OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "content/browser/tracing/trace_subscriber_stdio.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/debug/trace_event.h" | |
9 #include "base/file_util.h" | |
10 #include "base/logging.h" | |
11 #include "base/threading/sequenced_worker_pool.h" | |
12 #include "content/public/browser/browser_thread.h" | |
13 | |
14 namespace content { | |
15 | |
16 // All method calls on this class are done on a SequencedWorkerPool thread. | |
17 class TraceSubscriberStdio::TraceSubscriberStdioWorker | |
18 : public base::RefCountedThreadSafe<TraceSubscriberStdioWorker> { | |
19 public: | |
20 TraceSubscriberStdioWorker(const base::FilePath& path, | |
21 FileType file_type, | |
22 bool has_system_trace) | |
23 : path_(path), | |
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) {} | |
31 | |
32 void OnTraceStart() { | |
33 DCHECK(!file_); | |
34 file_ = file_util::OpenFile(path_, "w+"); | |
35 if (!IsValid()) { | |
36 LOG(ERROR) << "Failed to open performance trace file: " << path_.value(); | |
37 return; | |
38 } | |
39 | |
40 VLOG(0) << "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 DCHECK(!data_ptr->data().empty()); | |
50 if (needs_comma_) | |
51 WriteString(","); | |
52 WriteString(data_ptr->data()); | |
53 needs_comma_ = true; | |
54 } | |
55 | |
56 void OnSystemTraceData( | |
57 const scoped_refptr<base::RefCountedString>& data_ptr) { | |
58 if (wrote_trace_) { | |
59 WriteSystemTrace(data_ptr); | |
60 End(); | |
61 } else { | |
62 pending_system_trace_ = data_ptr; | |
63 has_pending_system_trace_ = true; | |
64 } | |
65 } | |
66 | |
67 void OnTraceEnd() { | |
68 if (!IsValid()) | |
69 return; | |
70 WriteString("]"); | |
71 | |
72 wrote_trace_ = true; | |
73 | |
74 if (!has_system_trace_ || wrote_system_trace_) { | |
75 End(); | |
76 return; | |
77 } | |
78 | |
79 WriteString(","); | |
80 if (has_pending_system_trace_) { | |
81 WriteSystemTrace(pending_system_trace_); | |
82 End(); | |
83 } | |
84 } | |
85 | |
86 private: | |
87 friend class base::RefCountedThreadSafe<TraceSubscriberStdioWorker>; | |
88 | |
89 ~TraceSubscriberStdioWorker() { | |
90 CloseFile(); | |
91 } | |
92 | |
93 bool IsValid() const { | |
94 return file_ && (0 == ferror(file_)); | |
95 } | |
96 | |
97 void CloseFile() { | |
98 if (file_) { | |
99 fclose(file_); | |
100 file_ = 0; | |
101 | |
102 } | |
103 } | |
104 | |
105 void End() { | |
106 if (file_type_ == FILE_TYPE_PROPERTY_LIST) | |
107 WriteString("}"); | |
108 CloseFile(); | |
109 } | |
110 | |
111 void WriteSystemTrace(const scoped_refptr<base::RefCountedString>& data_ptr) { | |
112 // Newlines need to be replaced with the string "\n" to be parsed correctly. | |
113 // Double quotes need to be replaced with the string "\"". | |
114 // System logs are ASCII. | |
115 const std::string& data = data_ptr->data(); | |
116 const char* chars = data.c_str(); | |
117 WriteString("\"systemTraceEvents\":\""); | |
118 size_t old_index = 0; | |
119 for (size_t new_index = data.find_first_of("\n\""); | |
120 std::string::npos != new_index; | |
121 old_index = new_index + 1, | |
122 new_index = data.find_first_of("\n\"", old_index)) { | |
123 WriteChars(chars + old_index, new_index - old_index); | |
124 if (chars[new_index] == '\n') | |
125 WriteChars("\\n", 2); | |
126 else | |
127 WriteChars("\\\"", 2); | |
128 } | |
129 WriteChars(chars + old_index, data.size() - old_index); | |
130 WriteString("\""); | |
131 wrote_system_trace_ = true; | |
132 } | |
133 | |
134 void WriteChars(const char* output_chars, size_t size) { | |
135 if (size == 0) | |
136 return; | |
137 | |
138 if (IsValid()) { | |
139 size_t written = fwrite(output_chars, 1, size, file_); | |
140 if (written != size) { | |
141 LOG(ERROR) << "Error " << ferror(file_) << " in fwrite() to trace file"; | |
142 CloseFile(); | |
143 } | |
144 } | |
145 } | |
146 | |
147 void WriteString(const std::string& output_str) { | |
148 WriteChars(output_str.data(), output_str.size()); | |
149 } | |
150 | |
151 base::FilePath path_; | |
152 const FileType file_type_; | |
153 const bool has_system_trace_; | |
154 FILE* file_; | |
155 bool needs_comma_; | |
156 bool wrote_trace_; | |
157 bool has_pending_system_trace_; | |
158 bool wrote_system_trace_; | |
159 scoped_refptr<base::RefCountedString> pending_system_trace_; | |
160 DISALLOW_COPY_AND_ASSIGN(TraceSubscriberStdioWorker); | |
161 }; | |
162 | |
163 TraceSubscriberStdio::TraceSubscriberStdio(const base::FilePath& path, | |
164 FileType file_type, | |
165 bool has_system_trace) | |
166 : worker_(new TraceSubscriberStdioWorker(path, | |
167 file_type, | |
168 has_system_trace)) { | |
169 if (has_system_trace) | |
170 CHECK_EQ(FILE_TYPE_PROPERTY_LIST, file_type); | |
171 BrowserThread::PostBlockingPoolSequencedTask( | |
172 __FILE__, FROM_HERE, | |
173 base::Bind(&TraceSubscriberStdioWorker::OnTraceStart, worker_)); | |
174 } | |
175 | |
176 TraceSubscriberStdio::~TraceSubscriberStdio() { | |
177 } | |
178 | |
179 void TraceSubscriberStdio::OnEndTracingComplete() { | |
180 BrowserThread::PostBlockingPoolSequencedTask( | |
181 __FILE__, FROM_HERE, | |
182 base::Bind(&TraceSubscriberStdioWorker::OnTraceEnd, worker_)); | |
183 } | |
184 | |
185 void TraceSubscriberStdio::OnTraceDataCollected( | |
186 const scoped_refptr<base::RefCountedString>& data_ptr) { | |
187 BrowserThread::PostBlockingPoolSequencedTask( | |
188 __FILE__, FROM_HERE, | |
189 base::Bind(&TraceSubscriberStdioWorker::OnTraceData, worker_, data_ptr)); | |
190 } | |
191 | |
192 void TraceSubscriberStdio::OnEndSystemTracing( | |
193 const scoped_refptr<base::RefCountedString>& events_str_ptr) { | |
194 BrowserThread::PostBlockingPoolSequencedTask( | |
195 __FILE__, FROM_HERE, | |
196 base::Bind(&TraceSubscriberStdioWorker::OnSystemTraceData, | |
197 worker_, | |
198 events_str_ptr)); | |
199 } | |
200 | |
201 } // namespace content | |
OLD | NEW |