| Index: content/browser/tracing/trace_subscriber_stdio.cc
|
| diff --git a/content/browser/tracing/trace_subscriber_stdio.cc b/content/browser/tracing/trace_subscriber_stdio.cc
|
| index b5f6e828c60b581f83a9ab4bb35209717e259d8b..35b96464e74b80ed0933f035c19b8e1ac46ca52f 100644
|
| --- a/content/browser/tracing/trace_subscriber_stdio.cc
|
| +++ b/content/browser/tracing/trace_subscriber_stdio.cc
|
| @@ -14,39 +14,78 @@
|
| namespace content {
|
|
|
| // All method calls on this class are done on a SequencedWorkerPool thread.
|
| -class TraceSubscriberStdioImpl
|
| - : public base::RefCountedThreadSafe<TraceSubscriberStdioImpl> {
|
| +class TraceSubscriberStdio::TraceSubscriberStdioWorker
|
| + : public base::RefCountedThreadSafe<TraceSubscriberStdioWorker> {
|
| public:
|
| - explicit TraceSubscriberStdioImpl(const base::FilePath& path)
|
| + TraceSubscriberStdioWorker(const base::FilePath& path,
|
| + FileType file_type,
|
| + bool has_system_trace)
|
| : path_(path),
|
| - file_(0) {}
|
| -
|
| - void OnStart() {
|
| + file_type_(file_type),
|
| + has_system_trace_(has_system_trace),
|
| + file_(0),
|
| + needs_comma_(false),
|
| + wrote_trace_(false),
|
| + has_pending_system_trace_(false),
|
| + wrote_system_trace_(false) {}
|
| +
|
| + void OnTraceStart() {
|
| DCHECK(!file_);
|
| - trace_buffer_.SetOutputCallback(
|
| - base::Bind(&TraceSubscriberStdioImpl::Write, this));
|
| file_ = file_util::OpenFile(path_, "w+");
|
| - if (IsValid()) {
|
| - LOG(INFO) << "Logging performance trace to file: " << path_.value();
|
| - trace_buffer_.Start();
|
| - } else {
|
| + if (!IsValid()) {
|
| LOG(ERROR) << "Failed to open performance trace file: " << path_.value();
|
| + return;
|
| }
|
| +
|
| + LOG(INFO) << "Logging performance trace to file: " << path_.value();
|
| + if (file_type_ == FILE_TYPE_PROPERTY_LIST)
|
| + WriteString("{\"traceEvents\":");
|
| + WriteString("[");
|
| }
|
|
|
| - void OnData(const scoped_refptr<base::RefCountedString>& data_ptr) {
|
| - trace_buffer_.AddFragment(data_ptr->data());
|
| + void OnTraceData(const scoped_refptr<base::RefCountedString>& data_ptr) {
|
| + if (!IsValid())
|
| + return;
|
| + if (needs_comma_)
|
| + WriteString(",");
|
| + WriteString(data_ptr->data());
|
| + needs_comma_ = true;
|
| }
|
|
|
| - void OnEnd() {
|
| - trace_buffer_.Finish();
|
| - CloseFile();
|
| + void OnSystemTraceData(
|
| + const scoped_refptr<base::RefCountedString>& data_ptr) {
|
| + if (wrote_trace_) {
|
| + WriteSystemTrace(data_ptr);
|
| + End();
|
| + } else {
|
| + pending_system_trace_ = data_ptr;
|
| + has_pending_system_trace_ = true;
|
| + }
|
| + }
|
| +
|
| + void OnTraceEnd() {
|
| + if (!IsValid())
|
| + return;
|
| + WriteString("]");
|
| +
|
| + wrote_trace_ = true;
|
| +
|
| + if (!has_system_trace_ || wrote_system_trace_) {
|
| + End();
|
| + return;
|
| + }
|
| +
|
| + WriteString(",");
|
| + if (has_pending_system_trace_) {
|
| + WriteSystemTrace(pending_system_trace_);
|
| + End();
|
| + }
|
| }
|
|
|
| private:
|
| - friend class base::RefCountedThreadSafe<TraceSubscriberStdioImpl>;
|
| + friend class base::RefCountedThreadSafe<TraceSubscriberStdioWorker>;
|
|
|
| - ~TraceSubscriberStdioImpl() {
|
| + ~TraceSubscriberStdioWorker() {
|
| CloseFile();
|
| }
|
|
|
| @@ -58,32 +97,79 @@ class TraceSubscriberStdioImpl
|
| if (file_) {
|
| fclose(file_);
|
| file_ = 0;
|
| +
|
| + }
|
| + }
|
| +
|
| + void End() {
|
| + if (file_type_ == FILE_TYPE_PROPERTY_LIST)
|
| + WriteString("}");
|
| + CloseFile();
|
| + }
|
| +
|
| + void WriteSystemTrace(const scoped_refptr<base::RefCountedString>& data_ptr) {
|
| + // Newlines need to be replaced with the string "\n" to be parsed correctly.
|
| + // Double quotes need to be replaced with the string "\"".
|
| + // System logs are ASCII.
|
| + const std::string& data = data_ptr->data();
|
| + const char* chars = data.c_str();
|
| + WriteString("\"systemTraceEvents\":\"");
|
| + size_t old_index = 0;
|
| + for (size_t new_index = data.find_first_of("\n\"");
|
| + std::string::npos != new_index;
|
| + old_index = new_index + 1,
|
| + new_index = data.find_first_of("\n\"", old_index)) {
|
| + WriteChars(chars + old_index, new_index - old_index);
|
| + if (chars[new_index] == '\n')
|
| + WriteChars("\\n", 2);
|
| + else
|
| + WriteChars("\\\"", 2);
|
| }
|
| - // This is important, as it breaks a reference cycle.
|
| - trace_buffer_.SetOutputCallback(
|
| - base::debug::TraceResultBuffer::OutputCallback());
|
| + WriteChars(chars + old_index, data.size() - old_index);
|
| + WriteString("\"");
|
| + wrote_system_trace_ = true;
|
| }
|
|
|
| - void Write(const std::string& output_str) {
|
| + void WriteChars(const char* output_chars, size_t size) {
|
| + if (size == 0)
|
| + return;
|
| +
|
| if (IsValid()) {
|
| - size_t written = fwrite(output_str.data(), 1, output_str.size(), file_);
|
| - if (written != output_str.size()) {
|
| + size_t written = fwrite(output_chars, 1, size, file_);
|
| + if (written != size) {
|
| LOG(ERROR) << "Error " << ferror(file_) << " in fwrite() to trace file";
|
| CloseFile();
|
| }
|
| }
|
| }
|
|
|
| + void WriteString(const std::string& output_str) {
|
| + WriteChars(output_str.data(), output_str.size());
|
| + }
|
| +
|
| base::FilePath path_;
|
| + const FileType file_type_;
|
| + const bool has_system_trace_;
|
| FILE* file_;
|
| - base::debug::TraceResultBuffer trace_buffer_;
|
| + bool needs_comma_;
|
| + bool wrote_trace_;
|
| + bool has_pending_system_trace_;
|
| + bool wrote_system_trace_;
|
| + scoped_refptr<base::RefCountedString> pending_system_trace_;
|
| + DISALLOW_COPY_AND_ASSIGN(TraceSubscriberStdioWorker);
|
| };
|
|
|
| -TraceSubscriberStdio::TraceSubscriberStdio(const base::FilePath& path)
|
| - : impl_(new TraceSubscriberStdioImpl(path)) {
|
| +TraceSubscriberStdio::TraceSubscriberStdio(const base::FilePath& path,
|
| + FileType file_type,
|
| + bool has_system_trace)
|
| + : worker_(new TraceSubscriberStdioWorker(path,
|
| + file_type,
|
| + has_system_trace)) {
|
| + if (has_system_trace)
|
| + CHECK_EQ(FILE_TYPE_PROPERTY_LIST, file_type);
|
| BrowserThread::PostBlockingPoolSequencedTask(
|
| __FILE__, FROM_HERE,
|
| - base::Bind(&TraceSubscriberStdioImpl::OnStart, impl_));
|
| + base::Bind(&TraceSubscriberStdioWorker::OnTraceStart, worker_));
|
| }
|
|
|
| TraceSubscriberStdio::~TraceSubscriberStdio() {
|
| @@ -92,14 +178,23 @@ TraceSubscriberStdio::~TraceSubscriberStdio() {
|
| void TraceSubscriberStdio::OnEndTracingComplete() {
|
| BrowserThread::PostBlockingPoolSequencedTask(
|
| __FILE__, FROM_HERE,
|
| - base::Bind(&TraceSubscriberStdioImpl::OnEnd, impl_));
|
| + base::Bind(&TraceSubscriberStdioWorker::OnTraceEnd, worker_));
|
| }
|
|
|
| void TraceSubscriberStdio::OnTraceDataCollected(
|
| const scoped_refptr<base::RefCountedString>& data_ptr) {
|
| BrowserThread::PostBlockingPoolSequencedTask(
|
| __FILE__, FROM_HERE,
|
| - base::Bind(&TraceSubscriberStdioImpl::OnData, impl_, data_ptr));
|
| + base::Bind(&TraceSubscriberStdioWorker::OnTraceData, worker_, data_ptr));
|
| +}
|
| +
|
| +void TraceSubscriberStdio::OnEndSystemTracing(
|
| + const scoped_refptr<base::RefCountedString>& events_str_ptr) {
|
| + BrowserThread::PostBlockingPoolSequencedTask(
|
| + __FILE__, FROM_HERE,
|
| + base::Bind(&TraceSubscriberStdioWorker::OnSystemTraceData,
|
| + worker_,
|
| + events_str_ptr));
|
| }
|
|
|
| } // namespace content
|
|
|