Chromium Code Reviews| Index: content/browser/devtools/protocol/tracing_handler.cc |
| diff --git a/content/browser/devtools/protocol/tracing_handler.cc b/content/browser/devtools/protocol/tracing_handler.cc |
| index a57fdb8df7d74aac235a7a0ecacddc05c8e32b47..134ee2be2486da8593cd1ad27980c751f344c0cd 100644 |
| --- a/content/browser/devtools/protocol/tracing_handler.cc |
| +++ b/content/browser/devtools/protocol/tracing_handler.cc |
| @@ -4,13 +4,59 @@ |
| #include "content/browser/devtools/protocol/tracing_handler.h" |
| +#include <cmath> |
| + |
| +#include "base/bind.h" |
| +#include "base/debug/trace_event_impl.h" |
| +#include "base/strings/string_split.h" |
| +#include "base/strings/stringprintf.h" |
| +#include "base/time/time.h" |
| +#include "base/timer/timer.h" |
| + |
| namespace content { |
| namespace devtools { |
| namespace tracing { |
| typedef DevToolsProtocolClient::Response Response; |
| -TracingHandler::TracingHandler() { |
| +namespace { |
| + |
| +const char kRecordUntilFull[] = "record-until-full"; |
| +const char kRecordContinuously[] = "record-continuously"; |
| +const char kRecordAsMuchAsPossible[] = "record-as-much-as-possible"; |
| +const char kEnableSampling[] = "enable-sampling"; |
| + |
| +class DevToolsTraceSinkProxy : public TracingController::TraceDataSink { |
| + public: |
| + explicit DevToolsTraceSinkProxy(base::WeakPtr<TracingHandler> handler) |
| + : tracing_handler_(handler) {} |
| + |
| + virtual void AddTraceChunk(const std::string& chunk) override { |
| + if (TracingHandler* h = tracing_handler_.get()) |
| + h->OnTraceDataCollected(chunk); |
| + } |
| + virtual void Close() override { |
| + if (TracingHandler* h = tracing_handler_.get()) |
| + h->OnTraceComplete(); |
| + } |
| + |
| + private: |
| + virtual ~DevToolsTraceSinkProxy() {} |
| + |
| + base::WeakPtr<TracingHandler> tracing_handler_; |
| +}; |
| + |
| +} // namespace |
| + |
| +const char* TracingHandler::kDefaultCategories = |
| + "-*,disabled-by-default-devtools.timeline*"; |
| +const double TracingHandler::kDefaultReportingInterval = 1000.0; |
| +const double TracingHandler::kMinimumReportingInterval = 250.0; |
| + |
| +TracingHandler::TracingHandler(TracingHandler::Target target) |
| + : target_(target), |
| + is_recording_(false), |
| + weak_factory_(this) { |
| } |
| TracingHandler::~TracingHandler() { |
| @@ -20,32 +66,150 @@ void TracingHandler::SetClient(scoped_ptr<Client> client) { |
| client_.swap(client); |
| } |
| -Response TracingHandler::Start(const std::string& categories, |
| - const std::string& options, |
| - const double* buffer_usage_reporting_interval) { |
| - return Response::FallThrough(); |
| +void TracingHandler::Detached() { |
| + if (is_recording_) |
| + DisableRecording(true); |
| +} |
| + |
| +void TracingHandler::OnTraceDataCollected(const std::string& trace_fragment) { |
| + // Hand-craft protocol notification message so we can substitute JSON |
| + // that we already got as string as a bare object, not a quoted string. |
| + std::string message( |
| + "{ \"method\": \"Tracing.dataCollected\", \"params\": { \"value\": ["); |
| + const size_t messageSuffixSize = 10; |
| + message.reserve(message.size() + trace_fragment.size() + messageSuffixSize); |
| + message += trace_fragment; |
| + message += "] } }", client_->SendRawMessage(message); |
| +} |
| + |
| +void TracingHandler::OnTraceComplete() { |
| + TracingCompleteParams params; |
| + client_->TracingComplete(params); |
| } |
| scoped_refptr<DevToolsProtocol::Response> TracingHandler::Start( |
| const std::string& categories, |
| - const std::string& options, |
| + const std::string& options_str, |
| const double* buffer_usage_reporting_interval, |
| scoped_refptr<DevToolsProtocol::Command> command) { |
| - return NULL; |
| -} |
| + if (is_recording_) |
| + return command->InternalErrorResponse("Tracing is already started"); |
| + is_recording_ = true; |
| + |
| + base::debug::TraceOptions options = TraceOptionsFromString(options_str); |
| + if (buffer_usage_reporting_interval) |
| + SetupTimer(*buffer_usage_reporting_interval); |
| + |
| + // If inspected target is a render process Tracing.start will be handled by |
| + // tracing agent in the renderer. |
| + if (target_ == Renderer) { |
| + TracingController::GetInstance()->EnableRecording( |
| + base::debug::CategoryFilter(categories), |
| + options, |
| + TracingController::EnableRecordingDoneCallback()); |
| + return NULL; |
|
vkuzkokov
2014/10/07 13:36:07
Consider using nullptr in this file.
dgozman
2014/10/14 12:42:22
Done.
|
| + } |
| -Response TracingHandler::End() { |
| - return Response::FallThrough(); |
| + TracingController::GetInstance()->EnableRecording( |
| + base::debug::CategoryFilter(categories), |
| + options, |
| + base::Bind(&TracingHandler::OnRecordingEnabled, |
| + weak_factory_.GetWeakPtr(), |
| + command)); |
| + return command->AsyncResponsePromise(); |
| } |
| scoped_refptr<DevToolsProtocol::Response> TracingHandler::End( |
| scoped_refptr<DevToolsProtocol::Command> command) { |
| - return NULL; |
| + if (!is_recording_) |
| + return command->InternalErrorResponse("Tracing is not started"); |
| + DisableRecording(false); |
| + // If inspected target is a render process Tracing.end will be handled by |
| + // tracing agent in the renderer. |
| + if (target_ == Renderer) |
| + return NULL; |
| + return command->SuccessResponse(NULL); |
| } |
| scoped_refptr<DevToolsProtocol::Response> TracingHandler::GetCategories( |
| scoped_refptr<DevToolsProtocol::Command> command) { |
| - return NULL; |
| + TracingController::GetInstance()->GetCategories( |
| + base::Bind(&TracingHandler::OnCategoriesReceived, |
| + weak_factory_.GetWeakPtr(), |
| + command)); |
| + return command->AsyncResponsePromise(); |
| +} |
| + |
| +void TracingHandler::OnRecordingEnabled( |
| + scoped_refptr<DevToolsProtocol::Command> command) { |
| + StartResponse response; |
| + client_->SendStartResponse(command, response); |
| +} |
| + |
| +void TracingHandler::OnBufferUsage(float usage) { |
| + BufferUsageParams params; |
| + params.set_value(usage); |
| + client_->BufferUsage(params); |
| +} |
| + |
| +void TracingHandler::OnCategoriesReceived( |
| + scoped_refptr<DevToolsProtocol::Command> command, |
| + const std::set<std::string>& category_set) { |
| + std::vector<std::string> categories; |
| + for (const auto& category : category_set) |
|
caseq
2014/10/13 13:01:27
consider using range constructor for categories in
dgozman
2014/10/14 12:42:22
Done.
|
| + categories.push_back(category); |
| + |
| + GetCategoriesResponse response; |
| + response.set_categories(categories); |
| + client_->SendGetCategoriesResponse(command, response); |
| +} |
| + |
| +base::debug::TraceOptions TracingHandler::TraceOptionsFromString( |
| + const std::string& options) { |
| + std::vector<std::string> split; |
| + std::vector<std::string>::iterator iter; |
| + base::debug::TraceOptions ret; |
| + |
| + base::SplitString(options, ',', &split); |
| + for (iter = split.begin(); iter != split.end(); ++iter) { |
| + if (*iter == kRecordUntilFull) { |
| + ret.record_mode = base::debug::RECORD_UNTIL_FULL; |
| + } else if (*iter == kRecordContinuously) { |
| + ret.record_mode = base::debug::RECORD_CONTINUOUSLY; |
| + } else if (*iter == kRecordAsMuchAsPossible) { |
| + ret.record_mode = base::debug::RECORD_AS_MUCH_AS_POSSIBLE; |
| + } else if (*iter == kEnableSampling) { |
| + ret.enable_sampling = true; |
| + } |
| + } |
| + return ret; |
| +} |
| + |
| +void TracingHandler::SetupTimer(double usage_reporting_interval) { |
| + if (usage_reporting_interval == 0) return; |
| + |
| + if (usage_reporting_interval < kMinimumReportingInterval) |
| + usage_reporting_interval = kMinimumReportingInterval; |
| + |
| + base::TimeDelta interval = base::TimeDelta::FromMilliseconds( |
| + std::ceil(usage_reporting_interval)); |
| + buffer_usage_poll_timer_.reset(new base::Timer( |
| + FROM_HERE, |
| + interval, |
| + base::Bind( |
| + base::IgnoreResult(&TracingController::GetTraceBufferPercentFull), |
| + base::Unretained(TracingController::GetInstance()), |
| + base::Bind(&TracingHandler::OnBufferUsage, |
| + weak_factory_.GetWeakPtr())), |
| + true)); |
| + buffer_usage_poll_timer_->Reset(); |
| +} |
| + |
| +void TracingHandler::DisableRecording(bool abort) { |
| + is_recording_ = false; |
| + buffer_usage_poll_timer_.reset(); |
| + TracingController::GetInstance()->DisableRecording( |
| + abort ? NULL : new DevToolsTraceSinkProxy(weak_factory_.GetWeakPtr())); |
| } |
| } // namespace tracing |