| 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 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 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 |