158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// found in the LICENSE file. 458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "content/browser/browser_shutdown_profile_dumper.h" 658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/base_switches.h" 858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/command_line.h" 958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/debug/trace_event.h" 1058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/debug/trace_event_impl.h" 1158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/file_util.h" 1258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/files/file_path.h" 1358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/logging.h" 14d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "base/synchronization/waitable_event.h" 15d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "base/threading/thread.h" 16d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "base/threading/thread_restrictions.h" 1758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "content/public/common/content_switches.h" 1858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 1958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)namespace content { 2058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 2158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)BrowserShutdownProfileDumper::BrowserShutdownProfileDumper() 2258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) : blocks_(0), 2358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) dump_file_(NULL) { 2458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 2558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 2658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)BrowserShutdownProfileDumper::~BrowserShutdownProfileDumper() { 2758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) WriteTracesToDisc(GetFileName()); 2858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 2958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 3058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void BrowserShutdownProfileDumper::WriteTracesToDisc( 3158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const base::FilePath& file_name) { 3258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Note: I have seen a usage of 0.000xx% when dumping - which fits easily. 3358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Since the tracer stops when the trace buffer is filled, we'd rather save 3458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // what we have than nothing since we might see from the amount of events 3558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // that caused the problem. 3658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DVLOG(1) << "Flushing shutdown traces to disc. The buffer is %" << 3758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::debug::TraceLog::GetInstance()->GetBufferPercentFull() << 3858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) " full."; 3958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(!dump_file_); 40a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) dump_file_ = base::OpenFile(file_name, "w+"); 4158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!IsFileValid()) { 4258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) LOG(ERROR) << "Failed to open performance trace file: " << 4358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) file_name.value(); 4458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return; 4558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 4658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) WriteString("{\"traceEvents\":"); 4758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) WriteString("["); 4858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 49d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // TraceLog::Flush() requires the calling thread to have a message loop. 50d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // As the message loop of the current thread may have quit, start another 51d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // thread for flushing the trace. 52d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) base::WaitableEvent flush_complete_event(false, false); 53d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) base::Thread flush_thread("browser_shutdown_trace_event_flush"); 54d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) flush_thread.Start(); 55d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) flush_thread.message_loop()->PostTask( 56d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) FROM_HERE, 57d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) base::Bind(&BrowserShutdownProfileDumper::EndTraceAndFlush, 58d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) base::Unretained(this), 59d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) base::Unretained(&flush_complete_event))); 60d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 61d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) bool original_wait_allowed = base::ThreadRestrictions::SetWaitAllowed(true); 62d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) flush_complete_event.Wait(); 63d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) base::ThreadRestrictions::SetWaitAllowed(original_wait_allowed); 64d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 65d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 66d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void BrowserShutdownProfileDumper::EndTraceAndFlush( 67d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) base::WaitableEvent* flush_complete_event) { 68f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::debug::TraceLog::GetInstance()->SetDisabled(); 6958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::debug::TraceLog::GetInstance()->Flush( 7058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::Bind(&BrowserShutdownProfileDumper::WriteTraceDataCollected, 71d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) base::Unretained(this), 72d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) base::Unretained(flush_complete_event))); 7358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 7458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 7558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)base::FilePath BrowserShutdownProfileDumper::GetFileName() { 7658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 7758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::FilePath trace_file = 7858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) command_line.GetSwitchValuePath(switches::kTraceShutdownFile); 7958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 8058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!trace_file.empty()) 8158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return trace_file; 8258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 8358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Default to saving the startup trace into the current dir. 8458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return base::FilePath().AppendASCII("chrometrace.log"); 8558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 8658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 8758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void BrowserShutdownProfileDumper::WriteTraceDataCollected( 88d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) base::WaitableEvent* flush_complete_event, 8958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const scoped_refptr<base::RefCountedString>& events_str, 9058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) bool has_more_events) { 91d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (!IsFileValid()) { 92d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) flush_complete_event->Signal(); 9358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return; 94d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 9558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (blocks_) { 9658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Blocks are not comma separated. Beginning with the second block we 9758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // start therefore to add one in front of the previous block. 9858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) WriteString(","); 9958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 10058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) ++blocks_; 10158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) WriteString(events_str->data()); 10258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 10358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!has_more_events) { 10458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) WriteString("]"); 10558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) WriteString("}"); 10658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) CloseFile(); 107d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) flush_complete_event->Signal(); 10858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 10958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 11058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 11158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool BrowserShutdownProfileDumper::IsFileValid() { 11258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return dump_file_ && (ferror(dump_file_) == 0); 11358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 11458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 11558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void BrowserShutdownProfileDumper::WriteString(const std::string& string) { 11658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) WriteChars(string.data(), string.size()); 11758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 11858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 11958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void BrowserShutdownProfileDumper::WriteChars(const char* chars, size_t size) { 12058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!IsFileValid()) 12158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return; 12258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 12358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) size_t written = fwrite(chars, 1, size, dump_file_); 12458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (written != size) { 12558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) LOG(ERROR) << "Error " << ferror(dump_file_) << 12658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) " in fwrite() to trace file"; 12758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) CloseFile(); 12858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 12958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 13058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 13158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void BrowserShutdownProfileDumper::CloseFile() { 13258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!dump_file_) 13358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return; 134a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::CloseFile(dump_file_); 13558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) dump_file_ = NULL; 13658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 13758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 13858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} // namespace content 139