Chromium Code Reviews| OLD | NEW |
|---|---|
| 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) { | |
|
dsinclair
2013/08/19 20:12:26
nit: indenting.
DaveMoore
2013/08/19 22:07:46
Done.
| |
| 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 std::string data = data_ptr->data(); | |
| 113 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.
| |
| 114 WriteString("\"systemTraceEvents\":\""); | |
| 115 int old_index = 0; | |
| 116 for (size_t new_index = data.find('\n'); | |
| 117 std::string::npos != new_index; | |
| 118 old_index = new_index + 1, new_index = data.find('\n', old_index)) { | |
| 119 WriteChars(chars + old_index, new_index - old_index); | |
| 120 WriteChars("\\n", 2); | |
| 121 } | |
| 122 WriteChars(chars + old_index, data.size() - old_index); | |
| 123 WriteString("\""); | |
| 124 wrote_system_trace_ = true; | |
| 125 } | |
| 126 | |
| 127 void WriteChars(const char* output_chars, size_t size) { | |
| 68 if (IsValid()) { | 128 if (IsValid()) { |
|
dsinclair
2013/08/19 20:12:26
We seem to be doing if (!IsValid()) early returns
| |
| 69 size_t written = fwrite(output_str.data(), 1, output_str.size(), file_); | 129 size_t written = fwrite(output_chars, 1, size, file_); |
| 70 if (written != output_str.size()) { | 130 if (written != size) { |
| 71 LOG(ERROR) << "Error " << ferror(file_) << " in fwrite() to trace file"; | 131 LOG(ERROR) << "Error " << ferror(file_) << " in fwrite() to trace file"; |
| 72 CloseFile(); | 132 CloseFile(); |
| 73 } | 133 } |
| 74 } | 134 } |
| 75 } | 135 } |
| 76 | 136 |
| 137 void WriteString(const std::string& output_str) { | |
| 138 WriteChars(output_str.data(), output_str.size()); | |
| 139 } | |
| 140 | |
| 77 base::FilePath path_; | 141 base::FilePath path_; |
| 142 FileType file_type_; | |
| 143 bool has_system_trace_; | |
| 78 FILE* file_; | 144 FILE* file_; |
| 79 base::debug::TraceResultBuffer trace_buffer_; | 145 bool needs_comma_; |
| 146 bool wrote_trace_; | |
| 147 bool has_pending_system_trace_; | |
| 148 bool wrote_system_trace_; | |
| 149 scoped_refptr<base::RefCountedString> pending_system_trace_; | |
| 80 }; | 150 }; |
| 81 | 151 |
| 82 TraceSubscriberStdio::TraceSubscriberStdio(const base::FilePath& path) | 152 TraceSubscriberStdio::TraceSubscriberStdio(const base::FilePath& path, |
| 83 : impl_(new TraceSubscriberStdioImpl(path)) { | 153 FileType file_type, |
| 154 bool has_system_trace) | |
| 155 : worker_(new TraceSubscriberStdioWorker(path, | |
| 156 file_type, | |
| 157 has_system_trace)) { | |
| 158 if (has_system_trace) | |
| 159 CHECK_EQ(FILE_TYPE_PROPERTY_LIST, file_type); | |
| 84 BrowserThread::PostBlockingPoolSequencedTask( | 160 BrowserThread::PostBlockingPoolSequencedTask( |
| 85 __FILE__, FROM_HERE, | 161 __FILE__, FROM_HERE, |
| 86 base::Bind(&TraceSubscriberStdioImpl::OnStart, impl_)); | 162 base::Bind(&TraceSubscriberStdioWorker::OnTraceStart, worker_)); |
| 87 } | 163 } |
| 88 | 164 |
| 89 TraceSubscriberStdio::~TraceSubscriberStdio() { | 165 TraceSubscriberStdio::~TraceSubscriberStdio() { |
| 90 } | 166 } |
| 91 | 167 |
| 92 void TraceSubscriberStdio::OnEndTracingComplete() { | 168 void TraceSubscriberStdio::OnEndTracingComplete() { |
| 93 BrowserThread::PostBlockingPoolSequencedTask( | 169 BrowserThread::PostBlockingPoolSequencedTask( |
| 94 __FILE__, FROM_HERE, | 170 __FILE__, FROM_HERE, |
| 95 base::Bind(&TraceSubscriberStdioImpl::OnEnd, impl_)); | 171 base::Bind(&TraceSubscriberStdioWorker::OnTraceEnd, worker_)); |
| 96 } | 172 } |
| 97 | 173 |
| 98 void TraceSubscriberStdio::OnTraceDataCollected( | 174 void TraceSubscriberStdio::OnTraceDataCollected( |
| 99 const scoped_refptr<base::RefCountedString>& data_ptr) { | 175 const scoped_refptr<base::RefCountedString>& data_ptr) { |
| 100 BrowserThread::PostBlockingPoolSequencedTask( | 176 BrowserThread::PostBlockingPoolSequencedTask( |
| 101 __FILE__, FROM_HERE, | 177 __FILE__, FROM_HERE, |
| 102 base::Bind(&TraceSubscriberStdioImpl::OnData, impl_, data_ptr)); | 178 base::Bind(&TraceSubscriberStdioWorker::OnTraceData, worker_, data_ptr)); |
| 179 } | |
| 180 | |
| 181 void TraceSubscriberStdio::OnEndSystemTracing( | |
| 182 const scoped_refptr<base::RefCountedString>& events_str_ptr) { | |
| 183 BrowserThread::PostBlockingPoolSequencedTask( | |
| 184 __FILE__, FROM_HERE, | |
| 185 base::Bind(&TraceSubscriberStdioWorker::OnSystemTraceData, | |
| 186 worker_, | |
| 187 events_str_ptr)); | |
| 103 } | 188 } |
| 104 | 189 |
| 105 } // namespace content | 190 } // namespace content |
| OLD | NEW |