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..2849c8fa32c733be720a5c58ff30b58ad5d244c9 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) |
+ explicit 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) { |
dsinclair
2013/08/19 20:12:26
nit: indenting.
DaveMoore
2013/08/19 22:07:46
Done.
|
+ 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,69 @@ 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. |
+ std::string data = data_ptr->data(); |
+ const char* chars = data.data(); |
dsinclair
2013/08/19 20:12:26
Is it guaranteed that data() won't have any "'s in
DaveMoore
2013/08/19 22:07:46
Done.
|
+ WriteString("\"systemTraceEvents\":\""); |
+ int old_index = 0; |
+ for (size_t new_index = data.find('\n'); |
+ std::string::npos != new_index; |
+ old_index = new_index + 1, new_index = data.find('\n', old_index)) { |
+ WriteChars(chars + old_index, new_index - old_index); |
+ WriteChars("\\n", 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 (IsValid()) { |
dsinclair
2013/08/19 20:12:26
We seem to be doing if (!IsValid()) early returns
|
- 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_; |
+ FileType file_type_; |
+ 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_; |
}; |
-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 +168,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 |