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

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

Issue 66893003: Allow TracingController to output trace data to specified file (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Removed unnecessary include Created 7 years, 1 month 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 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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/tracing_controller_impl.h" 5 #include "content/browser/tracing/tracing_controller_impl.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/file_util.h" 8 #include "base/file_util.h"
9 #include "base/json/string_escape.h" 9 #include "base/json/string_escape.h"
10 #include "base/strings/string_number_conversions.h" 10 #include "base/strings/string_number_conversions.h"
(...skipping 10 matching lines...) Expand all
21 21
22 base::LazyInstance<TracingControllerImpl>::Leaky g_controller = 22 base::LazyInstance<TracingControllerImpl>::Leaky g_controller =
23 LAZY_INSTANCE_INITIALIZER; 23 LAZY_INSTANCE_INITIALIZER;
24 24
25 } // namespace 25 } // namespace
26 26
27 TracingController* TracingController::GetInstance() { 27 TracingController* TracingController::GetInstance() {
28 return TracingControllerImpl::GetInstance(); 28 return TracingControllerImpl::GetInstance();
29 } 29 }
30 30
31 class TracingControllerImpl::ResultFile {
32 public:
33 explicit ResultFile(const base::FilePath& path);
34 void Write(const scoped_refptr<base::RefCountedString>& events_str_ptr) {
35 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
36 base::Bind(&TracingControllerImpl::ResultFile::WriteTask,
37 base::Unretained(this), events_str_ptr));
38 }
39 void Close(const base::Closure& callback) {
40 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
41 base::Bind(&TracingControllerImpl::ResultFile::CloseTask,
42 base::Unretained(this), callback));
43 }
44 const base::FilePath& path() const { return path_; }
45
46 private:
47 void OpenTask();
48 void WriteTask(const scoped_refptr<base::RefCountedString>& events_str_ptr);
49 void CloseTask(const base::Closure& callback);
50
51 FILE* file_;
52 base::FilePath path_;
53 bool has_at_least_one_result_;
54
55 DISALLOW_COPY_AND_ASSIGN(ResultFile);
56 };
57
58 TracingControllerImpl::ResultFile::ResultFile(const base::FilePath& path)
59 : file_(NULL),
60 path_(path),
61 has_at_least_one_result_(false) {
62 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
63 base::Bind(&TracingControllerImpl::ResultFile::OpenTask,
64 base::Unretained(this)));
65 }
66
67 void TracingControllerImpl::ResultFile::OpenTask() {
68 if (path_.empty())
69 file_util::CreateTemporaryFile(&path_);
70 file_ = file_util::OpenFile(path_, "w");
71 if (!file_) {
72 LOG(ERROR) << "Failed to open " << path_.value();
73 return;
74 }
75 const char* preamble = "{\"traceEvents\": [";
76 size_t written = fwrite(preamble, strlen(preamble), 1, file_);
77 DCHECK(written == 1);
78 }
79
80 void TracingControllerImpl::ResultFile::WriteTask(
81 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
82 if (!file_)
83 return;
84
85 // If there is already a result in the file, then put a commma
86 // before the next batch of results.
87 if (has_at_least_one_result_)
88 fwrite(",", 1, 1, file_);
89 has_at_least_one_result_ = true;
90 size_t written = fwrite(events_str_ptr->data().c_str(),
91 events_str_ptr->data().size(), 1,
92 file_);
93 DCHECK(written == 1);
94 }
95
96 void TracingControllerImpl::ResultFile::CloseTask(
97 const base::Closure& callback) {
98 if (!file_)
99 return;
100
101 const char* trailout = "]}";
102 size_t written = fwrite(trailout, strlen(trailout), 1, file_);
103 DCHECK(written == 1);
104 file_util::CloseFile(file_);
105 file_ = NULL;
106
107 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
108 }
109
110
31 TracingControllerImpl::TracingControllerImpl() : 111 TracingControllerImpl::TracingControllerImpl() :
32 pending_disable_recording_ack_count_(0), 112 pending_disable_recording_ack_count_(0),
33 pending_capture_monitoring_snapshot_ack_count_(0), 113 pending_capture_monitoring_snapshot_ack_count_(0),
34 is_recording_(false), 114 is_recording_(false),
35 is_monitoring_(false), 115 is_monitoring_(false),
116 trace_options_(TraceLog::RECORD_UNTIL_FULL),
36 category_filter_( 117 category_filter_(
37 base::debug::CategoryFilter::kDefaultCategoryFilterString), 118 base::debug::CategoryFilter::kDefaultCategoryFilterString) {
38 result_file_(0),
39 result_file_has_at_least_one_result_(false) {
40 } 119 }
41 120
42 TracingControllerImpl::~TracingControllerImpl() { 121 TracingControllerImpl::~TracingControllerImpl() {
43 // This is a Leaky instance. 122 // This is a Leaky instance.
44 NOTREACHED(); 123 NOTREACHED();
45 } 124 }
46 125
47 TracingControllerImpl* TracingControllerImpl::GetInstance() { 126 TracingControllerImpl* TracingControllerImpl::GetInstance() {
48 return g_controller.Pointer(); 127 return g_controller.Pointer();
49 } 128 }
50 129
51 void TracingControllerImpl::GetCategories( 130 void TracingControllerImpl::GetCategories(
52 const GetCategoriesDoneCallback& callback) { 131 const GetCategoriesDoneCallback& callback) {
53 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 132 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
54 133
55 // Known categories come back from child processes with the EndTracingAck 134 // Known categories come back from child processes with the EndTracingAck
56 // message. So to get known categories, just begin and end tracing immediately 135 // message. So to get known categories, just begin and end tracing immediately
57 // afterwards. This will ping all the child processes for categories. 136 // afterwards. This will ping all the child processes for categories.
58 pending_get_categories_done_callback_ = callback; 137 pending_get_categories_done_callback_ = callback;
59 EnableRecording(base::debug::CategoryFilter("*"), 138 EnableRecording(base::debug::CategoryFilter("*"),
60 TracingController::Options(), 139 TracingController::Options(),
61 EnableRecordingDoneCallback()); 140 EnableRecordingDoneCallback());
62 DisableRecording(TracingFileResultCallback()); 141 DisableRecording(base::FilePath(), TracingFileResultCallback());
63 } 142 }
64 143
65 bool TracingControllerImpl::EnableRecording( 144 bool TracingControllerImpl::EnableRecording(
66 const base::debug::CategoryFilter& filter, 145 const base::debug::CategoryFilter& filter,
67 TracingController::Options options, 146 TracingController::Options options,
68 const EnableRecordingDoneCallback& callback) { 147 const EnableRecordingDoneCallback& callback) {
69 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
70 149
71 if (!can_enable_recording()) 150 if (!can_enable_recording())
72 return false; 151 return false;
(...skipping 14 matching lines...) Expand all
87 it->get()->SendBeginTracing( 166 it->get()->SendBeginTracing(
88 category_filter_.ToString(), trace_options_, false); 167 category_filter_.ToString(), trace_options_, false);
89 } 168 }
90 169
91 if (!callback.is_null()) 170 if (!callback.is_null())
92 callback.Run(); 171 callback.Run();
93 return true; 172 return true;
94 } 173 }
95 174
96 bool TracingControllerImpl::DisableRecording( 175 bool TracingControllerImpl::DisableRecording(
176 const base::FilePath& result_file_path,
97 const TracingFileResultCallback& callback) { 177 const TracingFileResultCallback& callback) {
98 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 178 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
99 179
100 if (!can_disable_recording()) 180 if (!can_disable_recording())
101 return false; 181 return false;
102 182
103 pending_disable_recording_done_callback_ = callback; 183 pending_disable_recording_done_callback_ = callback;
104 184
105 // Disable local trace early to avoid traces during end-tracing process from 185 // Disable local trace early to avoid traces during end-tracing process from
106 // interfering with the process. 186 // interfering with the process.
107 TraceLog::GetInstance()->SetDisabled(); 187 TraceLog::GetInstance()->SetDisabled();
108 188
109 #if defined(OS_ANDROID) 189 #if defined(OS_ANDROID)
110 if (pending_get_categories_done_callback_.is_null()) 190 if (pending_get_categories_done_callback_.is_null())
111 TraceLog::GetInstance()->AddClockSyncMetadataEvent(); 191 TraceLog::GetInstance()->AddClockSyncMetadataEvent();
112 #endif 192 #endif
113 193
114 // We don't need to create a temporary file when getting categories. 194 if (!callback.is_null() || !result_file_path.empty())
115 if (pending_get_categories_done_callback_.is_null()) { 195 result_file_.reset(new ResultFile(result_file_path));
116 base::FilePath temporary_file;
117 file_util::CreateTemporaryFile(&temporary_file);
118 result_file_path_.reset(new base::FilePath(temporary_file));
119 result_file_ = file_util::OpenFile(*result_file_path_, "w");
120 result_file_has_at_least_one_result_ = false;
121 const char* preamble = "{\"traceEvents\": [";
122 size_t written = fwrite(preamble, strlen(preamble), 1, result_file_);
123 DCHECK(written == 1);
124 }
125 196
126 // There could be a case where there are no child processes and filters_ 197 // There could be a case where there are no child processes and filters_
127 // is empty. In that case we can immediately tell the subscriber that tracing 198 // is empty. In that case we can immediately tell the subscriber that tracing
128 // has ended. To avoid recursive calls back to the subscriber, we will just 199 // has ended. To avoid recursive calls back to the subscriber, we will just
129 // use the existing asynchronous OnDisableRecordingAcked code. 200 // use the existing asynchronous OnDisableRecordingAcked code.
130 // Count myself (local trace) in pending_disable_recording_ack_count_, 201 // Count myself (local trace) in pending_disable_recording_ack_count_,
131 // acked below. 202 // acked below.
132 pending_disable_recording_ack_count_ = filters_.size() + 1; 203 pending_disable_recording_ack_count_ = filters_.size() + 1;
133 204
134 // Handle special case of zero child processes. 205 // Handle special case of zero child processes.
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
196 } 267 }
197 268
198 void TracingControllerImpl::GetMonitoringStatus( 269 void TracingControllerImpl::GetMonitoringStatus(
199 bool* out_enabled, 270 bool* out_enabled,
200 base::debug::CategoryFilter* out_filter, 271 base::debug::CategoryFilter* out_filter,
201 TracingController::Options* out_options) { 272 TracingController::Options* out_options) {
202 NOTIMPLEMENTED(); 273 NOTIMPLEMENTED();
203 } 274 }
204 275
205 void TracingControllerImpl::CaptureMonitoringSnapshot( 276 void TracingControllerImpl::CaptureMonitoringSnapshot(
277 const base::FilePath& result_file_path,
206 const TracingFileResultCallback& callback) { 278 const TracingFileResultCallback& callback) {
207 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 279 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
208 280
209 if (!can_disable_monitoring()) 281 if (!can_disable_monitoring())
210 return; 282 return;
211 283
212 pending_capture_monitoring_snapshot_done_callback_ = callback; 284 pending_capture_monitoring_snapshot_done_callback_ = callback;
213 285
214 base::FilePath temporary_file; 286 if (!callback.is_null() || !result_file_path.empty())
215 file_util::CreateTemporaryFile(&temporary_file); 287 monitoring_snapshot_file_.reset(new ResultFile(result_file_path));
216 result_file_path_.reset(new base::FilePath(temporary_file));
217 result_file_ = file_util::OpenFile(*result_file_path_, "w");
218 result_file_has_at_least_one_result_ = false;
219 const char* preamble = "{\"traceEvents\": [";
220 size_t written = fwrite(preamble, strlen(preamble), 1, result_file_);
221 DCHECK(written == 1);
222 288
223 // There could be a case where there are no child processes and filters_ 289 // There could be a case where there are no child processes and filters_
224 // is empty. In that case we can immediately tell the subscriber that tracing 290 // is empty. In that case we can immediately tell the subscriber that tracing
225 // has ended. To avoid recursive calls back to the subscriber, we will just 291 // has ended. To avoid recursive calls back to the subscriber, we will just
226 // use the existing asynchronous OnCaptureMonitoringSnapshotAcked code. 292 // use the existing asynchronous OnCaptureMonitoringSnapshotAcked code.
227 // Count myself in pending_capture_monitoring_snapshot_ack_count_, 293 // Count myself in pending_capture_monitoring_snapshot_ack_count_,
228 // acked below. 294 // acked below.
229 pending_capture_monitoring_snapshot_ack_count_ = filters_.size() + 1; 295 pending_capture_monitoring_snapshot_ack_count_ = filters_.size() + 1;
230 296
231 // Handle special case of zero child processes. 297 // Handle special case of zero child processes.
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
301 return; 367 return;
302 368
303 // All acks (including from the subprocesses and the local trace) have been 369 // All acks (including from the subprocesses and the local trace) have been
304 // received. 370 // received.
305 is_recording_ = false; 371 is_recording_ = false;
306 372
307 // Trigger callback if one is set. 373 // Trigger callback if one is set.
308 if (!pending_get_categories_done_callback_.is_null()) { 374 if (!pending_get_categories_done_callback_.is_null()) {
309 pending_get_categories_done_callback_.Run(known_category_groups_); 375 pending_get_categories_done_callback_.Run(known_category_groups_);
310 pending_get_categories_done_callback_.Reset(); 376 pending_get_categories_done_callback_.Reset();
311 } else if (!pending_disable_recording_done_callback_.is_null()) { 377 } else if (result_file_) {
312 const char* trailout = "]}"; 378 result_file_->Close(
313 size_t written = fwrite(trailout, strlen(trailout), 1, result_file_); 379 base::Bind(&TracingControllerImpl::OnResultFileClosed,
314 DCHECK(written == 1); 380 base::Unretained(this)));
315 file_util::CloseFile(result_file_);
316 result_file_ = 0;
317 pending_disable_recording_done_callback_.Run(result_file_path_.Pass());
318 pending_disable_recording_done_callback_.Reset();
319 } 381 }
320 } 382 }
321 383
384 void TracingControllerImpl::OnResultFileClosed() {
385 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
386
387 if (!result_file_)
388 return;
389
390 if (!pending_disable_recording_done_callback_.is_null()) {
391 pending_disable_recording_done_callback_.Run(result_file_->path());
392 pending_disable_recording_done_callback_.Reset();
393 }
394 result_file_.reset();
395 }
396
322 void TracingControllerImpl::OnCaptureMonitoringSnapshotAcked() { 397 void TracingControllerImpl::OnCaptureMonitoringSnapshotAcked() {
323 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 398 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
324 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 399 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
325 base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked, 400 base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked,
326 base::Unretained(this))); 401 base::Unretained(this)));
327 return; 402 return;
328 } 403 }
329 404
330 if (pending_capture_monitoring_snapshot_ack_count_ == 0) 405 if (pending_capture_monitoring_snapshot_ack_count_ == 0)
331 return; 406 return;
332 407
333 if (--pending_capture_monitoring_snapshot_ack_count_ == 1) { 408 if (--pending_capture_monitoring_snapshot_ack_count_ == 1) {
334 // All acks from subprocesses have been received. Now flush the local trace. 409 // All acks from subprocesses have been received. Now flush the local trace.
335 // During or after this call, our OnLocalMonitoringTraceDataCollected 410 // During or after this call, our OnLocalMonitoringTraceDataCollected
336 // will be called with the last of the local trace data. 411 // will be called with the last of the local trace data.
337 TraceLog::GetInstance()->FlushButLeaveBufferIntact( 412 TraceLog::GetInstance()->FlushButLeaveBufferIntact(
338 base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected, 413 base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected,
339 base::Unretained(this))); 414 base::Unretained(this)));
340 } 415 }
341 416
342 if (pending_capture_monitoring_snapshot_ack_count_ != 0) 417 if (pending_capture_monitoring_snapshot_ack_count_ != 0)
343 return; 418 return;
344 419
345 if (!pending_capture_monitoring_snapshot_done_callback_.is_null()) { 420 if (monitoring_snapshot_file_) {
346 const char* trailout = "]}"; 421 monitoring_snapshot_file_->Close(
347 size_t written = fwrite(trailout, strlen(trailout), 1, result_file_); 422 base::Bind(&TracingControllerImpl::OnMonitoringSnapshotFileClosed,
348 DCHECK(written == 1); 423 base::Unretained(this)));
349 file_util::CloseFile(result_file_);
350 result_file_ = 0;
351 pending_capture_monitoring_snapshot_done_callback_.Run(
352 result_file_path_.Pass());
353 pending_capture_monitoring_snapshot_done_callback_.Reset();
354 } 424 }
355 } 425 }
356 426
427 void TracingControllerImpl::OnMonitoringSnapshotFileClosed() {
428 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
429
430 if (!monitoring_snapshot_file_)
431 return;
432
433 if (!pending_capture_monitoring_snapshot_done_callback_.is_null()) {
434 pending_capture_monitoring_snapshot_done_callback_.Run(
435 monitoring_snapshot_file_->path());
436 pending_capture_monitoring_snapshot_done_callback_.Reset();
437 }
438 monitoring_snapshot_file_.reset();
439 }
440
357 void TracingControllerImpl::OnTraceDataCollected( 441 void TracingControllerImpl::OnTraceDataCollected(
358 const scoped_refptr<base::RefCountedString>& events_str_ptr) { 442 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
359 // OnTraceDataCollected may be called from any browser thread, either by the 443 // OnTraceDataCollected may be called from any browser thread, either by the
360 // local event trace system or from child processes via TraceMessageFilter. 444 // local event trace system or from child processes via TraceMessageFilter.
361 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 445 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
362 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 446 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
363 base::Bind(&TracingControllerImpl::OnTraceDataCollected, 447 base::Bind(&TracingControllerImpl::OnTraceDataCollected,
364 base::Unretained(this), events_str_ptr)); 448 base::Unretained(this), events_str_ptr));
365 return; 449 return;
366 } 450 }
367 451
368 // Drop trace events if we are just getting categories. 452 if (result_file_)
369 if (!pending_get_categories_done_callback_.is_null()) 453 result_file_->Write(events_str_ptr);
454 }
455
456 void TracingControllerImpl::OnMonitoringTraceDataCollected(
457 const scoped_refptr<base::RefCountedString>& events_str_ptr) {
458 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
459 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
460 base::Bind(&TracingControllerImpl::OnMonitoringTraceDataCollected,
461 base::Unretained(this), events_str_ptr));
370 return; 462 return;
463 }
371 464
372 // If there is already a result in the file, then put a commma 465 if (!monitoring_snapshot_file_)
373 // before the next batch of results. 466 monitoring_snapshot_file_->Write(events_str_ptr);
374 if (result_file_has_at_least_one_result_) {
375 size_t written = fwrite(",", 1, 1, result_file_);
376 DCHECK(written == 1);
377 } else {
378 result_file_has_at_least_one_result_ = true;
379 }
380 size_t written = fwrite(events_str_ptr->data().c_str(),
381 events_str_ptr->data().size(), 1,
382 result_file_);
383 DCHECK(written == 1);
384 } 467 }
385 468
386 void TracingControllerImpl::OnLocalTraceDataCollected( 469 void TracingControllerImpl::OnLocalTraceDataCollected(
387 const scoped_refptr<base::RefCountedString>& events_str_ptr, 470 const scoped_refptr<base::RefCountedString>& events_str_ptr,
388 bool has_more_events) { 471 bool has_more_events) {
389 if (events_str_ptr->data().size()) 472 if (events_str_ptr->data().size())
390 OnTraceDataCollected(events_str_ptr); 473 OnTraceDataCollected(events_str_ptr);
391 474
392 if (has_more_events) 475 if (has_more_events)
393 return; 476 return;
394 477
395 // Simulate an DisableRecordingAcked for the local trace. 478 // Simulate an DisableRecordingAcked for the local trace.
396 std::vector<std::string> category_groups; 479 std::vector<std::string> category_groups;
397 TraceLog::GetInstance()->GetKnownCategoryGroups(&category_groups); 480 TraceLog::GetInstance()->GetKnownCategoryGroups(&category_groups);
398 OnDisableRecordingAcked(category_groups); 481 OnDisableRecordingAcked(category_groups);
399 } 482 }
400 483
401 void TracingControllerImpl::OnLocalMonitoringTraceDataCollected( 484 void TracingControllerImpl::OnLocalMonitoringTraceDataCollected(
402 const scoped_refptr<base::RefCountedString>& events_str_ptr, 485 const scoped_refptr<base::RefCountedString>& events_str_ptr,
403 bool has_more_events) { 486 bool has_more_events) {
404 if (events_str_ptr->data().size()) 487 if (events_str_ptr->data().size())
405 OnTraceDataCollected(events_str_ptr); 488 OnMonitoringTraceDataCollected(events_str_ptr);
406 489
407 if (has_more_events) 490 if (has_more_events)
408 return; 491 return;
409 492
410 // Simulate an CaptureMonitoringSnapshotAcked for the local trace. 493 // Simulate an CaptureMonitoringSnapshotAcked for the local trace.
411 OnCaptureMonitoringSnapshotAcked(); 494 OnCaptureMonitoringSnapshotAcked();
412 } 495 }
413 496
414 } // namespace content 497 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/tracing/tracing_controller_impl.h ('k') | content/public/browser/tracing_controller.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698