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

Side by Side 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: Started the profiling in AttemptUserExit instead of BrowserMainRunner::Shutdown. Created 7 years, 3 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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/public/browser/browser_main_runner.h" 5 #include "content/public/browser/browser_main_runner.h"
6 6
7 #include "base/allocator/allocator_shim.h" 7 #include "base/allocator/allocator_shim.h"
8 #include "base/base_switches.h" 8 #include "base/base_switches.h"
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/debug/trace_event.h" 10 #include "base/debug/trace_event.h"
11 #include "base/debug/trace_event_impl.h"
12 #include "base/file_util.h"
13 #include "base/files/file_path.h"
11 #include "base/logging.h" 14 #include "base/logging.h"
12 #include "base/metrics/histogram.h" 15 #include "base/metrics/histogram.h"
13 #include "base/metrics/statistics_recorder.h" 16 #include "base/metrics/statistics_recorder.h"
14 #include "content/browser/browser_main_loop.h" 17 #include "content/browser/browser_main_loop.h"
15 #include "content/browser/notification_service_impl.h" 18 #include "content/browser/notification_service_impl.h"
16 #include "content/public/common/content_switches.h" 19 #include "content/public/common/content_switches.h"
17 #include "content/public/common/main_function_params.h" 20 #include "content/public/common/main_function_params.h"
18 #include "ui/base/ime/input_method_initializer.h" 21 #include "ui/base/ime/input_method_initializer.h"
19 22
20 #if defined(OS_WIN) 23 #if defined(OS_WIN)
21 #include "base/win/metro.h" 24 #include "base/win/metro.h"
22 #include "base/win/windows_version.h" 25 #include "base/win/windows_version.h"
23 #include "ui/base/win/scoped_ole_initializer.h" 26 #include "ui/base/win/scoped_ole_initializer.h"
24 #endif 27 #endif
25 28
26 bool g_exited_main_message_loop = false; 29 bool g_exited_main_message_loop = false;
27 30
31 namespace {
32
33 // This class is intended to dump the tracing results of the shutdown process
34 // to a file before the browser process exits.
35 // It will save the file either into the command line passed
36 // "--trace-shutdown-file=<name>" parameter - or - to "chrometrace.log".
37 // Use the class with a scoped_ptr to automatically write the dump when the
38 // object gets destroyed.
39 // Note that we cannot use the asynchronous file writer since the
40 // |SequencedWorkerPool| will get killed in the shutdown process.
41 class BrowserShutdownProfileDumper {
42 public:
43 BrowserShutdownProfileDumper() : blocks_(0), dump_file_(0) {
44 }
45
46 virtual ~BrowserShutdownProfileDumper() {
47 WriteTracesToDisc(GetFileName());
48 }
49
50 private:
51 // Writes all traces which happened to disc.
52 void WriteTracesToDisc(base::FilePath file_name) {
DaveMoore 2013/08/30 22:51:15 What happens if the trace buffer fills up before t
Mr4D (OOO till 08-26) 2013/08/31 02:03:44 As I understood it it will stop tracing when the b
53 LOG(ERROR) << "Flushing shutdown traces to disc. The buffer is %" <<
54 base::debug::TraceLog::GetInstance()->GetBufferPercentFull() <<
55 " full.";
56 DCHECK(!dump_file_);
57 dump_file_ = file_util::OpenFile(file_name, "w+");
58 if (!IsFileValid()) {
59 LOG(ERROR) << "Failed to open performance trace file: " <<
60 file_name.value();
61 return;
62 }
63 WriteString("{\"traceEvents\":");
64 WriteString("[");
65
66 base::debug::TraceLog::GetInstance()->Flush(
67 base::Bind(&BrowserShutdownProfileDumper::WriteTraceDataCollected,
68 base::Unretained(this)));
69
70 WriteString("]");
71 WriteString("}");
72 CloseFile();
73 }
74
75 // Returns the file name where we should save the trace dump to.
76 base::FilePath GetFileName() {
77 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
78 base::FilePath trace_file =
79 command_line.GetSwitchValuePath(switches::kTraceShutdownFile);
80
81 if (!trace_file.empty())
82 return trace_file;
83
84 // Default to saving the startup trace into the current dir.
85 return base::FilePath().AppendASCII("chrometrace.log");
86 }
87
88 // The callback for the |TraceLog::Flush| function. It saves all traces to
89 // disc.
90 void WriteTraceDataCollected(
91 const scoped_refptr<base::RefCountedString>& events_str) {
92 if (!IsFileValid())
93 return;
94 if (blocks_) {
95 // Blocks are not comma separated. Beginning with the second block we
96 // start therefore to add one in front of the previous block.
97 WriteString(",");
98 }
99 blocks_++;
100 WriteString(events_str->data());
101 }
102
103 // Returns true if the dump file is valid.
104 bool IsFileValid() {
105 return dump_file_ && (0 == ferror(dump_file_));
106 }
107
108 // Writes a string to the dump file.
109 void WriteString(const std::string& string) {
110 WriteChars(string.data(), string.size());
111
112 }
113
114 // Write a buffer to the dump file.
115 void WriteChars(const char* chars, size_t size) {
116 if (!IsFileValid())
117 return;
118
119 size_t written = fwrite(chars, 1, size, dump_file_);
120 if (written != size) {
121 LOG(ERROR) << "Error " << ferror(dump_file_) <<
122 " in fwrite() to trace file";
123 CloseFile();
124 }
125 }
126
127 // Closes the dump file.
128 void CloseFile() {
129 if (!IsFileValid())
130 return;
131 fclose(dump_file_);
132 dump_file_ = 0;
133 }
134
135 // The number of blocks we have already written.
136 int blocks_;
137 // For dumping the content to disc.
138 FILE* dump_file_;
139 };
140
141 }
142
28 namespace content { 143 namespace content {
29 144
30 class BrowserMainRunnerImpl : public BrowserMainRunner { 145 class BrowserMainRunnerImpl : public BrowserMainRunner {
31 public: 146 public:
32 BrowserMainRunnerImpl() 147 BrowserMainRunnerImpl()
33 : initialization_started_(false), is_shutdown_(false) {} 148 : initialization_started_(false), is_shutdown_(false) {}
34 149
35 virtual ~BrowserMainRunnerImpl() { 150 virtual ~BrowserMainRunnerImpl() {
36 if (initialization_started_ && !is_shutdown_) 151 if (initialization_started_ && !is_shutdown_)
37 Shutdown(); 152 Shutdown();
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
115 } 230 }
116 231
117 virtual int Run() OVERRIDE { 232 virtual int Run() OVERRIDE {
118 DCHECK(initialization_started_); 233 DCHECK(initialization_started_);
119 DCHECK(!is_shutdown_); 234 DCHECK(!is_shutdown_);
120 main_loop_->RunMainMessageLoopParts(); 235 main_loop_->RunMainMessageLoopParts();
121 return main_loop_->GetResultCode(); 236 return main_loop_->GetResultCode();
122 } 237 }
123 238
124 virtual void Shutdown() OVERRIDE { 239 virtual void Shutdown() OVERRIDE {
125 DCHECK(initialization_started_); 240 // The shutdown tracing got enabled in AttemptUserExit earlier, but someone
126 DCHECK(!is_shutdown_); 241 // needs to write the result to disc. For that a dumper needs to get created
127 g_exited_main_message_loop = true; 242 // which will dump the traces to disc when it gets destroyed.
243 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
244 scoped_ptr<BrowserShutdownProfileDumper> profiler;
245 if (command_line.HasSwitch(switches::kTraceShutdown))
246 profiler.reset(new BrowserShutdownProfileDumper());
128 247
129 main_loop_->ShutdownThreadsAndCleanUp(); 248 {
249 // The trace event has to stay between profiler creation and destruction.
250 TRACE_EVENT0("shutdown", "BrowserMainRunner");
251 DCHECK(initialization_started_);
252 DCHECK(!is_shutdown_);
253 g_exited_main_message_loop = true;
130 254
131 ui::ShutdownInputMethod(); 255 main_loop_->ShutdownThreadsAndCleanUp();
132 #if defined(OS_WIN)
133 ole_initializer_.reset(NULL);
134 #endif
135 256
136 main_loop_.reset(NULL); 257 ui::ShutdownInputMethod();
258 #if defined(OS_WIN)
259 ole_initializer_.reset(NULL);
260 #endif
137 261
138 notification_service_.reset(NULL); 262 main_loop_.reset(NULL);
139 263
140 is_shutdown_ = true; 264 notification_service_.reset(NULL);
265
266 is_shutdown_ = true;
267 }
141 } 268 }
142 269
143 protected: 270 protected:
144 // True if we have started to initialize the runner. 271 // True if we have started to initialize the runner.
145 bool initialization_started_; 272 bool initialization_started_;
146 273
147 // True if the runner has been shut down. 274 // True if the runner has been shut down.
148 bool is_shutdown_; 275 bool is_shutdown_;
149 276
150 scoped_ptr<NotificationServiceImpl> notification_service_; 277 scoped_ptr<NotificationServiceImpl> notification_service_;
151 scoped_ptr<BrowserMainLoop> main_loop_; 278 scoped_ptr<BrowserMainLoop> main_loop_;
152 #if defined(OS_WIN) 279 #if defined(OS_WIN)
153 scoped_ptr<ui::ScopedOleInitializer> ole_initializer_; 280 scoped_ptr<ui::ScopedOleInitializer> ole_initializer_;
154 #endif 281 #endif
155 282
156 DISALLOW_COPY_AND_ASSIGN(BrowserMainRunnerImpl); 283 DISALLOW_COPY_AND_ASSIGN(BrowserMainRunnerImpl);
157 }; 284 };
158 285
159 // static 286 // static
160 BrowserMainRunner* BrowserMainRunner::Create() { 287 BrowserMainRunner* BrowserMainRunner::Create() {
161 return new BrowserMainRunnerImpl(); 288 return new BrowserMainRunnerImpl();
162 } 289 }
163 290
164 } // namespace content 291 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698