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 |