tracing: get rid of files in TracingController interface
The only way to get the tracing data used to be by reading the file provided in TracingController::DisableTracing() interface. This does not fit well for most usages, so this introduces a TraceDataSink interface that is backed either by a file, string, or, in case of DevTools, by the protocol client. This resolves the OOM in browser and imporves performance while recording very large traces through DevTools, streamlines TracingController core and reduces coplexity of code for most TracingController clients. BUG=409733,361045 Review URL: https://codereview.chromium.org/541763002 Cr-Commit-Position: refs/heads/master@{#294801}
This commit is contained in:
@@ -19,6 +19,30 @@ namespace {
|
|||||||
|
|
||||||
using content::BrowserThread;
|
using content::BrowserThread;
|
||||||
|
|
||||||
|
class StringTraceSink : public content::TracingController::TraceDataSink {
|
||||||
|
public:
|
||||||
|
StringTraceSink(std::string* result, const base::Closure& callback)
|
||||||
|
: result_(result), completion_callback_(callback) {}
|
||||||
|
|
||||||
|
virtual void AddTraceChunk(const std::string& chunk) OVERRIDE {
|
||||||
|
*result_ += result_->empty() ? "[" : ",";
|
||||||
|
*result_ += chunk;
|
||||||
|
}
|
||||||
|
virtual void Close() OVERRIDE {
|
||||||
|
if (!result_->empty())
|
||||||
|
*result_ += "]";
|
||||||
|
completion_callback_.Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual ~StringTraceSink() {}
|
||||||
|
|
||||||
|
std::string* result_;
|
||||||
|
base::Closure completion_callback_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(StringTraceSink);
|
||||||
|
};
|
||||||
|
|
||||||
class InProcessTraceController {
|
class InProcessTraceController {
|
||||||
public:
|
public:
|
||||||
static InProcessTraceController* GetInstance() {
|
static InProcessTraceController* GetInstance() {
|
||||||
@@ -87,12 +111,12 @@ class InProcessTraceController {
|
|||||||
using namespace base::debug;
|
using namespace base::debug;
|
||||||
|
|
||||||
if (!content::TracingController::GetInstance()->DisableRecording(
|
if (!content::TracingController::GetInstance()->DisableRecording(
|
||||||
base::FilePath(),
|
new StringTraceSink(
|
||||||
base::Bind(&InProcessTraceController::OnTraceDataCollected,
|
json_trace_output,
|
||||||
base::Unretained(this),
|
base::Bind(&InProcessTraceController::OnTracingComplete,
|
||||||
base::Unretained(json_trace_output))))
|
base::Unretained(this))))) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
// Wait for OnEndTracingComplete() to quit the message loop.
|
// Wait for OnEndTracingComplete() to quit the message loop.
|
||||||
message_loop_runner_ = new content::MessageLoopRunner;
|
message_loop_runner_ = new content::MessageLoopRunner;
|
||||||
message_loop_runner_->Run();
|
message_loop_runner_->Run();
|
||||||
@@ -110,38 +134,7 @@ class InProcessTraceController {
|
|||||||
message_loop_runner_->Quit();
|
message_loop_runner_->Quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnEndTracingComplete() {
|
void OnTracingComplete() { message_loop_runner_->Quit(); }
|
||||||
message_loop_runner_->Quit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnTraceDataCollected(std::string* json_trace_output,
|
|
||||||
const base::FilePath& path) {
|
|
||||||
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
|
|
||||||
base::Bind(&InProcessTraceController::ReadTraceData,
|
|
||||||
base::Unretained(this),
|
|
||||||
base::Unretained(json_trace_output),
|
|
||||||
path));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReadTraceData(std::string* json_trace_output,
|
|
||||||
const base::FilePath& path) {
|
|
||||||
json_trace_output->clear();
|
|
||||||
bool ok = base::ReadFileToString(path, json_trace_output);
|
|
||||||
DCHECK(ok);
|
|
||||||
base::DeleteFile(path, false);
|
|
||||||
|
|
||||||
// The callers expect an array of trace events.
|
|
||||||
const char* preamble = "{\"traceEvents\": ";
|
|
||||||
const char* trailout = "}";
|
|
||||||
DCHECK(StartsWithASCII(*json_trace_output, preamble, true));
|
|
||||||
DCHECK(EndsWith(*json_trace_output, trailout, true));
|
|
||||||
json_trace_output->erase(0, strlen(preamble));
|
|
||||||
json_trace_output->erase(json_trace_output->end() - 1);
|
|
||||||
|
|
||||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
|
||||||
base::Bind(&InProcessTraceController::OnEndTracingComplete,
|
|
||||||
base::Unretained(this)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnWatchEventMatched() {
|
void OnWatchEventMatched() {
|
||||||
if (watch_notification_count_ == 0)
|
if (watch_notification_count_ == 0)
|
||||||
|
@@ -5,14 +5,13 @@
|
|||||||
#include "components/feedback/tracing_manager.h"
|
#include "components/feedback/tracing_manager.h"
|
||||||
|
|
||||||
#include "base/bind.h"
|
#include "base/bind.h"
|
||||||
#include "base/files/file_util.h"
|
|
||||||
#include "base/location.h"
|
|
||||||
#include "base/memory/ref_counted_memory.h"
|
#include "base/memory/ref_counted_memory.h"
|
||||||
#include "base/message_loop/message_loop_proxy.h"
|
#include "base/message_loop/message_loop_proxy.h"
|
||||||
#include "components/feedback/feedback_util.h"
|
#include "components/feedback/feedback_util.h"
|
||||||
#include "content/public/browser/tracing_controller.h"
|
#include "content/public/browser/tracing_controller.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Only once trace manager can exist at a time.
|
// Only once trace manager can exist at a time.
|
||||||
TracingManager* g_tracing_manager = NULL;
|
TracingManager* g_tracing_manager = NULL;
|
||||||
// Trace IDs start at 1 and increase.
|
// Trace IDs start at 1 and increase.
|
||||||
@@ -43,9 +42,9 @@ int TracingManager::RequestTrace() {
|
|||||||
current_trace_id_ = g_next_trace_id;
|
current_trace_id_ = g_next_trace_id;
|
||||||
++g_next_trace_id;
|
++g_next_trace_id;
|
||||||
content::TracingController::GetInstance()->DisableRecording(
|
content::TracingController::GetInstance()->DisableRecording(
|
||||||
base::FilePath(),
|
content::TracingController::CreateStringSink(
|
||||||
base::Bind(&TracingManager::OnTraceDataCollected,
|
base::Bind(&TracingManager::OnTraceDataCollected,
|
||||||
weak_ptr_factory_.GetWeakPtr()));
|
weak_ptr_factory_.GetWeakPtr())));
|
||||||
return current_trace_id_;
|
return current_trace_id_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,20 +95,13 @@ void TracingManager::StartTracing() {
|
|||||||
content::TracingController::EnableRecordingDoneCallback());
|
content::TracingController::EnableRecordingDoneCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TracingManager::OnTraceDataCollected(const base::FilePath& path) {
|
void TracingManager::OnTraceDataCollected(base::RefCountedString* trace_data) {
|
||||||
if (!current_trace_id_)
|
if (!current_trace_id_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string data;
|
|
||||||
if (!base::ReadFileToString(path, &data)) {
|
|
||||||
LOG(ERROR) << "Failed to read trace data from: " << path.value();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
base::DeleteFile(path, false);
|
|
||||||
|
|
||||||
std::string output_val;
|
std::string output_val;
|
||||||
feedback_util::ZipString(
|
feedback_util::ZipString(
|
||||||
base::FilePath(kTracingFilename), data, &output_val);
|
base::FilePath(kTracingFilename), trace_data->data(), &output_val);
|
||||||
|
|
||||||
scoped_refptr<base::RefCountedString> output(
|
scoped_refptr<base::RefCountedString> output(
|
||||||
base::RefCountedString::TakeString(&output_val));
|
base::RefCountedString::TakeString(&output_val));
|
||||||
|
@@ -58,7 +58,7 @@ class TracingManager {
|
|||||||
TracingManager();
|
TracingManager();
|
||||||
|
|
||||||
void StartTracing();
|
void StartTracing();
|
||||||
void OnTraceDataCollected(const base::FilePath& path);
|
void OnTraceDataCollected(base::RefCountedString* data);
|
||||||
|
|
||||||
// ID of the trace that is being collected.
|
// ID of the trace that is being collected.
|
||||||
int current_trace_id_;
|
int current_trace_id_;
|
||||||
|
@@ -54,11 +54,12 @@ void TracingControllerAndroid::StopTracing(JNIEnv* env,
|
|||||||
base::FilePath file_path(
|
base::FilePath file_path(
|
||||||
base::android::ConvertJavaStringToUTF8(env, jfilepath));
|
base::android::ConvertJavaStringToUTF8(env, jfilepath));
|
||||||
if (!TracingController::GetInstance()->DisableRecording(
|
if (!TracingController::GetInstance()->DisableRecording(
|
||||||
file_path,
|
TracingController::CreateFileSink(
|
||||||
base::Bind(&TracingControllerAndroid::OnTracingStopped,
|
file_path,
|
||||||
weak_factory_.GetWeakPtr()))) {
|
base::Bind(&TracingControllerAndroid::OnTracingStopped,
|
||||||
|
weak_factory_.GetWeakPtr())))) {
|
||||||
LOG(ERROR) << "EndTracingAsync failed, forcing an immediate stop";
|
LOG(ERROR) << "EndTracingAsync failed, forcing an immediate stop";
|
||||||
OnTracingStopped(file_path);
|
OnTracingStopped();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,8 +72,7 @@ void TracingControllerAndroid::GenerateTracingFilePath(
|
|||||||
base::android::ConvertJavaStringToUTF8(env, jfilename.obj()));
|
base::android::ConvertJavaStringToUTF8(env, jfilename.obj()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TracingControllerAndroid::OnTracingStopped(
|
void TracingControllerAndroid::OnTracingStopped() {
|
||||||
const base::FilePath& file_path) {
|
|
||||||
JNIEnv* env = base::android::AttachCurrentThread();
|
JNIEnv* env = base::android::AttachCurrentThread();
|
||||||
base::android::ScopedJavaLocalRef<jobject> obj = weak_java_object_.get(env);
|
base::android::ScopedJavaLocalRef<jobject> obj = weak_java_object_.get(env);
|
||||||
if (obj.obj())
|
if (obj.obj())
|
||||||
|
@@ -29,7 +29,7 @@ class TracingControllerAndroid {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
~TracingControllerAndroid();
|
~TracingControllerAndroid();
|
||||||
void OnTracingStopped(const base::FilePath& file_path);
|
void OnTracingStopped();
|
||||||
void OnKnownCategoriesReceived(
|
void OnKnownCategoriesReceived(
|
||||||
const std::set<std::string>& categories_received);
|
const std::set<std::string>& categories_received);
|
||||||
|
|
||||||
|
@@ -7,7 +7,6 @@
|
|||||||
#include "base/bind.h"
|
#include "base/bind.h"
|
||||||
#include "base/command_line.h"
|
#include "base/command_line.h"
|
||||||
#include "base/debug/trace_event.h"
|
#include "base/debug/trace_event.h"
|
||||||
#include "base/files/file_util.h"
|
|
||||||
#include "base/logging.h"
|
#include "base/logging.h"
|
||||||
#include "base/message_loop/message_loop.h"
|
#include "base/message_loop/message_loop.h"
|
||||||
#include "base/metrics/field_trial.h"
|
#include "base/metrics/field_trial.h"
|
||||||
@@ -1197,7 +1196,9 @@ void BrowserMainLoop::InitStartupTracing(
|
|||||||
void BrowserMainLoop::EndStartupTracing() {
|
void BrowserMainLoop::EndStartupTracing() {
|
||||||
is_tracing_startup_ = false;
|
is_tracing_startup_ = false;
|
||||||
TracingController::GetInstance()->DisableRecording(
|
TracingController::GetInstance()->DisableRecording(
|
||||||
startup_trace_file_, base::Bind(&OnStoppedStartupTracing));
|
TracingController::CreateFileSink(
|
||||||
|
startup_trace_file_,
|
||||||
|
base::Bind(OnStoppedStartupTracing, startup_trace_file_)));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace content
|
} // namespace content
|
||||||
|
@@ -7,13 +7,7 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
#include "base/bind.h"
|
#include "base/bind.h"
|
||||||
#include "base/callback.h"
|
|
||||||
#include "base/debug/trace_event_impl.h"
|
#include "base/debug/trace_event_impl.h"
|
||||||
#include "base/files/file_util.h"
|
|
||||||
#include "base/json/json_reader.h"
|
|
||||||
#include "base/json/json_writer.h"
|
|
||||||
#include "base/location.h"
|
|
||||||
#include "base/memory/ref_counted_memory.h"
|
|
||||||
#include "base/strings/string_split.h"
|
#include "base/strings/string_split.h"
|
||||||
#include "base/strings/stringprintf.h"
|
#include "base/strings/stringprintf.h"
|
||||||
#include "base/time/time.h"
|
#include "base/time/time.h"
|
||||||
@@ -33,18 +27,25 @@ const char kRecordContinuously[] = "record-continuously";
|
|||||||
const char kRecordAsMuchAsPossible[] = "record-as-much-as-possible";
|
const char kRecordAsMuchAsPossible[] = "record-as-much-as-possible";
|
||||||
const char kEnableSampling[] = "enable-sampling";
|
const char kEnableSampling[] = "enable-sampling";
|
||||||
|
|
||||||
void ReadFile(
|
class DevToolsTraceSinkProxy : public TracingController::TraceDataSink {
|
||||||
const base::FilePath& path,
|
public:
|
||||||
const base::Callback<void(const scoped_refptr<base::RefCountedString>&)>
|
explicit DevToolsTraceSinkProxy(base::WeakPtr<DevToolsTracingHandler> handler)
|
||||||
callback) {
|
: tracing_handler_(handler) {}
|
||||||
std::string trace_data;
|
|
||||||
if (!base::ReadFileToString(path, &trace_data))
|
virtual void AddTraceChunk(const std::string& chunk) OVERRIDE {
|
||||||
LOG(ERROR) << "Failed to read file: " << path.value();
|
if (DevToolsTracingHandler* h = tracing_handler_.get())
|
||||||
base::DeleteFile(path, false);
|
h->OnTraceDataCollected(chunk);
|
||||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
}
|
||||||
base::Bind(callback, make_scoped_refptr(
|
virtual void Close() OVERRIDE {
|
||||||
base::RefCountedString::TakeString(&trace_data))));
|
if (DevToolsTracingHandler* h = tracing_handler_.get())
|
||||||
}
|
h->OnTraceComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual ~DevToolsTraceSinkProxy() {}
|
||||||
|
|
||||||
|
base::WeakPtr<DevToolsTracingHandler> tracing_handler_;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -70,58 +71,22 @@ DevToolsTracingHandler::DevToolsTracingHandler(
|
|||||||
DevToolsTracingHandler::~DevToolsTracingHandler() {
|
DevToolsTracingHandler::~DevToolsTracingHandler() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevToolsTracingHandler::BeginReadingRecordingResult(
|
|
||||||
const base::FilePath& path) {
|
|
||||||
BrowserThread::PostTask(
|
|
||||||
BrowserThread::FILE, FROM_HERE,
|
|
||||||
base::Bind(&ReadFile, path,
|
|
||||||
base::Bind(&DevToolsTracingHandler::ReadRecordingResult,
|
|
||||||
weak_factory_.GetWeakPtr())));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DevToolsTracingHandler::ReadRecordingResult(
|
|
||||||
const scoped_refptr<base::RefCountedString>& trace_data) {
|
|
||||||
if (trace_data->data().size()) {
|
|
||||||
scoped_ptr<base::Value> trace_value(base::JSONReader::Read(
|
|
||||||
trace_data->data()));
|
|
||||||
base::DictionaryValue* dictionary = NULL;
|
|
||||||
bool ok = trace_value->GetAsDictionary(&dictionary);
|
|
||||||
DCHECK(ok);
|
|
||||||
base::ListValue* list = NULL;
|
|
||||||
ok = dictionary->GetList("traceEvents", &list);
|
|
||||||
DCHECK(ok);
|
|
||||||
std::string buffer;
|
|
||||||
for (size_t i = 0; i < list->GetSize(); ++i) {
|
|
||||||
std::string item;
|
|
||||||
base::Value* item_value;
|
|
||||||
list->Get(i, &item_value);
|
|
||||||
base::JSONWriter::Write(item_value, &item);
|
|
||||||
if (buffer.size())
|
|
||||||
buffer.append(",");
|
|
||||||
buffer.append(item);
|
|
||||||
const size_t kMessageSizeThreshold = 1024 * 1024;
|
|
||||||
if (buffer.size() > kMessageSizeThreshold) {
|
|
||||||
OnTraceDataCollected(buffer);
|
|
||||||
buffer.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (buffer.size())
|
|
||||||
OnTraceDataCollected(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
SendNotification(devtools::Tracing::tracingComplete::kName, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DevToolsTracingHandler::OnTraceDataCollected(
|
void DevToolsTracingHandler::OnTraceDataCollected(
|
||||||
const std::string& trace_fragment) {
|
const std::string& trace_fragment) {
|
||||||
// Hand-craft protocol notification message so we can substitute JSON
|
// Hand-craft protocol notification message so we can substitute JSON
|
||||||
// that we already got as string as a bare object, not a quoted string.
|
// that we already got as string as a bare object, not a quoted string.
|
||||||
std::string message = base::StringPrintf(
|
std::string message =
|
||||||
"{ \"method\": \"%s\", \"params\": { \"%s\": [ %s ] } }",
|
base::StringPrintf("{ \"method\": \"%s\", \"params\": { \"%s\": [",
|
||||||
devtools::Tracing::dataCollected::kName,
|
devtools::Tracing::dataCollected::kName,
|
||||||
devtools::Tracing::dataCollected::kParamValue,
|
devtools::Tracing::dataCollected::kParamValue);
|
||||||
trace_fragment.c_str());
|
const size_t messageSuffixSize = 10;
|
||||||
SendRawMessage(message);
|
message.reserve(message.size() + trace_fragment.size() + messageSuffixSize);
|
||||||
|
message += trace_fragment;
|
||||||
|
message += "] } }", SendRawMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevToolsTracingHandler::OnTraceComplete() {
|
||||||
|
SendNotification(devtools::Tracing::tracingComplete::kName, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
base::debug::TraceOptions DevToolsTracingHandler::TraceOptionsFromString(
|
base::debug::TraceOptions DevToolsTracingHandler::TraceOptionsFromString(
|
||||||
@@ -221,23 +186,20 @@ DevToolsTracingHandler::OnEnd(
|
|||||||
// tracing agent in the renderer.
|
// tracing agent in the renderer.
|
||||||
if (target_ == Renderer)
|
if (target_ == Renderer)
|
||||||
return NULL;
|
return NULL;
|
||||||
DisableRecording(
|
DisableRecording(false);
|
||||||
base::Bind(&DevToolsTracingHandler::BeginReadingRecordingResult,
|
|
||||||
weak_factory_.GetWeakPtr()));
|
|
||||||
return command->SuccessResponse(NULL);
|
return command->SuccessResponse(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevToolsTracingHandler::DisableRecording(
|
void DevToolsTracingHandler::DisableRecording(bool abort) {
|
||||||
const TracingController::TracingFileResultCallback& callback) {
|
|
||||||
is_recording_ = false;
|
is_recording_ = false;
|
||||||
buffer_usage_poll_timer_.reset();
|
buffer_usage_poll_timer_.reset();
|
||||||
TracingController::GetInstance()->DisableRecording(base::FilePath(),
|
TracingController::GetInstance()->DisableRecording(
|
||||||
callback);
|
abort ? NULL : new DevToolsTraceSinkProxy(weak_factory_.GetWeakPtr()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevToolsTracingHandler::OnClientDetached() {
|
void DevToolsTracingHandler::OnClientDetached() {
|
||||||
if (is_recording_)
|
if (is_recording_)
|
||||||
DisableRecording();
|
DisableRecording(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
scoped_refptr<DevToolsProtocol::Response>
|
scoped_refptr<DevToolsProtocol::Response>
|
||||||
@@ -283,9 +245,7 @@ void DevToolsTracingHandler::DisableTracing() {
|
|||||||
if (!is_recording_)
|
if (!is_recording_)
|
||||||
return;
|
return;
|
||||||
is_recording_ = false;
|
is_recording_ = false;
|
||||||
DisableRecording(
|
DisableRecording(false);
|
||||||
base::Bind(&DevToolsTracingHandler::BeginReadingRecordingResult,
|
|
||||||
weak_factory_.GetWeakPtr()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -33,10 +33,10 @@ class DevToolsTracingHandler : public DevToolsProtocol::Handler {
|
|||||||
void EnableTracing(const std::string& category_filter);
|
void EnableTracing(const std::string& category_filter);
|
||||||
void DisableTracing();
|
void DisableTracing();
|
||||||
|
|
||||||
private:
|
|
||||||
void BeginReadingRecordingResult(const base::FilePath& path);
|
|
||||||
void ReadRecordingResult(const scoped_refptr<base::RefCountedString>& result);
|
|
||||||
void OnTraceDataCollected(const std::string& trace_fragment);
|
void OnTraceDataCollected(const std::string& trace_fragment);
|
||||||
|
void OnTraceComplete();
|
||||||
|
|
||||||
|
private:
|
||||||
void OnRecordingEnabled(scoped_refptr<DevToolsProtocol::Command> command);
|
void OnRecordingEnabled(scoped_refptr<DevToolsProtocol::Command> command);
|
||||||
void OnBufferUsage(float usage);
|
void OnBufferUsage(float usage);
|
||||||
|
|
||||||
@@ -55,9 +55,7 @@ class DevToolsTracingHandler : public DevToolsProtocol::Handler {
|
|||||||
|
|
||||||
void SetupTimer(double usage_reporting_interval);
|
void SetupTimer(double usage_reporting_interval);
|
||||||
|
|
||||||
void DisableRecording(
|
void DisableRecording(bool abort);
|
||||||
const TracingController::TracingFileResultCallback& callback =
|
|
||||||
TracingController::TracingFileResultCallback());
|
|
||||||
|
|
||||||
base::WeakPtrFactory<DevToolsTracingHandler> weak_factory_;
|
base::WeakPtrFactory<DevToolsTracingHandler> weak_factory_;
|
||||||
scoped_ptr<base::Timer> buffer_usage_poll_timer_;
|
scoped_ptr<base::Timer> buffer_usage_poll_timer_;
|
||||||
|
@@ -3,8 +3,9 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
#include "base/files/file_util.h"
|
#include "base/files/file_util.h"
|
||||||
|
#include "base/memory/ref_counted_memory.h"
|
||||||
#include "base/run_loop.h"
|
#include "base/run_loop.h"
|
||||||
#include "content/browser/tracing/tracing_controller_impl.h"
|
#include "content/public/browser/tracing_controller.h"
|
||||||
#include "content/public/test/browser_test_utils.h"
|
#include "content/public/test/browser_test_utils.h"
|
||||||
#include "content/public/test/content_browser_test.h"
|
#include "content/public/test/content_browser_test.h"
|
||||||
#include "content/public/test/content_browser_test_utils.h"
|
#include "content/public/test/content_browser_test_utils.h"
|
||||||
@@ -51,8 +52,15 @@ class TracingControllerTest : public ContentBrowserTest {
|
|||||||
quit_callback.Run();
|
quit_callback.Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisableRecordingDoneCallbackTest(base::Closure quit_callback,
|
void DisableRecordingStringDoneCallbackTest(base::Closure quit_callback,
|
||||||
const base::FilePath& file_path) {
|
base::RefCountedString* data) {
|
||||||
|
disable_recording_done_callback_count_++;
|
||||||
|
EXPECT_TRUE(data->size() > 0);
|
||||||
|
quit_callback.Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisableRecordingFileDoneCallbackTest(base::Closure quit_callback,
|
||||||
|
const base::FilePath& file_path) {
|
||||||
disable_recording_done_callback_count_++;
|
disable_recording_done_callback_count_++;
|
||||||
EXPECT_TRUE(PathExists(file_path));
|
EXPECT_TRUE(PathExists(file_path));
|
||||||
int64 file_size;
|
int64 file_size;
|
||||||
@@ -115,7 +123,7 @@ class TracingControllerTest : public ContentBrowserTest {
|
|||||||
return last_actual_monitoring_file_path_;
|
return last_actual_monitoring_file_path_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestEnableAndDisableRecording(const base::FilePath& result_file_path) {
|
void TestEnableAndDisableRecordingString() {
|
||||||
Navigate(shell());
|
Navigate(shell());
|
||||||
|
|
||||||
TracingController* controller = TracingController::GetInstance();
|
TracingController* controller = TracingController::GetInstance();
|
||||||
@@ -135,11 +143,46 @@ class TracingControllerTest : public ContentBrowserTest {
|
|||||||
|
|
||||||
{
|
{
|
||||||
base::RunLoop run_loop;
|
base::RunLoop run_loop;
|
||||||
TracingController::TracingFileResultCallback callback =
|
base::Callback<void(base::RefCountedString*)> callback = base::Bind(
|
||||||
base::Bind(&TracingControllerTest::DisableRecordingDoneCallbackTest,
|
&TracingControllerTest::DisableRecordingStringDoneCallbackTest,
|
||||||
|
base::Unretained(this),
|
||||||
|
run_loop.QuitClosure());
|
||||||
|
bool result = controller->DisableRecording(
|
||||||
|
TracingController::CreateStringSink(callback));
|
||||||
|
ASSERT_TRUE(result);
|
||||||
|
run_loop.Run();
|
||||||
|
EXPECT_EQ(disable_recording_done_callback_count(), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestEnableAndDisableRecordingFile(
|
||||||
|
const base::FilePath& result_file_path) {
|
||||||
|
Navigate(shell());
|
||||||
|
|
||||||
|
TracingController* controller = TracingController::GetInstance();
|
||||||
|
|
||||||
|
{
|
||||||
|
base::RunLoop run_loop;
|
||||||
|
TracingController::EnableRecordingDoneCallback callback =
|
||||||
|
base::Bind(&TracingControllerTest::EnableRecordingDoneCallbackTest,
|
||||||
base::Unretained(this),
|
base::Unretained(this),
|
||||||
run_loop.QuitClosure());
|
run_loop.QuitClosure());
|
||||||
bool result = controller->DisableRecording(result_file_path, callback);
|
bool result = controller->EnableRecording(
|
||||||
|
CategoryFilter(), TraceOptions(), callback);
|
||||||
|
ASSERT_TRUE(result);
|
||||||
|
run_loop.Run();
|
||||||
|
EXPECT_EQ(enable_recording_done_callback_count(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
base::RunLoop run_loop;
|
||||||
|
base::Closure callback = base::Bind(
|
||||||
|
&TracingControllerTest::DisableRecordingFileDoneCallbackTest,
|
||||||
|
base::Unretained(this),
|
||||||
|
run_loop.QuitClosure(),
|
||||||
|
result_file_path);
|
||||||
|
bool result = controller->DisableRecording(
|
||||||
|
TracingController::CreateFileSink(result_file_path, callback));
|
||||||
ASSERT_TRUE(result);
|
ASSERT_TRUE(result);
|
||||||
run_loop.Run();
|
run_loop.Run();
|
||||||
EXPECT_EQ(disable_recording_done_callback_count(), 1);
|
EXPECT_EQ(disable_recording_done_callback_count(), 1);
|
||||||
@@ -199,13 +242,13 @@ class TracingControllerTest : public ContentBrowserTest {
|
|||||||
|
|
||||||
{
|
{
|
||||||
base::RunLoop run_loop;
|
base::RunLoop run_loop;
|
||||||
TracingController::TracingFileResultCallback callback =
|
base::Closure callback = base::Bind(
|
||||||
base::Bind(&TracingControllerTest::
|
&TracingControllerTest::CaptureMonitoringSnapshotDoneCallbackTest,
|
||||||
CaptureMonitoringSnapshotDoneCallbackTest,
|
base::Unretained(this),
|
||||||
base::Unretained(this),
|
run_loop.QuitClosure(),
|
||||||
run_loop.QuitClosure());
|
result_file_path);
|
||||||
ASSERT_TRUE(controller->CaptureMonitoringSnapshot(result_file_path,
|
ASSERT_TRUE(controller->CaptureMonitoringSnapshot(
|
||||||
callback));
|
TracingController::CreateFileSink(result_file_path, callback)));
|
||||||
run_loop.Run();
|
run_loop.Run();
|
||||||
EXPECT_EQ(capture_monitoring_snapshot_done_callback_count(), 1);
|
EXPECT_EQ(capture_monitoring_snapshot_done_callback_count(), 1);
|
||||||
}
|
}
|
||||||
@@ -264,14 +307,14 @@ IN_PROC_BROWSER_TEST_F(TracingControllerTest, GetCategories) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
IN_PROC_BROWSER_TEST_F(TracingControllerTest, EnableAndDisableRecording) {
|
IN_PROC_BROWSER_TEST_F(TracingControllerTest, EnableAndDisableRecording) {
|
||||||
TestEnableAndDisableRecording(base::FilePath());
|
TestEnableAndDisableRecordingString();
|
||||||
}
|
}
|
||||||
|
|
||||||
IN_PROC_BROWSER_TEST_F(TracingControllerTest,
|
IN_PROC_BROWSER_TEST_F(TracingControllerTest,
|
||||||
EnableAndDisableRecordingWithFilePath) {
|
EnableAndDisableRecordingWithFilePath) {
|
||||||
base::FilePath file_path;
|
base::FilePath file_path;
|
||||||
base::CreateTemporaryFile(&file_path);
|
base::CreateTemporaryFile(&file_path);
|
||||||
TestEnableAndDisableRecording(file_path);
|
TestEnableAndDisableRecordingFile(file_path);
|
||||||
EXPECT_EQ(file_path.value(), last_actual_recording_file_path().value());
|
EXPECT_EQ(file_path.value(), last_actual_recording_file_path().value());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,14 +327,15 @@ IN_PROC_BROWSER_TEST_F(TracingControllerTest,
|
|||||||
CategoryFilter(),
|
CategoryFilter(),
|
||||||
TraceOptions(),
|
TraceOptions(),
|
||||||
TracingController::EnableRecordingDoneCallback()));
|
TracingController::EnableRecordingDoneCallback()));
|
||||||
EXPECT_TRUE(controller->DisableRecording(
|
EXPECT_TRUE(controller->DisableRecording(NULL));
|
||||||
base::FilePath(), TracingController::TracingFileResultCallback()));
|
|
||||||
base::RunLoop().RunUntilIdle();
|
base::RunLoop().RunUntilIdle();
|
||||||
}
|
}
|
||||||
|
|
||||||
IN_PROC_BROWSER_TEST_F(TracingControllerTest,
|
IN_PROC_BROWSER_TEST_F(TracingControllerTest,
|
||||||
EnableCaptureAndDisableMonitoring) {
|
EnableCaptureAndDisableMonitoring) {
|
||||||
TestEnableCaptureAndDisableMonitoring(base::FilePath());
|
base::FilePath file_path;
|
||||||
|
base::CreateTemporaryFile(&file_path);
|
||||||
|
TestEnableCaptureAndDisableMonitoring(file_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
IN_PROC_BROWSER_TEST_F(TracingControllerTest,
|
IN_PROC_BROWSER_TEST_F(TracingControllerTest,
|
||||||
@@ -322,8 +366,7 @@ IN_PROC_BROWSER_TEST_F(
|
|||||||
CategoryFilter("*"),
|
CategoryFilter("*"),
|
||||||
trace_options,
|
trace_options,
|
||||||
TracingController::EnableMonitoringDoneCallback()));
|
TracingController::EnableMonitoringDoneCallback()));
|
||||||
controller->CaptureMonitoringSnapshot(
|
controller->CaptureMonitoringSnapshot(NULL);
|
||||||
base::FilePath(), TracingController::TracingFileResultCallback());
|
|
||||||
base::RunLoop().RunUntilIdle();
|
base::RunLoop().RunUntilIdle();
|
||||||
EXPECT_TRUE(controller->DisableMonitoring(
|
EXPECT_TRUE(controller->DisableMonitoring(
|
||||||
TracingController::DisableMonitoringDoneCallback()));
|
TracingController::DisableMonitoringDoneCallback()));
|
||||||
|
@@ -34,134 +34,126 @@ namespace {
|
|||||||
base::LazyInstance<TracingControllerImpl>::Leaky g_controller =
|
base::LazyInstance<TracingControllerImpl>::Leaky g_controller =
|
||||||
LAZY_INSTANCE_INITIALIZER;
|
LAZY_INSTANCE_INITIALIZER;
|
||||||
|
|
||||||
|
class FileTraceDataSink : public TracingController::TraceDataSink {
|
||||||
|
public:
|
||||||
|
explicit FileTraceDataSink(const base::FilePath& trace_file_path,
|
||||||
|
const base::Closure& callback)
|
||||||
|
: file_path_(trace_file_path),
|
||||||
|
completion_callback_(callback),
|
||||||
|
file_(NULL) {}
|
||||||
|
|
||||||
|
virtual void AddTraceChunk(const std::string& chunk) OVERRIDE {
|
||||||
|
std::string tmp = chunk;
|
||||||
|
scoped_refptr<base::RefCountedString> chunk_ptr =
|
||||||
|
base::RefCountedString::TakeString(&tmp);
|
||||||
|
BrowserThread::PostTask(
|
||||||
|
BrowserThread::FILE,
|
||||||
|
FROM_HERE,
|
||||||
|
base::Bind(
|
||||||
|
&FileTraceDataSink::AddTraceChunkOnFileThread, this, chunk_ptr));
|
||||||
|
}
|
||||||
|
virtual void SetSystemTrace(const std::string& data) OVERRIDE {
|
||||||
|
system_trace_ = data;
|
||||||
|
}
|
||||||
|
virtual void Close() OVERRIDE {
|
||||||
|
BrowserThread::PostTask(
|
||||||
|
BrowserThread::FILE,
|
||||||
|
FROM_HERE,
|
||||||
|
base::Bind(&FileTraceDataSink::CloseOnFileThread, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual ~FileTraceDataSink() { DCHECK(file_ == NULL); }
|
||||||
|
|
||||||
|
void AddTraceChunkOnFileThread(
|
||||||
|
const scoped_refptr<base::RefCountedString> chunk) {
|
||||||
|
if (!OpenFileIfNeededOnFileThread())
|
||||||
|
return;
|
||||||
|
fwrite(chunk->data().c_str(), strlen(chunk->data().c_str()), 1, file_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenFileIfNeededOnFileThread() {
|
||||||
|
if (file_ != NULL)
|
||||||
|
return true;
|
||||||
|
file_ = base::OpenFile(file_path_, "w");
|
||||||
|
if (file_ == NULL) {
|
||||||
|
LOG(ERROR) << "Failed to open " << file_path_.value();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const char preamble[] = "{\"traceEvents\": [";
|
||||||
|
fwrite(preamble, strlen(preamble), 1, file_);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CloseOnFileThread() {
|
||||||
|
if (OpenFileIfNeededOnFileThread()) {
|
||||||
|
fputc(']', file_);
|
||||||
|
if (!system_trace_.empty()) {
|
||||||
|
const char systemTraceEvents[] = ",\"systemTraceEvents\": ";
|
||||||
|
fwrite(systemTraceEvents, strlen(systemTraceEvents), 1, file_);
|
||||||
|
fwrite(system_trace_.c_str(), strlen(system_trace_.c_str()), 1, file_);
|
||||||
|
}
|
||||||
|
fputc('}', file_);
|
||||||
|
base::CloseFile(file_);
|
||||||
|
file_ = NULL;
|
||||||
|
}
|
||||||
|
BrowserThread::PostTask(
|
||||||
|
BrowserThread::UI,
|
||||||
|
FROM_HERE,
|
||||||
|
base::Bind(&FileTraceDataSink::FinalizeOnUIThread, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FinalizeOnUIThread() { completion_callback_.Run(); }
|
||||||
|
|
||||||
|
base::FilePath file_path_;
|
||||||
|
base::Closure completion_callback_;
|
||||||
|
FILE* file_;
|
||||||
|
std::string system_trace_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(FileTraceDataSink);
|
||||||
|
};
|
||||||
|
|
||||||
|
class StringTraceDataSink : public TracingController::TraceDataSink {
|
||||||
|
public:
|
||||||
|
typedef base::Callback<void(base::RefCountedString*)> CompletionCallback;
|
||||||
|
|
||||||
|
explicit StringTraceDataSink(CompletionCallback callback)
|
||||||
|
: completion_callback_(callback) {}
|
||||||
|
|
||||||
|
// TracingController::TraceDataSink implementation
|
||||||
|
virtual void AddTraceChunk(const std::string& chunk) OVERRIDE {
|
||||||
|
if (!trace_.empty())
|
||||||
|
trace_ += ",";
|
||||||
|
trace_ += chunk;
|
||||||
|
}
|
||||||
|
virtual void SetSystemTrace(const std::string& data) OVERRIDE {
|
||||||
|
system_trace_ = data;
|
||||||
|
}
|
||||||
|
virtual void Close() OVERRIDE {
|
||||||
|
std::string result = "{\"traceEvents\":[" + trace_ + "]";
|
||||||
|
if (!system_trace_.empty())
|
||||||
|
result += ",\"systemTraceEvents\": " + system_trace_;
|
||||||
|
result += "}";
|
||||||
|
|
||||||
|
completion_callback_.Run(base::RefCountedString::TakeString(&result));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual ~StringTraceDataSink() {}
|
||||||
|
|
||||||
|
std::string trace_;
|
||||||
|
std::string system_trace_;
|
||||||
|
CompletionCallback completion_callback_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(StringTraceDataSink);
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
TracingController* TracingController::GetInstance() {
|
TracingController* TracingController::GetInstance() {
|
||||||
return TracingControllerImpl::GetInstance();
|
return TracingControllerImpl::GetInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
class TracingControllerImpl::ResultFile {
|
|
||||||
public:
|
|
||||||
explicit ResultFile(const base::FilePath& path);
|
|
||||||
void Write(const scoped_refptr<base::RefCountedString>& events_str_ptr) {
|
|
||||||
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
|
|
||||||
base::Bind(&TracingControllerImpl::ResultFile::WriteTask,
|
|
||||||
base::Unretained(this), events_str_ptr));
|
|
||||||
}
|
|
||||||
void Close(const base::Closure& callback) {
|
|
||||||
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
|
|
||||||
base::Bind(&TracingControllerImpl::ResultFile::CloseTask,
|
|
||||||
base::Unretained(this), callback));
|
|
||||||
}
|
|
||||||
void WriteSystemTrace(
|
|
||||||
const scoped_refptr<base::RefCountedString>& events_str_ptr) {
|
|
||||||
BrowserThread::PostTask(
|
|
||||||
BrowserThread::FILE,
|
|
||||||
FROM_HERE,
|
|
||||||
base::Bind(&TracingControllerImpl::ResultFile::WriteSystemTraceTask,
|
|
||||||
base::Unretained(this), events_str_ptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
const base::FilePath& path() const { return path_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
void OpenTask();
|
|
||||||
void WriteTask(const scoped_refptr<base::RefCountedString>& events_str_ptr);
|
|
||||||
void WriteSystemTraceTask(
|
|
||||||
const scoped_refptr<base::RefCountedString>& events_str_ptr);
|
|
||||||
void CloseTask(const base::Closure& callback);
|
|
||||||
|
|
||||||
FILE* file_;
|
|
||||||
base::FilePath path_;
|
|
||||||
bool has_at_least_one_result_;
|
|
||||||
scoped_refptr<base::RefCountedString> system_trace_;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(ResultFile);
|
|
||||||
};
|
|
||||||
|
|
||||||
TracingControllerImpl::ResultFile::ResultFile(const base::FilePath& path)
|
|
||||||
: file_(NULL),
|
|
||||||
path_(path),
|
|
||||||
has_at_least_one_result_(false) {
|
|
||||||
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
|
|
||||||
base::Bind(&TracingControllerImpl::ResultFile::OpenTask,
|
|
||||||
base::Unretained(this)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void TracingControllerImpl::ResultFile::OpenTask() {
|
|
||||||
if (path_.empty())
|
|
||||||
base::CreateTemporaryFile(&path_);
|
|
||||||
file_ = base::OpenFile(path_, "w");
|
|
||||||
if (!file_) {
|
|
||||||
LOG(ERROR) << "Failed to open " << path_.value();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const char* preamble = "{\"traceEvents\": [";
|
|
||||||
size_t written = fwrite(preamble, strlen(preamble), 1, file_);
|
|
||||||
DCHECK(written == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TracingControllerImpl::ResultFile::WriteTask(
|
|
||||||
const scoped_refptr<base::RefCountedString>& events_str_ptr) {
|
|
||||||
if (!file_ || !events_str_ptr->data().size())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// If there is already a result in the file, then put a comma
|
|
||||||
// before the next batch of results.
|
|
||||||
if (has_at_least_one_result_) {
|
|
||||||
size_t written = fwrite(",", 1, 1, file_);
|
|
||||||
DCHECK(written == 1);
|
|
||||||
}
|
|
||||||
has_at_least_one_result_ = true;
|
|
||||||
size_t written = fwrite(events_str_ptr->data().c_str(),
|
|
||||||
events_str_ptr->data().size(), 1,
|
|
||||||
file_);
|
|
||||||
DCHECK(written == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TracingControllerImpl::ResultFile::WriteSystemTraceTask(
|
|
||||||
const scoped_refptr<base::RefCountedString>& events_str_ptr) {
|
|
||||||
system_trace_ = events_str_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TracingControllerImpl::ResultFile::CloseTask(
|
|
||||||
const base::Closure& callback) {
|
|
||||||
if (!file_)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const char* trailevents = "]";
|
|
||||||
size_t written = fwrite(trailevents, strlen(trailevents), 1, file_);
|
|
||||||
DCHECK(written == 1);
|
|
||||||
|
|
||||||
if (system_trace_.get()) {
|
|
||||||
#if defined(OS_WIN)
|
|
||||||
// The Windows kernel events are kept into a JSon format stored as string
|
|
||||||
// and must not be escaped.
|
|
||||||
std::string json_string = system_trace_->data();
|
|
||||||
#else
|
|
||||||
std::string json_string = base::GetQuotedJSONString(system_trace_->data());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const char* systemTraceHead = ",\n\"systemTraceEvents\": ";
|
|
||||||
written = fwrite(systemTraceHead, strlen(systemTraceHead), 1, file_);
|
|
||||||
DCHECK(written == 1);
|
|
||||||
|
|
||||||
written = fwrite(json_string.data(), json_string.size(), 1, file_);
|
|
||||||
DCHECK(written == 1);
|
|
||||||
|
|
||||||
system_trace_ = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* trailout = "}";
|
|
||||||
written = fwrite(trailout, strlen(trailout), 1, file_);
|
|
||||||
DCHECK(written == 1);
|
|
||||||
base::CloseFile(file_);
|
|
||||||
file_ = NULL;
|
|
||||||
|
|
||||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
TracingControllerImpl::TracingControllerImpl() :
|
TracingControllerImpl::TracingControllerImpl() :
|
||||||
pending_disable_recording_ack_count_(0),
|
pending_disable_recording_ack_count_(0),
|
||||||
pending_capture_monitoring_snapshot_ack_count_(0),
|
pending_capture_monitoring_snapshot_ack_count_(0),
|
||||||
@@ -199,7 +191,7 @@ bool TracingControllerImpl::GetCategories(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ok = DisableRecording(base::FilePath(), TracingFileResultCallback());
|
bool ok = DisableRecording(NULL);
|
||||||
DCHECK(ok);
|
DCHECK(ok);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -286,20 +278,18 @@ void TracingControllerImpl::OnEnableRecordingDone(
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool TracingControllerImpl::DisableRecording(
|
bool TracingControllerImpl::DisableRecording(
|
||||||
const base::FilePath& result_file_path,
|
const scoped_refptr<TraceDataSink>& trace_data_sink) {
|
||||||
const TracingFileResultCallback& callback) {
|
|
||||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||||
|
|
||||||
if (!can_disable_recording())
|
if (!can_disable_recording())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
trace_data_sink_ = trace_data_sink;
|
||||||
trace_options_ = TraceOptions();
|
trace_options_ = TraceOptions();
|
||||||
// Disable local trace early to avoid traces during end-tracing process from
|
// Disable local trace early to avoid traces during end-tracing process from
|
||||||
// interfering with the process.
|
// interfering with the process.
|
||||||
base::Closure on_disable_recording_done_callback =
|
base::Closure on_disable_recording_done_callback = base::Bind(
|
||||||
base::Bind(&TracingControllerImpl::OnDisableRecordingDone,
|
&TracingControllerImpl::OnDisableRecordingDone, base::Unretained(this));
|
||||||
base::Unretained(this),
|
|
||||||
result_file_path, callback);
|
|
||||||
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
|
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
|
||||||
base::Bind(&TracingControllerImpl::SetDisabledOnFileThread,
|
base::Bind(&TracingControllerImpl::SetDisabledOnFileThread,
|
||||||
base::Unretained(this),
|
base::Unretained(this),
|
||||||
@@ -307,21 +297,14 @@ bool TracingControllerImpl::DisableRecording(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TracingControllerImpl::OnDisableRecordingDone(
|
void TracingControllerImpl::OnDisableRecordingDone() {
|
||||||
const base::FilePath& result_file_path,
|
|
||||||
const TracingFileResultCallback& callback) {
|
|
||||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||||
|
|
||||||
pending_disable_recording_done_callback_ = callback;
|
|
||||||
|
|
||||||
#if defined(OS_ANDROID)
|
#if defined(OS_ANDROID)
|
||||||
if (pending_get_categories_done_callback_.is_null())
|
if (pending_get_categories_done_callback_.is_null())
|
||||||
TraceLog::GetInstance()->AddClockSyncMetadataEvent();
|
TraceLog::GetInstance()->AddClockSyncMetadataEvent();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!callback.is_null() || !result_file_path.empty())
|
|
||||||
result_file_.reset(new ResultFile(result_file_path));
|
|
||||||
|
|
||||||
// Count myself (local trace) in pending_disable_recording_ack_count_,
|
// Count myself (local trace) in pending_disable_recording_ack_count_,
|
||||||
// acked below.
|
// acked below.
|
||||||
pending_disable_recording_ack_count_ = trace_message_filters_.size() + 1;
|
pending_disable_recording_ack_count_ = trace_message_filters_.size() + 1;
|
||||||
@@ -431,6 +414,18 @@ bool TracingControllerImpl::DisableMonitoring(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scoped_refptr<TracingController::TraceDataSink>
|
||||||
|
TracingController::CreateStringSink(
|
||||||
|
const base::Callback<void(base::RefCountedString*)>& callback) {
|
||||||
|
return new StringTraceDataSink(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
scoped_refptr<TracingController::TraceDataSink>
|
||||||
|
TracingController::CreateFileSink(const base::FilePath& file_path,
|
||||||
|
const base::Closure& callback) {
|
||||||
|
return new FileTraceDataSink(file_path, callback);
|
||||||
|
}
|
||||||
|
|
||||||
void TracingControllerImpl::OnDisableMonitoringDone(
|
void TracingControllerImpl::OnDisableMonitoringDone(
|
||||||
const DisableMonitoringDoneCallback& callback) {
|
const DisableMonitoringDoneCallback& callback) {
|
||||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||||
@@ -442,7 +437,6 @@ void TracingControllerImpl::OnDisableMonitoringDone(
|
|||||||
it != trace_message_filters_.end(); ++it) {
|
it != trace_message_filters_.end(); ++it) {
|
||||||
it->get()->SendDisableMonitoring();
|
it->get()->SendDisableMonitoring();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!callback.is_null())
|
if (!callback.is_null())
|
||||||
callback.Run();
|
callback.Run();
|
||||||
}
|
}
|
||||||
@@ -457,18 +451,16 @@ void TracingControllerImpl::GetMonitoringStatus(
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool TracingControllerImpl::CaptureMonitoringSnapshot(
|
bool TracingControllerImpl::CaptureMonitoringSnapshot(
|
||||||
const base::FilePath& result_file_path,
|
const scoped_refptr<TraceDataSink>& monitoring_data_sink) {
|
||||||
const TracingFileResultCallback& callback) {
|
|
||||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||||
|
|
||||||
if (!can_disable_monitoring())
|
if (!can_disable_monitoring())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (callback.is_null() && result_file_path.empty())
|
if (!monitoring_data_sink.get())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
pending_capture_monitoring_snapshot_done_callback_ = callback;
|
monitoring_data_sink_ = monitoring_data_sink;
|
||||||
monitoring_snapshot_file_.reset(new ResultFile(result_file_path));
|
|
||||||
|
|
||||||
// Count myself in pending_capture_monitoring_snapshot_ack_count_,
|
// Count myself in pending_capture_monitoring_snapshot_ack_count_,
|
||||||
// acked below.
|
// acked below.
|
||||||
@@ -685,10 +677,6 @@ void TracingControllerImpl::OnDisableRecordingAcked(
|
|||||||
if (pending_disable_recording_ack_count_ != 0)
|
if (pending_disable_recording_ack_count_ != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
OnDisableRecordingComplete();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TracingControllerImpl::OnDisableRecordingComplete() {
|
|
||||||
// All acks (including from the subprocesses and the local trace) have been
|
// All acks (including from the subprocesses and the local trace) have been
|
||||||
// received.
|
// received.
|
||||||
is_recording_ = false;
|
is_recording_ = false;
|
||||||
@@ -697,34 +685,28 @@ void TracingControllerImpl::OnDisableRecordingComplete() {
|
|||||||
if (!pending_get_categories_done_callback_.is_null()) {
|
if (!pending_get_categories_done_callback_.is_null()) {
|
||||||
pending_get_categories_done_callback_.Run(known_category_groups_);
|
pending_get_categories_done_callback_.Run(known_category_groups_);
|
||||||
pending_get_categories_done_callback_.Reset();
|
pending_get_categories_done_callback_.Reset();
|
||||||
} else if (result_file_) {
|
} else if (trace_data_sink_.get()) {
|
||||||
result_file_->Close(
|
trace_data_sink_->Close();
|
||||||
base::Bind(&TracingControllerImpl::OnResultFileClosed,
|
trace_data_sink_ = NULL;
|
||||||
base::Unretained(this)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TracingControllerImpl::OnResultFileClosed() {
|
|
||||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
|
||||||
|
|
||||||
if (!result_file_)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!pending_disable_recording_done_callback_.is_null()) {
|
|
||||||
pending_disable_recording_done_callback_.Run(result_file_->path());
|
|
||||||
pending_disable_recording_done_callback_.Reset();
|
|
||||||
}
|
|
||||||
result_file_.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(OS_CHROMEOS) || defined(OS_WIN)
|
#if defined(OS_CHROMEOS) || defined(OS_WIN)
|
||||||
void TracingControllerImpl::OnEndSystemTracingAcked(
|
void TracingControllerImpl::OnEndSystemTracingAcked(
|
||||||
const scoped_refptr<base::RefCountedString>& events_str_ptr) {
|
const scoped_refptr<base::RefCountedString>& events_str_ptr) {
|
||||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||||
|
|
||||||
if (result_file_)
|
if (trace_data_sink_.get()) {
|
||||||
result_file_->WriteSystemTrace(events_str_ptr);
|
#if defined(OS_WIN)
|
||||||
|
// The Windows kernel events are kept into a JSon format stored as string
|
||||||
|
// and must not be escaped.
|
||||||
|
std::string json_string = events_str_ptr->data();
|
||||||
|
#else
|
||||||
|
std::string json_string =
|
||||||
|
base::GetQuotedJSONString(events_str_ptr->data());
|
||||||
|
#endif
|
||||||
|
trace_data_sink_->SetSystemTrace(json_string);
|
||||||
|
}
|
||||||
DCHECK(!is_system_tracing_);
|
DCHECK(!is_system_tracing_);
|
||||||
std::vector<std::string> category_groups;
|
std::vector<std::string> category_groups;
|
||||||
OnDisableRecordingAcked(NULL, category_groups);
|
OnDisableRecordingAcked(NULL, category_groups);
|
||||||
@@ -763,27 +745,12 @@ void TracingControllerImpl::OnCaptureMonitoringSnapshotAcked(
|
|||||||
if (pending_capture_monitoring_snapshot_ack_count_ != 0)
|
if (pending_capture_monitoring_snapshot_ack_count_ != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (monitoring_snapshot_file_) {
|
if (monitoring_data_sink_.get()) {
|
||||||
monitoring_snapshot_file_->Close(
|
monitoring_data_sink_->Close();
|
||||||
base::Bind(&TracingControllerImpl::OnMonitoringSnapshotFileClosed,
|
monitoring_data_sink_ = NULL;
|
||||||
base::Unretained(this)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TracingControllerImpl::OnMonitoringSnapshotFileClosed() {
|
|
||||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
|
||||||
|
|
||||||
if (!monitoring_snapshot_file_)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!pending_capture_monitoring_snapshot_done_callback_.is_null()) {
|
|
||||||
pending_capture_monitoring_snapshot_done_callback_.Run(
|
|
||||||
monitoring_snapshot_file_->path());
|
|
||||||
pending_capture_monitoring_snapshot_done_callback_.Reset();
|
|
||||||
}
|
|
||||||
monitoring_snapshot_file_.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TracingControllerImpl::OnTraceDataCollected(
|
void TracingControllerImpl::OnTraceDataCollected(
|
||||||
const scoped_refptr<base::RefCountedString>& events_str_ptr) {
|
const scoped_refptr<base::RefCountedString>& events_str_ptr) {
|
||||||
// OnTraceDataCollected may be called from any browser thread, either by the
|
// OnTraceDataCollected may be called from any browser thread, either by the
|
||||||
@@ -795,8 +762,8 @@ void TracingControllerImpl::OnTraceDataCollected(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result_file_)
|
if (trace_data_sink_.get())
|
||||||
result_file_->Write(events_str_ptr);
|
trace_data_sink_->AddTraceChunk(events_str_ptr->data());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TracingControllerImpl::OnMonitoringTraceDataCollected(
|
void TracingControllerImpl::OnMonitoringTraceDataCollected(
|
||||||
@@ -808,8 +775,8 @@ void TracingControllerImpl::OnMonitoringTraceDataCollected(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (monitoring_snapshot_file_)
|
if (monitoring_data_sink_.get())
|
||||||
monitoring_snapshot_file_->Write(events_str_ptr);
|
monitoring_data_sink_->AddTraceChunk(events_str_ptr->data());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TracingControllerImpl::OnLocalTraceDataCollected(
|
void TracingControllerImpl::OnLocalTraceDataCollected(
|
||||||
|
@@ -9,12 +9,12 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "base/files/file_path.h"
|
|
||||||
#include "base/lazy_instance.h"
|
#include "base/lazy_instance.h"
|
||||||
#include "content/public/browser/tracing_controller.h"
|
#include "content/public/browser/tracing_controller.h"
|
||||||
|
|
||||||
namespace base {
|
namespace base {
|
||||||
class RefCountedString;
|
class RefCountedString;
|
||||||
|
class RefCountedMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace content {
|
namespace content {
|
||||||
@@ -34,8 +34,7 @@ class TracingControllerImpl : public TracingController {
|
|||||||
const base::debug::TraceOptions& trace_options,
|
const base::debug::TraceOptions& trace_options,
|
||||||
const EnableRecordingDoneCallback& callback) OVERRIDE;
|
const EnableRecordingDoneCallback& callback) OVERRIDE;
|
||||||
virtual bool DisableRecording(
|
virtual bool DisableRecording(
|
||||||
const base::FilePath& result_file_path,
|
const scoped_refptr<TraceDataSink>& sink) OVERRIDE;
|
||||||
const TracingFileResultCallback& callback) OVERRIDE;
|
|
||||||
virtual bool EnableMonitoring(
|
virtual bool EnableMonitoring(
|
||||||
const base::debug::CategoryFilter& category_filter,
|
const base::debug::CategoryFilter& category_filter,
|
||||||
const base::debug::TraceOptions& trace_options,
|
const base::debug::TraceOptions& trace_options,
|
||||||
@@ -47,8 +46,7 @@ class TracingControllerImpl : public TracingController {
|
|||||||
base::debug::CategoryFilter* out_category_filter,
|
base::debug::CategoryFilter* out_category_filter,
|
||||||
base::debug::TraceOptions* out_trace_options) OVERRIDE;
|
base::debug::TraceOptions* out_trace_options) OVERRIDE;
|
||||||
virtual bool CaptureMonitoringSnapshot(
|
virtual bool CaptureMonitoringSnapshot(
|
||||||
const base::FilePath& result_file_path,
|
const scoped_refptr<TraceDataSink>& sink) OVERRIDE;
|
||||||
const TracingFileResultCallback& callback) OVERRIDE;
|
|
||||||
virtual bool GetTraceBufferPercentFull(
|
virtual bool GetTraceBufferPercentFull(
|
||||||
const GetTraceBufferPercentFullCallback& callback) OVERRIDE;
|
const GetTraceBufferPercentFullCallback& callback) OVERRIDE;
|
||||||
virtual bool SetWatchEvent(const std::string& category_name,
|
virtual bool SetWatchEvent(const std::string& category_name,
|
||||||
@@ -61,7 +59,6 @@ class TracingControllerImpl : public TracingController {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::set<scoped_refptr<TraceMessageFilter> > TraceMessageFilterSet;
|
typedef std::set<scoped_refptr<TraceMessageFilter> > TraceMessageFilterSet;
|
||||||
class ResultFile;
|
|
||||||
|
|
||||||
friend struct base::DefaultLazyInstanceTraits<TracingControllerImpl>;
|
friend struct base::DefaultLazyInstanceTraits<TracingControllerImpl>;
|
||||||
friend class TraceMessageFilter;
|
friend class TraceMessageFilter;
|
||||||
@@ -74,7 +71,7 @@ class TracingControllerImpl : public TracingController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool can_disable_recording() const {
|
bool can_disable_recording() const {
|
||||||
return is_recording_ && !result_file_;
|
return is_recording_ && !trace_data_sink_.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool can_enable_monitoring() const {
|
bool can_enable_monitoring() const {
|
||||||
@@ -82,7 +79,7 @@ class TracingControllerImpl : public TracingController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool can_disable_monitoring() const {
|
bool can_disable_monitoring() const {
|
||||||
return is_monitoring_ && !monitoring_snapshot_file_;
|
return is_monitoring_ && !monitoring_data_sink_.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool can_get_trace_buffer_percent_full() const {
|
bool can_get_trace_buffer_percent_full() const {
|
||||||
@@ -114,8 +111,6 @@ class TracingControllerImpl : public TracingController {
|
|||||||
void OnDisableRecordingAcked(
|
void OnDisableRecordingAcked(
|
||||||
TraceMessageFilter* trace_message_filter,
|
TraceMessageFilter* trace_message_filter,
|
||||||
const std::vector<std::string>& known_category_groups);
|
const std::vector<std::string>& known_category_groups);
|
||||||
void OnDisableRecordingComplete();
|
|
||||||
void OnResultFileClosed();
|
|
||||||
|
|
||||||
#if defined(OS_CHROMEOS) || defined(OS_WIN)
|
#if defined(OS_CHROMEOS) || defined(OS_WIN)
|
||||||
void OnEndSystemTracingAcked(
|
void OnEndSystemTracingAcked(
|
||||||
@@ -124,7 +119,6 @@ class TracingControllerImpl : public TracingController {
|
|||||||
|
|
||||||
void OnCaptureMonitoringSnapshotAcked(
|
void OnCaptureMonitoringSnapshotAcked(
|
||||||
TraceMessageFilter* trace_message_filter);
|
TraceMessageFilter* trace_message_filter);
|
||||||
void OnMonitoringSnapshotFileClosed();
|
|
||||||
|
|
||||||
void OnTraceBufferPercentFullReply(
|
void OnTraceBufferPercentFullReply(
|
||||||
TraceMessageFilter* trace_message_filter,
|
TraceMessageFilter* trace_message_filter,
|
||||||
@@ -141,8 +135,7 @@ class TracingControllerImpl : public TracingController {
|
|||||||
void OnEnableRecordingDone(const base::debug::CategoryFilter& category_filter,
|
void OnEnableRecordingDone(const base::debug::CategoryFilter& category_filter,
|
||||||
const base::debug::TraceOptions& trace_options,
|
const base::debug::TraceOptions& trace_options,
|
||||||
const EnableRecordingDoneCallback& callback);
|
const EnableRecordingDoneCallback& callback);
|
||||||
void OnDisableRecordingDone(const base::FilePath& result_file_path,
|
void OnDisableRecordingDone();
|
||||||
const TracingFileResultCallback& callback);
|
|
||||||
void OnEnableMonitoringDone(
|
void OnEnableMonitoringDone(
|
||||||
const base::debug::CategoryFilter& category_filter,
|
const base::debug::CategoryFilter& category_filter,
|
||||||
const base::debug::TraceOptions& trace_options,
|
const base::debug::TraceOptions& trace_options,
|
||||||
@@ -172,8 +165,6 @@ class TracingControllerImpl : public TracingController {
|
|||||||
base::debug::TraceOptions trace_options_;
|
base::debug::TraceOptions trace_options_;
|
||||||
|
|
||||||
GetCategoriesDoneCallback pending_get_categories_done_callback_;
|
GetCategoriesDoneCallback pending_get_categories_done_callback_;
|
||||||
TracingFileResultCallback pending_disable_recording_done_callback_;
|
|
||||||
TracingFileResultCallback pending_capture_monitoring_snapshot_done_callback_;
|
|
||||||
GetTraceBufferPercentFullCallback pending_trace_buffer_percent_full_callback_;
|
GetTraceBufferPercentFullCallback pending_trace_buffer_percent_full_callback_;
|
||||||
|
|
||||||
std::string watch_category_name_;
|
std::string watch_category_name_;
|
||||||
@@ -182,8 +173,8 @@ class TracingControllerImpl : public TracingController {
|
|||||||
|
|
||||||
std::set<std::string> known_category_groups_;
|
std::set<std::string> known_category_groups_;
|
||||||
std::set<TracingUI*> tracing_uis_;
|
std::set<TracingUI*> tracing_uis_;
|
||||||
scoped_ptr<ResultFile> result_file_;
|
scoped_refptr<TraceDataSink> trace_data_sink_;
|
||||||
scoped_ptr<ResultFile> monitoring_snapshot_file_;
|
scoped_refptr<TraceDataSink> monitoring_data_sink_;
|
||||||
DISALLOW_COPY_AND_ASSIGN(TracingControllerImpl);
|
DISALLOW_COPY_AND_ASSIGN(TracingControllerImpl);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -13,7 +13,6 @@
|
|||||||
#include "base/bind_helpers.h"
|
#include "base/bind_helpers.h"
|
||||||
#include "base/command_line.h"
|
#include "base/command_line.h"
|
||||||
#include "base/debug/trace_event.h"
|
#include "base/debug/trace_event.h"
|
||||||
#include "base/files/file_util.h"
|
|
||||||
#include "base/format_macros.h"
|
#include "base/format_macros.h"
|
||||||
#include "base/json/json_reader.h"
|
#include "base/json/json_reader.h"
|
||||||
#include "base/json/json_writer.h"
|
#include "base/json/json_writer.h"
|
||||||
@@ -136,23 +135,6 @@ void OnTraceBufferPercentFullResult(
|
|||||||
callback.Run(base::RefCountedString::TakeString(&str));
|
callback.Run(base::RefCountedString::TakeString(&str));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReadRecordingResult(const WebUIDataSource::GotDataCallback& callback,
|
|
||||||
const base::FilePath& path) {
|
|
||||||
std::string tmp;
|
|
||||||
if (!base::ReadFileToString(path, &tmp))
|
|
||||||
LOG(ERROR) << "Failed to read file " << path.value();
|
|
||||||
base::DeleteFile(path, false);
|
|
||||||
callback.Run(base::RefCountedString::TakeString(&tmp));
|
|
||||||
}
|
|
||||||
|
|
||||||
void BeginReadingRecordingResult(
|
|
||||||
const WebUIDataSource::GotDataCallback& callback,
|
|
||||||
const base::FilePath& path) {
|
|
||||||
BrowserThread::PostTask(
|
|
||||||
BrowserThread::FILE, FROM_HERE,
|
|
||||||
base::Bind(ReadRecordingResult, callback, path));
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnMonitoringEnabledAck(const WebUIDataSource::GotDataCallback& callback);
|
void OnMonitoringEnabledAck(const WebUIDataSource::GotDataCallback& callback);
|
||||||
|
|
||||||
bool EnableMonitoring(const std::string& data64,
|
bool EnableMonitoring(const std::string& data64,
|
||||||
@@ -205,21 +187,9 @@ void GetMonitoringStatus(const WebUIDataSource::GotDataCallback& callback) {
|
|||||||
callback.Run(monitoring_options_base64);
|
callback.Run(monitoring_options_base64);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReadMonitoringSnapshot(const WebUIDataSource::GotDataCallback& callback,
|
void TracingCallbackWrapper(const WebUIDataSource::GotDataCallback& callback,
|
||||||
const base::FilePath& path) {
|
base::RefCountedString* data) {
|
||||||
std::string tmp;
|
callback.Run(data);
|
||||||
if (!base::ReadFileToString(path, &tmp))
|
|
||||||
LOG(ERROR) << "Failed to read file " << path.value();
|
|
||||||
base::DeleteFile(path, false);
|
|
||||||
callback.Run(base::RefCountedString::TakeString(&tmp));
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnMonitoringSnapshotCaptured(
|
|
||||||
const WebUIDataSource::GotDataCallback& callback,
|
|
||||||
const base::FilePath& path) {
|
|
||||||
BrowserThread::PostTask(
|
|
||||||
BrowserThread::FILE, FROM_HERE,
|
|
||||||
base::Bind(ReadMonitoringSnapshot, callback, path));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OnBeginJSONRequest(const std::string& path,
|
bool OnBeginJSONRequest(const std::string& path,
|
||||||
@@ -240,7 +210,8 @@ bool OnBeginJSONRequest(const std::string& path,
|
|||||||
}
|
}
|
||||||
if (path == "json/end_recording") {
|
if (path == "json/end_recording") {
|
||||||
return TracingController::GetInstance()->DisableRecording(
|
return TracingController::GetInstance()->DisableRecording(
|
||||||
base::FilePath(), base::Bind(BeginReadingRecordingResult, callback));
|
TracingControllerImpl::CreateStringSink(
|
||||||
|
base::Bind(TracingCallbackWrapper, callback)));
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* enableMonitoringPath = "json/begin_monitoring?";
|
const char* enableMonitoringPath = "json/begin_monitoring?";
|
||||||
@@ -254,7 +225,8 @@ bool OnBeginJSONRequest(const std::string& path,
|
|||||||
}
|
}
|
||||||
if (path == "json/capture_monitoring") {
|
if (path == "json/capture_monitoring") {
|
||||||
TracingController::GetInstance()->CaptureMonitoringSnapshot(
|
TracingController::GetInstance()->CaptureMonitoringSnapshot(
|
||||||
base::FilePath(), base::Bind(OnMonitoringSnapshotCaptured, callback));
|
TracingControllerImpl::CreateStringSink(
|
||||||
|
base::Bind(TracingCallbackWrapper, callback)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (path == "json/get_monitoring_status") {
|
if (path == "json/get_monitoring_status") {
|
||||||
|
@@ -10,12 +10,9 @@
|
|||||||
|
|
||||||
#include "base/callback.h"
|
#include "base/callback.h"
|
||||||
#include "base/debug/trace_event.h"
|
#include "base/debug/trace_event.h"
|
||||||
|
#include "base/memory/ref_counted.h"
|
||||||
#include "content/common/content_export.h"
|
#include "content/common/content_export.h"
|
||||||
|
|
||||||
namespace base {
|
|
||||||
class FilePath;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace content {
|
namespace content {
|
||||||
|
|
||||||
class TracingController;
|
class TracingController;
|
||||||
@@ -29,6 +26,36 @@ class TracingController {
|
|||||||
|
|
||||||
CONTENT_EXPORT static TracingController* GetInstance();
|
CONTENT_EXPORT static TracingController* GetInstance();
|
||||||
|
|
||||||
|
// An interface for trace data consumer. An implemnentation of this interface
|
||||||
|
// is passed to either DisableTracing() or CaptureMonitoringSnapshot() and
|
||||||
|
// receives the trace data followed by a notification that all child processes
|
||||||
|
// have completed tracing and the data collection is over.
|
||||||
|
// All methods are called on the UI thread.
|
||||||
|
// Close method will be called exactly once and no methods will be
|
||||||
|
// called after that.
|
||||||
|
class CONTENT_EXPORT TraceDataSink
|
||||||
|
: public base::RefCountedThreadSafe<TraceDataSink> {
|
||||||
|
public:
|
||||||
|
virtual void AddTraceChunk(const std::string& chunk) {}
|
||||||
|
virtual void SetSystemTrace(const std::string& data) {}
|
||||||
|
virtual void Close() {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
friend class base::RefCountedThreadSafe<TraceDataSink>;
|
||||||
|
virtual ~TraceDataSink() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a trace sink that may be supplied to DisableRecording or
|
||||||
|
// CaptureMonitoringSnapshot to capture the trace data as a string.
|
||||||
|
CONTENT_EXPORT static scoped_refptr<TraceDataSink> CreateStringSink(
|
||||||
|
const base::Callback<void(base::RefCountedString*)>& callback);
|
||||||
|
|
||||||
|
// Create a trace sink that may be supplied to DisableRecording or
|
||||||
|
// CaptureMonitoringSnapshot to dump the trace data to a file.
|
||||||
|
CONTENT_EXPORT static scoped_refptr<TraceDataSink> CreateFileSink(
|
||||||
|
const base::FilePath& file_path,
|
||||||
|
const base::Closure& callback);
|
||||||
|
|
||||||
// Get a set of category groups. The category groups can change as
|
// Get a set of category groups. The category groups can change as
|
||||||
// new code paths are reached.
|
// new code paths are reached.
|
||||||
//
|
//
|
||||||
@@ -76,15 +103,12 @@ class TracingController {
|
|||||||
// TracingFileResultCallback will be called back with a file that contains
|
// TracingFileResultCallback will be called back with a file that contains
|
||||||
// the traced data.
|
// the traced data.
|
||||||
//
|
//
|
||||||
// Trace data will be written into |result_file_path| if it is not empty, or
|
// If |trace_data_sink| is not null, it will receive chunks of trace data
|
||||||
// into a temporary file. The actual file path will be passed to |callback| if
|
// as a comma-separated sequences of JSON-stringified events, followed by
|
||||||
// it's not null.
|
// a notification that the trace collection is finished.
|
||||||
//
|
//
|
||||||
// If |result_file_path| is empty and |callback| is null, trace data won't be
|
virtual bool DisableRecording(
|
||||||
// written to any file.
|
const scoped_refptr<TraceDataSink>& trace_data_sink) = 0;
|
||||||
typedef base::Callback<void(const base::FilePath&)> TracingFileResultCallback;
|
|
||||||
virtual bool DisableRecording(const base::FilePath& result_file_path,
|
|
||||||
const TracingFileResultCallback& callback) = 0;
|
|
||||||
|
|
||||||
// Start monitoring on all processes.
|
// Start monitoring on all processes.
|
||||||
//
|
//
|
||||||
@@ -130,14 +154,11 @@ class TracingController {
|
|||||||
// request, TracingFileResultCallback will be called back with a file that
|
// request, TracingFileResultCallback will be called back with a file that
|
||||||
// contains the traced data.
|
// contains the traced data.
|
||||||
//
|
//
|
||||||
// Trace data will be written into |result_file_path| if it is not empty, or
|
// If |trace_data_sink| is not null, it will receive chunks of trace data
|
||||||
// into a temporary file. The actual file path will be passed to |callback|.
|
// as a comma-separated sequences of JSON-stringified events, followed by
|
||||||
//
|
// a notification that the trace collection is finished.
|
||||||
// If |result_file_path| is empty and |callback| is null, trace data won't be
|
|
||||||
// written to any file.
|
|
||||||
virtual bool CaptureMonitoringSnapshot(
|
virtual bool CaptureMonitoringSnapshot(
|
||||||
const base::FilePath& result_file_path,
|
const scoped_refptr<TraceDataSink>& trace_data_sink) = 0;
|
||||||
const TracingFileResultCallback& callback) = 0;
|
|
||||||
|
|
||||||
// Get the maximum across processes of trace buffer percent full state.
|
// Get the maximum across processes of trace buffer percent full state.
|
||||||
// When the TraceBufferPercentFull value is determined, the callback is
|
// When the TraceBufferPercentFull value is determined, the callback is
|
||||||
|
@@ -14,8 +14,8 @@
|
|||||||
#include "base/test/test_timeouts.h"
|
#include "base/test/test_timeouts.h"
|
||||||
#include "content/public/app/content_main.h"
|
#include "content/public/app/content_main.h"
|
||||||
#include "content/browser/renderer_host/render_process_host_impl.h"
|
#include "content/browser/renderer_host/render_process_host_impl.h"
|
||||||
|
#include "content/browser/tracing/tracing_controller_impl.h"
|
||||||
#include "content/public/browser/browser_thread.h"
|
#include "content/public/browser/browser_thread.h"
|
||||||
#include "content/public/browser/tracing_controller.h"
|
|
||||||
#include "content/public/common/content_switches.h"
|
#include "content/public/common/content_switches.h"
|
||||||
#include "content/public/common/main_function_params.h"
|
#include "content/public/common/main_function_params.h"
|
||||||
#include "content/public/test/test_launcher.h"
|
#include "content/public/test/test_launcher.h"
|
||||||
@@ -301,8 +301,11 @@ void BrowserTestBase::ProxyRunTestOnMainThreadLoop() {
|
|||||||
// Wait for tracing to collect results from the renderers.
|
// Wait for tracing to collect results from the renderers.
|
||||||
base::RunLoop run_loop;
|
base::RunLoop run_loop;
|
||||||
TracingController::GetInstance()->DisableRecording(
|
TracingController::GetInstance()->DisableRecording(
|
||||||
trace_file,
|
TracingControllerImpl::CreateFileSink(
|
||||||
base::Bind(&TraceDisableRecordingComplete, run_loop.QuitClosure()));
|
trace_file,
|
||||||
|
base::Bind(&TraceDisableRecordingComplete,
|
||||||
|
run_loop.QuitClosure(),
|
||||||
|
trace_file)));
|
||||||
run_loop.Run();
|
run_loop.Run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user