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 TraceSubscriberStdioImpl 18 : public base::RefCountedThreadSafe<TraceSubscriberStdioImpl> { 19 public: 20 explicit TraceSubscriberStdioImpl(const base::FilePath& path) 21 : path_(path), 22 file_(0) {} 23 24 void OnStart() { 25 DCHECK(!file_); 26 trace_buffer_.SetOutputCallback( 27 base::Bind(&TraceSubscriberStdioImpl::Write, this)); 28 file_ = file_util::OpenFile(path_, "w+"); 29 if (IsValid()) { 30 LOG(INFO) << "Logging performance trace to file: " << path_.value(); 31 trace_buffer_.Start(); 32 } else { 33 LOG(ERROR) << "Failed to open performance trace file: " << path_.value(); 34 } 35 } 36 37 void OnData(const scoped_refptr<base::RefCountedString>& data_ptr) { 38 trace_buffer_.AddFragment(data_ptr->data()); 39 } 40 41 void OnEnd() { 42 trace_buffer_.Finish(); 43 CloseFile(); 44 } 45 46 private: 47 friend class base::RefCountedThreadSafe<TraceSubscriberStdioImpl>; 48 49 ~TraceSubscriberStdioImpl() { 50 CloseFile(); 51 } 52 53 bool IsValid() const { 54 return file_ && (0 == ferror(file_)); 55 } 56 57 void CloseFile() { 58 if (file_) { 59 fclose(file_); 60 file_ = 0; 61 } 62 // This is important, as it breaks a reference cycle. 63 trace_buffer_.SetOutputCallback( 64 base::debug::TraceResultBuffer::OutputCallback()); 65 } 66 67 void Write(const std::string& output_str) { 68 if (IsValid()) { 69 size_t written = fwrite(output_str.data(), 1, output_str.size(), file_); 70 if (written != output_str.size()) { 71 LOG(ERROR) << "Error " << ferror(file_) << " in fwrite() to trace file"; 72 CloseFile(); 73 } 74 } 75 } 76 77 base::FilePath path_; 78 FILE* file_; 79 base::debug::TraceResultBuffer trace_buffer_; 80 }; 81 82 TraceSubscriberStdio::TraceSubscriberStdio(const base::FilePath& path) 83 : impl_(new TraceSubscriberStdioImpl(path)) { 84 BrowserThread::PostBlockingPoolSequencedTask( 85 __FILE__, FROM_HERE, 86 base::Bind(&TraceSubscriberStdioImpl::OnStart, impl_)); 87 } 88 89 TraceSubscriberStdio::~TraceSubscriberStdio() { 90 } 91 92 void TraceSubscriberStdio::OnEndTracingComplete() { 93 BrowserThread::PostBlockingPoolSequencedTask( 94 __FILE__, FROM_HERE, 95 base::Bind(&TraceSubscriberStdioImpl::OnEnd, impl_)); 96 } 97 98 void TraceSubscriberStdio::OnTraceDataCollected( 99 const scoped_refptr<base::RefCountedString>& data_ptr) { 100 BrowserThread::PostBlockingPoolSequencedTask( 101 __FILE__, FROM_HERE, 102 base::Bind(&TraceSubscriberStdioImpl::OnData, impl_, data_ptr)); 103 } 104 105 } // namespace content 106