Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(370)

Side by Side Diff: content/browser/tracing/trace_subscriber_stdio.cc

Issue 23125009: Add support for writing system traces at startup (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Wait for complete system tracing implementation Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/tracing/trace_subscriber_stdio.h" 5 #include "content/browser/tracing/trace_subscriber_stdio.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/debug/trace_event.h" 8 #include "base/debug/trace_event.h"
9 #include "base/file_util.h" 9 #include "base/file_util.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/threading/sequenced_worker_pool.h" 11 #include "base/threading/sequenced_worker_pool.h"
12 #include "content/public/browser/browser_thread.h" 12 #include "content/public/browser/browser_thread.h"
13 13
14 namespace content { 14 namespace content {
15 15
16 // All method calls on this class are done on a SequencedWorkerPool thread. 16 // All method calls on this class are done on a SequencedWorkerPool thread.
17 class TraceSubscriberStdioImpl 17 class TraceSubscriberStdio::TraceSubscriberStdioWorker
18 : public base::RefCountedThreadSafe<TraceSubscriberStdioImpl> { 18 : public base::RefCountedThreadSafe<TraceSubscriberStdioWorker> {
19 public: 19 public:
20 explicit TraceSubscriberStdioImpl(const base::FilePath& path) 20 explicit TraceSubscriberStdioWorker(const base::FilePath& path,
21 FileType file_type,
22 bool has_system_trace)
21 : path_(path), 23 : path_(path),
22 file_(0) {} 24 file_type_(file_type),
25 has_system_trace_(has_system_trace),
26 file_(0),
27 needs_comma_(false),
28 wrote_trace_(false),
29 has_pending_system_trace_(false),
30 wrote_system_trace_(false) {}
23 31
24 void OnStart() { 32 void OnTraceStart() {
25 DCHECK(!file_); 33 DCHECK(!file_);
26 trace_buffer_.SetOutputCallback(
27 base::Bind(&TraceSubscriberStdioImpl::Write, this));
28 file_ = file_util::OpenFile(path_, "w+"); 34 file_ = file_util::OpenFile(path_, "w+");
29 if (IsValid()) { 35 if (!IsValid()) {
30 LOG(INFO) << "Logging performance trace to file: " << path_.value(); 36 LOG(ERROR) << "Failed to open performance trace file: " << path_.value();
31 trace_buffer_.Start(); 37 return;
38 }
39
40 LOG(INFO) << "Logging performance trace to file: " << path_.value();
41 if (file_type_ == FILE_TYPE_PROPERTY_LIST)
42 WriteString("{\"traceEvents\":");
43 WriteString("[");
44 }
45
46 void OnTraceData(const scoped_refptr<base::RefCountedString>& data_ptr) {
47 if (!IsValid())
48 return;
49 if (needs_comma_)
50 WriteString(",");
51 WriteString(data_ptr->data());
52 needs_comma_ = true;
53 }
54
55 void OnSystemTraceData(
56 const scoped_refptr<base::RefCountedString>& data_ptr) {
57 if (wrote_trace_) {
58 WriteSystemTrace(data_ptr);
59 End();
32 } else { 60 } else {
33 LOG(ERROR) << "Failed to open performance trace file: " << path_.value(); 61 pending_system_trace_ = data_ptr;
62 has_pending_system_trace_ = true;
34 } 63 }
35 } 64 }
36 65
37 void OnData(const scoped_refptr<base::RefCountedString>& data_ptr) { 66 void OnTraceEnd() {
38 trace_buffer_.AddFragment(data_ptr->data()); 67 if (!IsValid())
68 return;
69 WriteString("]");
70
71 wrote_trace_ = true;
72
73 if (!has_system_trace_ || wrote_system_trace_) {
74 End();
75 return;
76 }
77
78 WriteString(",");
79 if (has_pending_system_trace_) {
80 WriteSystemTrace(pending_system_trace_);
81 End();
82 }
39 } 83 }
40 84
41 void OnEnd() { 85 private:
42 trace_buffer_.Finish(); 86 friend class base::RefCountedThreadSafe<TraceSubscriberStdioWorker>;
87
88 ~TraceSubscriberStdioWorker() {
43 CloseFile(); 89 CloseFile();
44 } 90 }
45 91
46 private:
47 friend class base::RefCountedThreadSafe<TraceSubscriberStdioImpl>;
48
49 ~TraceSubscriberStdioImpl() {
50 CloseFile();
51 }
52
53 bool IsValid() const { 92 bool IsValid() const {
54 return file_ && (0 == ferror(file_)); 93 return file_ && (0 == ferror(file_));
55 } 94 }
56 95
57 void CloseFile() { 96 void CloseFile() {
58 if (file_) { 97 if (file_) {
59 fclose(file_); 98 fclose(file_);
60 file_ = 0; 99 file_ = 0;
100
61 } 101 }
62 // This is important, as it breaks a reference cycle.
63 trace_buffer_.SetOutputCallback(
64 base::debug::TraceResultBuffer::OutputCallback());
65 } 102 }
66 103
67 void Write(const std::string& output_str) { 104 void End() {
105 if (file_type_ == FILE_TYPE_PROPERTY_LIST)
106 WriteString("}");
107 CloseFile();
108 }
109
110 void WriteSystemTrace(const scoped_refptr<base::RefCountedString>& data_ptr) {
111 // Newlines need to be replaced with the string "\n" to be parsed correctly.
112 // Double quotes need to be replaced with the string "\"".
113 // System logs are ASCII.
114 std::string data = data_ptr->data();
115 const char* chars = data.c_str();
116 WriteString("\"systemTraceEvents\":\"");
117 int old_index = 0;
118 for (size_t new_index = data.find_first_of("\n\"");
119 std::string::npos != new_index;
120 old_index = new_index + 1,
121 new_index = data.find_first_of("\n\"", old_index)) {
122 WriteChars(chars + old_index, new_index - old_index);
123 if (chars[new_index] == '\n')
124 WriteChars("\\n", 2);
125 else
126 WriteChars("\\\"", 2);
127 }
128 WriteChars(chars + old_index, data.size() - old_index);
129 WriteString("\"");
130 wrote_system_trace_ = true;
131 }
132
133 void WriteChars(const char* output_chars, size_t size) {
68 if (IsValid()) { 134 if (IsValid()) {
69 size_t written = fwrite(output_str.data(), 1, output_str.size(), file_); 135 size_t written = fwrite(output_chars, 1, size, file_);
70 if (written != output_str.size()) { 136 if (written != size) {
71 LOG(ERROR) << "Error " << ferror(file_) << " in fwrite() to trace file"; 137 LOG(ERROR) << "Error " << ferror(file_) << " in fwrite() to trace file";
72 CloseFile(); 138 CloseFile();
73 } 139 }
74 } 140 }
75 } 141 }
76 142
143 void WriteString(const std::string& output_str) {
144 WriteChars(output_str.data(), output_str.size());
145 }
146
77 base::FilePath path_; 147 base::FilePath path_;
148 FileType file_type_;
149 bool has_system_trace_;
78 FILE* file_; 150 FILE* file_;
79 base::debug::TraceResultBuffer trace_buffer_; 151 bool needs_comma_;
152 bool wrote_trace_;
153 bool has_pending_system_trace_;
154 bool wrote_system_trace_;
155 scoped_refptr<base::RefCountedString> pending_system_trace_;
80 }; 156 };
81 157
82 TraceSubscriberStdio::TraceSubscriberStdio(const base::FilePath& path) 158 TraceSubscriberStdio::TraceSubscriberStdio(const base::FilePath& path,
83 : impl_(new TraceSubscriberStdioImpl(path)) { 159 FileType file_type,
160 bool has_system_trace)
161 : worker_(new TraceSubscriberStdioWorker(path,
162 file_type,
163 has_system_trace)) {
164 if (has_system_trace)
165 CHECK_EQ(FILE_TYPE_PROPERTY_LIST, file_type);
84 BrowserThread::PostBlockingPoolSequencedTask( 166 BrowserThread::PostBlockingPoolSequencedTask(
85 __FILE__, FROM_HERE, 167 __FILE__, FROM_HERE,
86 base::Bind(&TraceSubscriberStdioImpl::OnStart, impl_)); 168 base::Bind(&TraceSubscriberStdioWorker::OnTraceStart, worker_));
87 } 169 }
88 170
89 TraceSubscriberStdio::~TraceSubscriberStdio() { 171 TraceSubscriberStdio::~TraceSubscriberStdio() {
90 } 172 }
91 173
92 void TraceSubscriberStdio::OnEndTracingComplete() { 174 void TraceSubscriberStdio::OnEndTracingComplete() {
93 BrowserThread::PostBlockingPoolSequencedTask( 175 BrowserThread::PostBlockingPoolSequencedTask(
94 __FILE__, FROM_HERE, 176 __FILE__, FROM_HERE,
95 base::Bind(&TraceSubscriberStdioImpl::OnEnd, impl_)); 177 base::Bind(&TraceSubscriberStdioWorker::OnTraceEnd, worker_));
96 } 178 }
97 179
98 void TraceSubscriberStdio::OnTraceDataCollected( 180 void TraceSubscriberStdio::OnTraceDataCollected(
99 const scoped_refptr<base::RefCountedString>& data_ptr) { 181 const scoped_refptr<base::RefCountedString>& data_ptr) {
100 BrowserThread::PostBlockingPoolSequencedTask( 182 BrowserThread::PostBlockingPoolSequencedTask(
101 __FILE__, FROM_HERE, 183 __FILE__, FROM_HERE,
102 base::Bind(&TraceSubscriberStdioImpl::OnData, impl_, data_ptr)); 184 base::Bind(&TraceSubscriberStdioWorker::OnTraceData, worker_, data_ptr));
185 }
186
187 void TraceSubscriberStdio::OnEndSystemTracing(
188 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
189 BrowserThread::PostBlockingPoolSequencedTask(
190 __FILE__, FROM_HERE,
191 base::Bind(&TraceSubscriberStdioWorker::OnSystemTraceData,
192 worker_,
193 events_str_ptr));
103 } 194 }
104 195
105 } // namespace content 196 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698