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

Unified Diff: content/browser/browser_main_runner.cc

Issue 23691025: Adding shutdown tracing capabilities (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 4 months 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 side-by-side diff with in-line comments
Download patch
Index: content/browser/browser_main_runner.cc
diff --git a/content/browser/browser_main_runner.cc b/content/browser/browser_main_runner.cc
index f97318a690657892c4676b1b1d454f9dd75f8a1b..5a0b0a1f5db76d1bb9bac20eaa48409b0788e725 100644
--- a/content/browser/browser_main_runner.cc
+++ b/content/browser/browser_main_runner.cc
@@ -8,6 +8,9 @@
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/debug/trace_event.h"
+#include "base/debug/trace_event_impl.h"
+#include "base/file_util.h"
+#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/metrics/statistics_recorder.h"
@@ -25,6 +28,124 @@
bool g_exited_main_message_loop = false;
+namespace {
+
+// This class is intended to initiate tracing of the shutdown procedure as well
+// as dumping the resulting traces to a file before the browser process exits.
+// It will save the file either into the command line passed
+// "--trace-shutdown-file=<name>" parameter - or - to "chrometrace.log".
+// Use the class with a scoped_ptr to automatically write the dump when the
+// object gets destroyed.
+// Note that we cannot use the asynchronous file writer since the
+// |SequencedWorkerPool| will get killed in the shutdown process.
+class BrowserShutdownProfilerAndDumper {
James Cook 2013/08/30 22:54:02 I think this class is big enough to go in a separa
Mr4D (OOO till 08-26) 2013/08/31 02:03:44 Done.
+ public:
+ BrowserShutdownProfilerAndDumper() : blocks_(0), dump_file_(0) {
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ base::debug::CategoryFilter category_filter(
+ command_line.GetSwitchValueASCII(switches::kTraceShutdown));
+ base::debug::TraceLog::GetInstance()->SetEnabled(
+ category_filter,
+ base::debug::TraceLog::RECORD_UNTIL_FULL);
+ }
+
+ virtual ~BrowserShutdownProfilerAndDumper() {
+ WriteTracesToDisc(GetFileName());
+ }
+
+ private:
+ // Writes all traces which happened to disc.
+ void WriteTracesToDisc(base::FilePath file_name) {
+ LOG(ERROR) << "Flushing shutdown traces to disc. The buffer is %" <<
James Cook 2013/08/30 22:54:02 Could this be a VLOG? Or is this slow enough that
Mr4D (OOO till 08-26) 2013/08/31 02:03:44 I did never run VLOG yet, but since you asked for
+ base::debug::TraceLog::GetInstance()->GetBufferPercentFull() <<
+ " full.";
+ DCHECK(!dump_file_);
+ dump_file_ = file_util::OpenFile(file_name, "w+");
+ if (!IsFileValid()) {
+ LOG(ERROR) << "Failed to open performance trace file: " <<
+ file_name.value();
+ return;
+ }
+ WriteString("{\"traceEvents\":");
+ WriteString("[");
+
+ base::debug::TraceLog::GetInstance()->Flush(
+ base::Bind(&BrowserShutdownProfilerAndDumper::WriteTraceDataCollected,
+ base::Unretained(this)));
+
+ WriteString("]");
+ WriteString("}");
+ CloseFile();
+ }
+
+ // Returns the file name where we should save the trace dump to.
+ base::FilePath GetFileName() {
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ base::FilePath trace_file =
+ command_line.GetSwitchValuePath(switches::kTraceShutdownFile);
+
+ if (!trace_file.empty())
+ return trace_file;
+
+ // Default to saving the startup trace into the current dir.
+ return base::FilePath().AppendASCII("chrometrace.log");
James Cook 2013/08/30 22:54:02 FYI - We usually use the suffix ".json" for trace
Mr4D (OOO till 08-26) 2013/08/31 02:03:44 I used the same default name as for the startup ca
+ }
+
+ // The callback for the |TraceLog::Flush| function. It saves all traces to
+ // disc.
+ void WriteTraceDataCollected(
+ const scoped_refptr<base::RefCountedString>& events_str) {
+ if (!IsFileValid())
+ return;
+ if (blocks_) {
+ // Blocks are not comma separated. Beginning with the second block we
+ // start therefore to add one in front of the previous block.
+ WriteString(",");
+ }
+ blocks_++;
+ WriteString(events_str->data());
+ }
+
+ // Returns true if the dump file is valid.
+ bool IsFileValid() {
+ return dump_file_ && (0 == ferror(dump_file_));
James Cook 2013/08/30 22:54:02 ferror(dump_file_) == 0
Mr4D (OOO till 08-26) 2013/08/31 02:03:44 Done.
+ }
+
+ // Writes a string to the dump file.
+ void WriteString(const std::string& string) {
+ WriteChars(string.data(), string.size());
+
James Cook 2013/08/30 22:54:02 no blank line
Mr4D (OOO till 08-26) 2013/08/31 02:03:44 Done.
+ }
+
+ // Write a buffer to the dump file.
+ void WriteChars(const char* chars, size_t size) {
+ if (!IsFileValid())
+ return;
+
+ size_t written = fwrite(chars, 1, size, dump_file_);
+ if (written != size) {
+ LOG(ERROR) << "Error " << ferror(dump_file_) <<
+ " in fwrite() to trace file";
+ CloseFile();
+ }
+ }
+
+ // Closes the dump file.
+ void CloseFile() {
+ if (!IsFileValid())
+ return;
+ fclose(dump_file_);
James Cook 2013/08/30 22:54:02 Use file_util::CloseFile()
Mr4D (OOO till 08-26) 2013/08/31 02:03:44 Done.
+ dump_file_ = 0;
+ }
+
+ // The number of blocks we have already written.
+ int blocks_;
+ // For dumping the content to disc.
+ FILE* dump_file_;
+};
+
+}
+
namespace content {
class BrowserMainRunnerImpl : public BrowserMainRunner {
@@ -122,22 +243,32 @@ class BrowserMainRunnerImpl : public BrowserMainRunner {
}
virtual void Shutdown() OVERRIDE {
- DCHECK(initialization_started_);
- DCHECK(!is_shutdown_);
- g_exited_main_message_loop = true;
-
- main_loop_->ShutdownThreadsAndCleanUp();
-
- ui::ShutdownInputMethod();
-#if defined(OS_WIN)
- ole_initializer_.reset(NULL);
-#endif
-
- main_loop_.reset(NULL);
-
- notification_service_.reset(NULL);
-
- is_shutdown_ = true;
+ // Enable shutdown tracing automatically upon shutdown if requested.
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ // When the object gets destroyed the traces will get written to disc.
+ scoped_ptr<BrowserShutdownProfilerAndDumper> profiler;
+ if (command_line.HasSwitch(switches::kTraceShutdown))
+ profiler.reset(new BrowserShutdownProfilerAndDumper());
+ {
James Cook 2013/08/30 22:54:02 Put a blank line above this, or move the comment f
Mr4D (OOO till 08-26) 2013/08/31 02:03:44 Did that already in the following patch. Done.
+ // The trace event has to stay between profiler creation and destruction.
+ TRACE_EVENT0("shutdown", "BrowserMainRunner");
+ DCHECK(initialization_started_);
+ DCHECK(!is_shutdown_);
+ g_exited_main_message_loop = true;
+
+ main_loop_->ShutdownThreadsAndCleanUp();
+
+ ui::ShutdownInputMethod();
+ #if defined(OS_WIN)
+ ole_initializer_.reset(NULL);
+ #endif
+
+ main_loop_.reset(NULL);
+
+ notification_service_.reset(NULL);
+
+ is_shutdown_ = true;
+ }
}
protected:

Powered by Google App Engine
This is Rietveld 408576698