summaryrefslogtreecommitdiffstats
path: root/content/browser
diff options
context:
space:
mode:
authorjoth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-09 19:21:33 +0000
committerjoth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-09 19:21:33 +0000
commit50f3842eba03378f345cfe61364cda455b342be2 (patch)
tree870bb60805a45b6693240e7edda1a014932fc112 /content/browser
parent7979168e1dfbf9a61aa0adbf641b6d310191b8c4 (diff)
downloadchromium_src-50f3842eba03378f345cfe61364cda455b342be2.zip
chromium_src-50f3842eba03378f345cfe61364cda455b342be2.tar.gz
chromium_src-50f3842eba03378f345cfe61364cda455b342be2.tar.bz2
Support --trace-startup and task tracing
passing --trace-startup puts the tracing system into record mode immediately saving the result to chrometrace.log or a file specified by --trace-startup-file BUG=None TEST=start chrome with --trace-startup, wait 5 secs, see chrometrace.log in current dir. open it in chrome://tracing/ Review URL: http://codereview.chromium.org/7887013 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@109281 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser')
-rw-r--r--content/browser/browser_main_loop.cc5
-rw-r--r--content/browser/gpu/gpu_process_host.cc3
-rw-r--r--content/browser/plugin_process_host.cc1
-rw-r--r--content/browser/renderer_host/browser_render_process_host.cc1
-rw-r--r--content/browser/trace_controller.cc152
-rw-r--r--content/browser/trace_controller.h20
-rw-r--r--content/browser/trace_subscriber_stdio.cc2
7 files changed, 133 insertions, 51 deletions
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 9045416..97da69e 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -13,6 +13,7 @@
#include "base/threading/thread_restrictions.h"
#include "base/tracked_objects.h"
#include "content/browser/browser_thread_impl.h"
+#include "content/browser/trace_controller.h"
#include "content/common/hi_res_timer_manager.h"
#include "content/common/sandbox_policy.h"
#include "content/public/browser/browser_main_parts.h"
@@ -246,6 +247,10 @@ void BrowserMainLoop::MainMessageLoopStart() {
InitializeMainThread();
+ // Start tracing to a file if needed.
+ if (base::debug::TraceLog::GetInstance()->IsEnabled())
+ TraceController::GetInstance()->InitStartupTracing(parsed_command_line_);
+
system_monitor_.reset(new base::SystemMonitor);
hi_res_timer_manager_.reset(new HighResolutionTimerManager);
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 305bbb9..0612fca 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -560,7 +560,8 @@ bool GpuProcessHost::LaunchGpuProcess() {
switches::kGpuNoContextLost,
switches::kGpuStartupDialog,
switches::kLoggingLevel,
- switches::kNoSandbox
+ switches::kNoSandbox,
+ switches::kTraceStartup,
};
cmd_line->CopySwitchesFrom(browser_command_line, kSwitchNames,
arraysize(kSwitchNames));
diff --git a/content/browser/plugin_process_host.cc b/content/browser/plugin_process_host.cc
index 475a4ef..1930bab 100644
--- a/content/browser/plugin_process_host.cc
+++ b/content/browser/plugin_process_host.cc
@@ -214,6 +214,7 @@ bool PluginProcessHost::Init(const webkit::WebPluginInfo& info,
switches::kNoSandbox,
switches::kPluginStartupDialog,
switches::kTestSandbox,
+ switches::kTraceStartup,
switches::kUseGL,
switches::kUserAgent,
switches::kV,
diff --git a/content/browser/renderer_host/browser_render_process_host.cc b/content/browser/renderer_host/browser_render_process_host.cc
index 659cc410..75e3473 100644
--- a/content/browser/renderer_host/browser_render_process_host.cc
+++ b/content/browser/renderer_host/browser_render_process_host.cc
@@ -616,6 +616,7 @@ void BrowserRenderProcessHost::PropagateBrowserCommandLineToRenderer(
switches::kShowPaintRects,
switches::kSimpleDataSource,
switches::kTestSandbox,
+ switches::kTraceStartup,
// This flag needs to be propagated to the renderer process for
// --in-process-webgl.
switches::kUseGL,
diff --git a/content/browser/trace_controller.cc b/content/browser/trace_controller.cc
index 9b380c0..137c4f7 100644
--- a/content/browser/trace_controller.cc
+++ b/content/browser/trace_controller.cc
@@ -5,14 +5,48 @@
#include "content/browser/trace_controller.h"
#include "base/bind.h"
+#include "base/command_line.h"
#include "base/debug/trace_event.h"
-#include "base/string_tokenizer.h"
+#include "base/string_number_conversions.h"
#include "content/browser/browser_message_filter.h"
#include "content/browser/trace_message_filter.h"
+#include "content/browser/trace_subscriber_stdio.h"
#include "content/common/child_process_messages.h"
+#include "content/public/common/content_switches.h"
+using base::debug::TraceLog;
using content::BrowserThread;
+namespace {
+
+class AutoStopTraceSubscriberStdio : public TraceSubscriberStdio {
+ public:
+ AutoStopTraceSubscriberStdio(const FilePath& file_path)
+ : TraceSubscriberStdio(file_path) {}
+
+ static void EndStartupTrace(TraceSubscriberStdio* subscriber) {
+ if (!TraceController::GetInstance()->EndTracingAsync(subscriber))
+ delete subscriber;
+ // else, the tracing will end asynchronously in OnEndTracingComplete().
+ }
+
+ virtual void OnEndTracingComplete() {
+ TraceSubscriberStdio::OnEndTracingComplete();
+ delete this;
+ // TODO(joth): this would be the time to automatically open up
+ // chrome://tracing/ and load up the trace data collected.
+ }
+};
+
+} // namespace
+
+void TraceSubscriber::OnKnownCategoriesCollected(
+ const std::set<std::string>& known_categories) {}
+
+void TraceSubscriber::OnTraceBufferPercentFullReply(float percent_full) {}
+
+TraceSubscriber::~TraceSubscriber() {}
+
TraceController::TraceController() :
subscriber_(NULL),
pending_end_ack_count_(0),
@@ -20,21 +54,58 @@ TraceController::TraceController() :
maximum_bpf_(0.0f),
is_tracing_(false),
is_get_categories_(false) {
- base::debug::TraceLog::GetInstance()->SetOutputCallback(
+ TraceLog::GetInstance()->SetOutputCallback(
base::Bind(&TraceController::OnTraceDataCollected,
base::Unretained(this)));
}
TraceController::~TraceController() {
- if (base::debug::TraceLog* trace_log = base::debug::TraceLog::GetInstance())
- trace_log->SetOutputCallback(base::debug::TraceLog::OutputCallback());
+ if (TraceLog* trace_log = TraceLog::GetInstance())
+ trace_log->SetOutputCallback(TraceLog::OutputCallback());
}
-//static
TraceController* TraceController::GetInstance() {
return Singleton<TraceController>::get();
}
+void TraceController::InitStartupTracing(const CommandLine& command_line) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ FilePath trace_file = command_line.GetSwitchValuePath(
+ switches::kTraceStartupFile);
+ // trace_file = "none" means that startup events will show up for the next
+ // begin/end tracing (via about:tracing or AutomationProxy::BeginTracing/
+ // EndTracing, for example).
+ if (trace_file == FilePath().AppendASCII("none"))
+ return;
+
+ if (trace_file.empty()) {
+ // Default to saving the startup trace into the current dir.
+ trace_file = FilePath().AppendASCII("chrometrace.log");
+ }
+ scoped_ptr<AutoStopTraceSubscriberStdio> subscriber(
+ new AutoStopTraceSubscriberStdio(trace_file));
+ DCHECK(can_begin_tracing(subscriber.get()));
+ if (!subscriber->IsValid()) {
+ TraceLog::GetInstance()->SetDisabled();
+ return;
+ }
+
+ std::string delay_str = command_line.GetSwitchValueASCII(
+ switches::kTraceStartupDuration);
+ int delay_secs = 5;
+ if (!delay_str.empty() && !base::StringToInt(delay_str, &delay_secs)) {
+ DLOG(WARNING) << "Could not parse --" << switches::kTraceStartupDuration
+ << "=" << delay_str << " defaulting to 5 (secs)";
+ delay_secs = 5;
+ }
+
+ OnTracingBegan(subscriber.get());
+ BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&AutoStopTraceSubscriberStdio::EndStartupTrace,
+ base::Unretained(subscriber.release())),
+ delay_secs * 1000);
+}
+
bool TraceController::GetKnownCategoriesAsync(TraceSubscriber* subscriber) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -60,48 +131,29 @@ bool TraceController::BeginTracing(
const std::vector<std::string>& excluded_categories) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (!can_begin_tracing() ||
- (subscriber_ != NULL && subscriber != subscriber_))
+ if (!can_begin_tracing(subscriber))
return false;
- subscriber_ = subscriber;
- included_categories_ = included_categories;
- excluded_categories_ = excluded_categories;
-
// Enable tracing
- is_tracing_ = true;
- base::debug::TraceLog::GetInstance()->SetEnabled(included_categories,
- excluded_categories);
-
- // Notify all child processes.
- for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) {
- it->get()->SendBeginTracing(included_categories, excluded_categories);
- }
+ TraceLog::GetInstance()->SetEnabled(included_categories, excluded_categories);
+ OnTracingBegan(subscriber);
return true;
}
bool TraceController::BeginTracing(TraceSubscriber* subscriber,
const std::string& categories) {
- std::vector<std::string> included, excluded;
- // Tokenize list of categories, delimited by ','.
- StringTokenizer tokens(categories, ",");
- while (tokens.GetNext()) {
- bool is_included = true;
- std::string category = tokens.token();
- // Excluded categories start with '-'.
- if (category.at(0) == '-') {
- // Remove '-' from category string.
- category = category.substr(1);
- is_included = false;
- }
- if (is_included)
- included.push_back(category);
- else
- excluded.push_back(category);
- }
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (!can_begin_tracing(subscriber))
+ return false;
+
+ // Enable tracing
+ TraceLog::GetInstance()->SetEnabled(categories);
- return BeginTracing(subscriber, included, excluded);
+ OnTracingBegan(subscriber);
+
+ return true;
}
bool TraceController::EndTracingAsync(TraceSubscriber* subscriber) {
@@ -121,7 +173,7 @@ bool TraceController::EndTracingAsync(TraceSubscriber* subscriber) {
if (pending_end_ack_count_ == 1) {
// Ack asynchronously now, because we don't have any children to wait for.
std::vector<std::string> categories;
- base::debug::TraceLog::GetInstance()->GetKnownCategories(&categories);
+ TraceLog::GetInstance()->GetKnownCategories(&categories);
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&TraceController::OnEndTracingAck, base::Unretained(this),
categories));
@@ -148,7 +200,7 @@ bool TraceController::GetTraceBufferPercentFullAsync(
// Handle special case of zero child processes.
if (pending_bpf_ack_count_ == 1) {
// Ack asynchronously now, because we don't have any children to wait for.
- float bpf = base::debug::TraceLog::GetInstance()->GetBufferPercentFull();
+ float bpf = TraceLog::GetInstance()->GetBufferPercentFull();
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&TraceController::OnTraceBufferPercentFullReply,
base::Unretained(this), bpf));
@@ -198,6 +250,19 @@ void TraceController::RemoveFilter(TraceMessageFilter* filter) {
filters_.erase(filter);
}
+void TraceController::OnTracingBegan(TraceSubscriber* subscriber) {
+ is_tracing_ = true;
+
+ subscriber_ = subscriber;
+
+ TraceLog::GetInstance()->GetEnabledTraceCategories(&included_categories_,
+ &excluded_categories_);
+ // Notify all child processes.
+ for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) {
+ it->get()->SendBeginTracing(included_categories_, excluded_categories_);
+ }
+}
+
void TraceController::OnEndTracingAck(
const std::vector<std::string>& known_categories) {
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
@@ -221,7 +286,7 @@ void TraceController::OnEndTracingAck(
// called with the last of the local trace data. Since we are on the UI
// thread, the call to OnTraceDataCollected will be synchronous, so we can
// immediately call OnEndTracingComplete below.
- base::debug::TraceLog::GetInstance()->SetEnabled(false);
+ TraceLog::GetInstance()->SetEnabled(false);
// Trigger callback if one is set.
if (subscriber_) {
@@ -240,7 +305,7 @@ void TraceController::OnEndTracingAck(
// The last ack represents local trace, so we need to ack it now. Note that
// this code only executes if there were child processes.
std::vector<std::string> categories;
- base::debug::TraceLog::GetInstance()->GetKnownCategories(&categories);
+ TraceLog::GetInstance()->GetKnownCategories(&categories);
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&TraceController::OnEndTracingAck, base::Unretained(this),
categories));
@@ -248,8 +313,7 @@ void TraceController::OnEndTracingAck(
}
void TraceController::OnTraceDataCollected(
- const scoped_refptr<base::debug::TraceLog::RefCountedString>&
- events_str_ptr) {
+ const scoped_refptr<TraceLog::RefCountedString>& events_str_ptr) {
// OnTraceDataCollected may be called from any browser thread, either by the
// local event trace system or from child processes via TraceMessageFilter.
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
@@ -301,7 +365,7 @@ void TraceController::OnTraceBufferPercentFullReply(float percent_full) {
if (pending_bpf_ack_count_ == 1) {
// The last ack represents local trace, so we need to ack it now. Note that
// this code only executes if there were child processes.
- float bpf = base::debug::TraceLog::GetInstance()->GetBufferPercentFull();
+ float bpf = TraceLog::GetInstance()->GetBufferPercentFull();
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&TraceController::OnTraceBufferPercentFullReply,
base::Unretained(this), bpf));
diff --git a/content/browser/trace_controller.h b/content/browser/trace_controller.h
index b14ec6a..1677056 100644
--- a/content/browser/trace_controller.h
+++ b/content/browser/trace_controller.h
@@ -13,6 +13,7 @@
#include "base/memory/singleton.h"
#include "content/common/content_export.h"
+class CommandLine;
class TraceMessageFilter;
// Objects interested in receiving trace data derive from TraceSubscriber.
@@ -28,8 +29,11 @@ class CONTENT_EXPORT TraceSubscriber {
virtual void OnTraceDataCollected(const std::string& trace_fragment) = 0;
// Called once after TraceController::GetKnownCategoriesAsync.
virtual void OnKnownCategoriesCollected(
- const std::set<std::string>& known_categories) {}
- virtual void OnTraceBufferPercentFullReply(float percent_full) {}
+ const std::set<std::string>& known_categories);
+ virtual void OnTraceBufferPercentFullReply(float percent_full);
+
+ protected:
+ virtual ~TraceSubscriber();
};
// TraceController is used on the browser processes to enable/disable
@@ -40,6 +44,10 @@ class CONTENT_EXPORT TraceController {
public:
static TraceController* GetInstance();
+ // Called on the main thread of the browser process to initialize
+ // startup tracing.
+ void InitStartupTracing(const CommandLine& command_line);
+
// Get set of known categories. This can change as new code paths are reached.
// If true is returned, subscriber->OnKnownCategoriesCollected will be called
// when once the categories are retrieved from child processes.
@@ -134,14 +142,16 @@ class CONTENT_EXPORT TraceController {
pending_bpf_ack_count_ == 0;
}
- bool can_begin_tracing() const { return !is_tracing_; }
+ bool can_begin_tracing(TraceSubscriber* subscriber) const {
+ return !is_tracing_ &&
+ (subscriber_ == NULL || subscriber == subscriber_);
+ }
// Methods for use by TraceMessageFilter.
- // Passing as scoped_refptr so that the method can be run asynchronously as
- // a task safely (otherwise the TraceMessageFilter could be destructed).
void AddFilter(TraceMessageFilter* filter);
void RemoveFilter(TraceMessageFilter* filter);
+ void OnTracingBegan(TraceSubscriber* subscriber);
void OnEndTracingAck(const std::vector<std::string>& known_categories);
void OnTraceDataCollected(
const scoped_refptr<base::debug::TraceLog::RefCountedString>&
diff --git a/content/browser/trace_subscriber_stdio.cc b/content/browser/trace_subscriber_stdio.cc
index 901aea0..0ecd51e 100644
--- a/content/browser/trace_subscriber_stdio.cc
+++ b/content/browser/trace_subscriber_stdio.cc
@@ -56,7 +56,7 @@ void TraceSubscriberStdio::OnTraceDataCollected(
void TraceSubscriberStdio::Write(const std::string& output_str) {
if (IsValid()) {
- size_t written = fwrite(output_str.c_str(), 1, output_str.size(), file_);
+ size_t written = fwrite(output_str.data(), 1, output_str.size(), file_);
if (written != output_str.size()) {
LOG(ERROR) << "Error " << ferror(file_) << " when writing to trace file";
CloseFile();