diff options
author | zhenw <zhenw@chromium.org> | 2015-08-31 10:28:17 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-08-31 17:28:51 +0000 |
commit | c074d28f557ee0996efb3aa584b8932e1beb837e (patch) | |
tree | 466ac51b35adc4c625a505de47c3107146c247f8 | |
parent | 3066461da9c580021ec109446fcf4938abf90610 (diff) | |
download | chromium_src-c074d28f557ee0996efb3aa584b8932e1beb837e.zip chromium_src-c074d28f557ee0996efb3aa584b8932e1beb837e.tar.gz chromium_src-c074d28f557ee0996efb3aa584b8932e1beb837e.tar.bz2 |
Reland again [Startup Tracing] Add --trace-config-file flag
Original CL: https://codereview.chromium.org/1315463002/
1st reland: https://codereview.chromium.org/1317333002/
--------
This CL adds --trace-config-file flag. Please see trace_config_file.h for details.
Design doc:
https://docs.google.com/document/d/1PgdXUOJF3WtEmYWUyGRbC2Fz2ICCZKO9jPvpLPRSHH8/edit?usp=sharing
BUG=317481, 482098
TBR=dsinclair@chromium.org,blundell@chromium.org,sievers@chromium.org,sky@chromium.org,msw@chromium.org
Review URL: https://codereview.chromium.org/1309243004
Cr-Commit-Position: refs/heads/master@{#346407}
23 files changed, 583 insertions, 143 deletions
diff --git a/components/BUILD.gn b/components/BUILD.gn index c700866..07ed6c7 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn @@ -421,6 +421,7 @@ test("components_unittests") { "//components/proximity_auth:unit_tests", "//components/sessions:unit_tests", "//components/storage_monitor:unit_tests", + "//components/tracing:unit_tests", ] } diff --git a/components/components_tests.gyp b/components/components_tests.gyp index 7d08f72..b647e26 100644 --- a/components/components_tests.gyp +++ b/components/components_tests.gyp @@ -622,6 +622,9 @@ 'sync_driver/tab_node_pool_unittest.cc', 'sync_driver/ui_data_type_controller_unittest.cc', ], + 'tracing_unittest_sources': [ + 'tracing/trace_config_file_unittest.cc', + ], 'translate_unittest_sources': [ 'translate/core/browser/language_state_unittest.cc', 'translate/core/browser/translate_browser_metrics_unittest.cc', @@ -1180,6 +1183,7 @@ '<@(copresence_unittest_sources)', '<@(feedback_unittest_sources)', '<@(proximity_auth_unittest_sources)', + '<@(tracing_unittest_sources)', ], 'sources!': [ 'variations/variations_request_scheduler_mobile_unittest.cc', @@ -1199,6 +1203,7 @@ 'components.gyp:pref_registry_test_support', 'components.gyp:proximity_auth', 'components.gyp:proximity_auth_test_support', + 'tracing.gyp:tracing', ], }], ['chromeos==1', { diff --git a/components/tracing.gyp b/components/tracing.gyp index cd7bc4f..8bf23d2 100644 --- a/components/tracing.gyp +++ b/components/tracing.gyp @@ -30,8 +30,8 @@ 'tracing/child_memory_dump_manager_delegate_impl.h', 'tracing/child_trace_message_filter.cc', 'tracing/child_trace_message_filter.h', - 'tracing/startup_tracing.cc', - 'tracing/startup_tracing.h', + 'tracing/trace_config_file.cc', + 'tracing/trace_config_file.h', 'tracing/tracing_export.h', 'tracing/tracing_messages.cc', 'tracing/tracing_messages.h', diff --git a/components/tracing/BUILD.gn b/components/tracing/BUILD.gn index 059f4f1..bd5b271 100644 --- a/components/tracing/BUILD.gn +++ b/components/tracing/BUILD.gn @@ -23,8 +23,8 @@ component("tracing") { component("startup_tracing") { sources = [ - "startup_tracing.cc", - "startup_tracing.h", + "trace_config_file.cc", + "trace_config_file.h", "tracing_export.h", "tracing_switches.cc", "tracing_switches.h", @@ -36,3 +36,17 @@ component("startup_tracing") { "//base", ] } + +source_set("unit_tests") { + testonly = true + + sources = [ + "trace_config_file_unittest.cc", + ] + + deps = [ + ":startup_tracing", + "//base/test:test_support", + "//testing/gtest", + ] +} diff --git a/components/tracing/startup_tracing.cc b/components/tracing/startup_tracing.cc deleted file mode 100644 index 321b950..0000000 --- a/components/tracing/startup_tracing.cc +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/tracing/startup_tracing.h" - -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/path_service.h" -#include "base/trace_event/trace_event.h" - -namespace tracing { - -namespace { - -// Maximum trace config file size that will be loaded, in bytes. -const size_t kTraceConfigFileSizeLimit = 64 * 1024; - -// Trace config file path: -// - Android: /data/local/.config/chrome-trace-config.json -// - POSIX other than Android: $HOME/.config/chrome-trace-config.json -// - Win: %USERPROFILE%/.config/chrome-trace-config.json -#if defined(OS_ANDROID) -const base::FilePath::CharType kAndroidTraceConfigDir[] = - FILE_PATH_LITERAL("/data/local"); -#endif - -const base::FilePath::CharType kChromeConfigDir[] = - FILE_PATH_LITERAL(".config"); -const base::FilePath::CharType kTraceConfigFileName[] = - FILE_PATH_LITERAL("chrome-trace-config.json"); - -base::FilePath GetTraceConfigFilePath() { -#if defined(OS_ANDROID) - base::FilePath path(kAndroidTraceConfigDir); -#elif defined(OS_POSIX) || defined(OS_WIN) - base::FilePath path; - PathService::Get(base::DIR_HOME, &path); -#else - base::FilePath path; -#endif - path = path.Append(kChromeConfigDir); - path = path.Append(kTraceConfigFileName); - return path; -} - -} // namespace - -void EnableStartupTracingIfConfigFileExists() { - base::FilePath trace_config_file_path = GetTraceConfigFilePath(); - if (!base::PathExists(trace_config_file_path)) - return; - - std::string trace_config_str; - if (!base::ReadFileToString(trace_config_file_path, - &trace_config_str, - kTraceConfigFileSizeLimit)) { - return; - } - - base::trace_event::TraceConfig trace_config(trace_config_str); - base::trace_event::TraceLog::GetInstance()->SetEnabled( - trace_config, base::trace_event::TraceLog::RECORDING_MODE); -} - -} // namespace tracing diff --git a/components/tracing/startup_tracing.h b/components/tracing/startup_tracing.h deleted file mode 100644 index 5d1c74d..0000000 --- a/components/tracing/startup_tracing.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_TRACING_STARTUP_TRACING_H_ -#define COMPONENTS_TRACING_STARTUP_TRACING_H_ - -#include "components/tracing/tracing_export.h" - -namespace tracing { - -// Enable startup tracing according to the trace config file. If the trace -// config file does not exist, it will do nothing. This is designed to be used -// by Telemetry. Telemetry will stop tracing via DevTools later. To avoid -// conflict, this should not be used when --trace-startup is enabled. -void TRACING_EXPORT EnableStartupTracingIfConfigFileExists(); - -} // namespace tracing - -#endif // COMPONENTS_TRACING_STARTUP_TRACING_H_ diff --git a/components/tracing/trace_config_file.cc b/components/tracing/trace_config_file.cc new file mode 100644 index 0000000..e1cbc5c --- /dev/null +++ b/components/tracing/trace_config_file.cc @@ -0,0 +1,140 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/tracing/trace_config_file.h" + +#include <string> + +#include "base/command_line.h" +#include "base/files/file_util.h" +#include "base/json/json_reader.h" +#include "base/json/json_writer.h" +#include "base/logging.h" +#include "base/memory/singleton.h" +#include "base/values.h" +#include "components/tracing/tracing_switches.h" + +namespace tracing { + +namespace { + +// Maximum trace config file size that will be loaded, in bytes. +const size_t kTraceConfigFileSizeLimit = 64 * 1024; + +// Trace config file path: +// - Android: /data/local/chrome-trace-config.json +// - Others: specified by --trace-config-file flag. +#if defined(OS_ANDROID) +const base::FilePath::CharType kAndroidTraceConfigFile[] = + FILE_PATH_LITERAL("/data/local/chrome-trace-config.json"); +#endif + +const base::FilePath::CharType kDefaultResultFile[] = + FILE_PATH_LITERAL("chrometrace.log"); + +// String parameters that can be used to parse the trace config file content. +const char kTraceConfigParam[] = "trace_config"; +const char kStartupDurationParam[] = "startup_duration"; +const char kResultFileParam[] = "result_file"; + +} // namespace + +TraceConfigFile* TraceConfigFile::GetInstance() { + return Singleton<TraceConfigFile, + DefaultSingletonTraits<TraceConfigFile>>::get(); +} + +TraceConfigFile::TraceConfigFile() + : is_enabled_(false), + trace_config_(base::trace_event::TraceConfig()), + startup_duration_(0), + result_file_(kDefaultResultFile) { +#if defined(OS_ANDROID) + base::FilePath trace_config_file(kAndroidTraceConfigFile); +#else + const base::CommandLine& command_line = + *base::CommandLine::ForCurrentProcess(); + if (!command_line.HasSwitch(switches::kTraceConfigFile) || + command_line.HasSwitch(switches::kTraceStartup) || + command_line.HasSwitch(switches::kTraceShutdown)) { + return; + } + base::FilePath trace_config_file = + command_line.GetSwitchValuePath(switches::kTraceConfigFile); +#endif + + if (trace_config_file.empty()) { + // If the trace config file path is not specified, trace Chrome with the + // default configuration for 5 sec. + startup_duration_ = 5; + is_enabled_ = true; + return; + } + + if (!base::PathExists(trace_config_file)) + return; + + std::string trace_config_file_content; + if (!base::ReadFileToString(trace_config_file, + &trace_config_file_content, + kTraceConfigFileSizeLimit)) { + return; + } + is_enabled_ = ParseTraceConfigFileContent(trace_config_file_content); +} + +TraceConfigFile::~TraceConfigFile() { +} + +bool TraceConfigFile::ParseTraceConfigFileContent(std::string content) { + scoped_ptr<base::Value> value(base::JSONReader::Read(content)); + if (!value || !value->IsType(base::Value::TYPE_DICTIONARY)) + return false; + + scoped_ptr<base::DictionaryValue> dict( + static_cast<base::DictionaryValue*>(value.release())); + + base::DictionaryValue* trace_config_dict = NULL; + if (!dict->GetDictionary(kTraceConfigParam, &trace_config_dict)) + return false; + + std::string trace_config_str; + base::JSONWriter::Write(*trace_config_dict, &trace_config_str); + trace_config_ = base::trace_event::TraceConfig(trace_config_str); + + if (!dict->GetInteger(kStartupDurationParam, &startup_duration_)) + startup_duration_ = 0; + + if (startup_duration_ < 0) + startup_duration_ = 0; + + std::string result_file_str; + if (dict->GetString(kResultFileParam, &result_file_str)) + result_file_ = base::FilePath().AppendASCII(result_file_str); + + return true; +} + +bool TraceConfigFile::IsEnabled() const { + return is_enabled_; +} + +base::trace_event::TraceConfig TraceConfigFile::GetTraceConfig() const { + DCHECK(IsEnabled()); + return trace_config_; +} + +int TraceConfigFile::GetStartupDuration() const { + DCHECK(IsEnabled()); + return startup_duration_; +} + +#if !defined(OS_ANDROID) +base::FilePath TraceConfigFile::GetResultFile() const { + DCHECK(IsEnabled()); + return result_file_; +} +#endif + +} // namespace tracing diff --git a/components/tracing/trace_config_file.h b/components/tracing/trace_config_file.h new file mode 100644 index 0000000..273f9f1 --- /dev/null +++ b/components/tracing/trace_config_file.h @@ -0,0 +1,94 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_TRACING_TRACE_CONFIG_FILE_H_ +#define COMPONENTS_TRACING_TRACE_CONFIG_FILE_H_ + +#include "base/files/file_path.h" +#include "base/macros.h" +#include "base/trace_event/trace_config.h" +#include "components/tracing/tracing_export.h" + +template <typename Type> struct DefaultSingletonTraits; + +namespace tracing { + +// TraceConfigFile is a singleton that contains the configurations of tracing. +// One can create a trace config file and use it to configure startup and/or +// shutdown tracing. +// +// The trace config file should be JSON formated. One example is: +// { +// "trace_config": { +// "record_mode": "record-until-full", +// "included_categories": ["cc", "skia"] +// }, +// "startup_duration": 5, +// "result_file": "chrometrace.log" +// } +// +// trace_config: The configuration of tracing. Please see the details in +// base/trace_event/trace_config.h. +// +// startup_duration: The duration for startup tracing in terms of seconds. +// Tracing will stop automatically after the duration. If this +// value is not specified, the duration is 0 and one needs +// to stop tracing by other ways, e.g., by DevTools, or get +// the result file after shutting the browser down. +// +// result_file: The file that contains the trace log. The default result +// file path is chrometrace.log. Chrome will dump the trace +// log to this file +// 1) after startup_duration if it is specified; +// 2) or after browser shutdown if startup duration is 0. +// One can also stop tracing and get the result by other ways, +// e.g., by DevTools. In that case, the trace log will not be +// saved to this file. +// Notice: This is not supported on Android. The result file +// path will be generated by tracing controller. +// +// The trace config file can be specified by the --trace-config-file flag on +// most platforms except on Android, e.g., --trace-config-file=path/to/file/. +// This flag should not be used with --trace-startup or --trace-shutdown. If +// those two flags are used, --trace-config-file flag will be ignored. If the +// --trace-config-file flag is used without the file path, Chrome will do +// startup tracing with 5 seconds' startup duration. +// +// On Android, Chrome does not read the --trace-config-file flag, because not +// all Chrome based browsers read customized flag, e.g., Android WebView. Chrome +// on Android reads from a fixed file location: +// /data/local/chrome-trace-config.json +// If this file exists, Chrome will start tracing according to the configuration +// specified in the file, otherwise, Chrome will not start tracing. +class TRACING_EXPORT TraceConfigFile { + public: + static TraceConfigFile* GetInstance(); + + bool IsEnabled() const; + base::trace_event::TraceConfig GetTraceConfig() const; + int GetStartupDuration() const; +#if !defined(OS_ANDROID) + base::FilePath GetResultFile() const; +#endif + + private: + // This allows constructor and destructor to be private and usable only + // by the Singleton class. + friend struct DefaultSingletonTraits<TraceConfigFile>; + TraceConfigFile(); + ~TraceConfigFile(); + + bool ParseTraceConfigFileContent(std::string content); + + bool is_enabled_; + base::trace_event::TraceConfig trace_config_; + int startup_duration_; + base::FilePath result_file_; + + DISALLOW_COPY_AND_ASSIGN(TraceConfigFile); +}; + +} // namespace tracing + +#endif // COMPONENTS_TRACING_TRACE_CONFIG_FILE_H_ diff --git a/components/tracing/trace_config_file_unittest.cc b/components/tracing/trace_config_file_unittest.cc new file mode 100644 index 0000000..d62c4d4 --- /dev/null +++ b/components/tracing/trace_config_file_unittest.cc @@ -0,0 +1,220 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/at_exit.h" +#include "base/command_line.h" +#include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" +#include "components/tracing/trace_config_file.h" +#include "components/tracing/tracing_switches.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace tracing { + +namespace { + +const char kTraceConfig[] = + "{" + "\"enable_argument_filter\":true," + "\"enable_sampling\":true," + "\"enable_systrace\":true," + "\"excluded_categories\":[\"excluded\",\"exc_pattern*\"]," + "\"included_categories\":[\"included\"," + "\"inc_pattern*\"," + "\"disabled-by-default-cc\"]," + "\"record_mode\":\"record-continuously\"," + "\"synthetic_delays\":[\"test.Delay1;16\",\"test.Delay2;32\"]" + "}"; + +std::string GetTraceConfigFileContent(std::string trace_config, + std::string startup_duration, + std::string result_file) { + std::string content = "{"; + if (!trace_config.empty()) + content += "\"trace_config\":" + trace_config; + + if (!startup_duration.empty()) { + if (content != "{") + content += ","; + content += "\"startup_duration\":" + startup_duration; + } + + if (!result_file.empty()) { + if (content != "{") + content += ","; + content += "\"result_file\":\"" + result_file + "\""; + } + + content += "}"; + return content; +} + +} // namespace + +TEST(TraceConfigFileTest, TraceStartupEnabled) { + base::ShadowingAtExitManager sem; + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kTraceStartup); + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kTraceConfigFile); + + EXPECT_FALSE(TraceConfigFile::GetInstance()->IsEnabled()); +} + +TEST(TraceConfigFileTest, TraceShutdownEnabled) { + base::ShadowingAtExitManager sem; + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kTraceShutdown); + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kTraceConfigFile); + + EXPECT_FALSE(TraceConfigFile::GetInstance()->IsEnabled()); +} + +TEST(TraceConfigFileTest, TraceConfigFileNotEnabled) { + base::ShadowingAtExitManager sem; + EXPECT_FALSE(TraceConfigFile::GetInstance()->IsEnabled()); +} + +TEST(TraceConfigFileTest, TraceConfigFileEnabledWithoutPath) { + base::ShadowingAtExitManager sem; + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kTraceConfigFile); + + ASSERT_TRUE(TraceConfigFile::GetInstance()->IsEnabled()); + EXPECT_EQ(base::trace_event::TraceConfig().ToString(), + TraceConfigFile::GetInstance()->GetTraceConfig().ToString()); + EXPECT_EQ(5, TraceConfigFile::GetInstance()->GetStartupDuration()); + EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("chrometrace.log")), + TraceConfigFile::GetInstance()->GetResultFile()); +} + +TEST(TraceConfigFileTest, TraceConfigFileEnabledWithInvalidPath) { + base::ShadowingAtExitManager sem; + base::CommandLine::ForCurrentProcess()->AppendSwitchPath( + switches::kTraceConfigFile, + base::FilePath(FILE_PATH_LITERAL("invalid-trace-config-file-path"))); + + EXPECT_FALSE(TraceConfigFile::GetInstance()->IsEnabled()); +} + +TEST(TraceConfigFileTest, ValidContent) { + base::ShadowingAtExitManager sem; + std::string content = GetTraceConfigFileContent( + kTraceConfig, "10", "trace_result_file.log"); + + base::FilePath trace_config_file; + base::ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + ASSERT_TRUE( + base::CreateTemporaryFileInDir(temp_dir.path(), &trace_config_file)); + ASSERT_NE(-1, base::WriteFile( + trace_config_file, content.c_str(), (int)content.length())); + base::CommandLine::ForCurrentProcess()->AppendSwitchPath( + switches::kTraceConfigFile, trace_config_file); + + ASSERT_TRUE(TraceConfigFile::GetInstance()->IsEnabled()); + EXPECT_STREQ( + kTraceConfig, + TraceConfigFile::GetInstance()->GetTraceConfig().ToString().c_str()); + EXPECT_EQ(10, TraceConfigFile::GetInstance()->GetStartupDuration()); + EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("trace_result_file.log")), + TraceConfigFile::GetInstance()->GetResultFile()); +} + +TEST(TraceConfigFileTest, ValidContentWithOnlyTraceConfig) { + base::ShadowingAtExitManager sem; + std::string content = GetTraceConfigFileContent(kTraceConfig, "", ""); + + base::FilePath trace_config_file; + base::ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + ASSERT_TRUE( + base::CreateTemporaryFileInDir(temp_dir.path(), &trace_config_file)); + ASSERT_NE(-1, base::WriteFile( + trace_config_file, content.c_str(), (int)content.length())); + base::CommandLine::ForCurrentProcess()->AppendSwitchPath( + switches::kTraceConfigFile, trace_config_file); + + ASSERT_TRUE(TraceConfigFile::GetInstance()->IsEnabled()); + EXPECT_STREQ( + kTraceConfig, + TraceConfigFile::GetInstance()->GetTraceConfig().ToString().c_str()); + EXPECT_EQ(0, TraceConfigFile::GetInstance()->GetStartupDuration()); + EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("chrometrace.log")), + TraceConfigFile::GetInstance()->GetResultFile()); +} + +TEST(TraceConfigFileTest, ContentWithNegtiveDuration) { + base::ShadowingAtExitManager sem; + std::string content = GetTraceConfigFileContent(kTraceConfig, "-1", ""); + + base::FilePath trace_config_file; + base::ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + ASSERT_TRUE( + base::CreateTemporaryFileInDir(temp_dir.path(), &trace_config_file)); + ASSERT_NE(-1, base::WriteFile( + trace_config_file, content.c_str(), (int)content.length())); + base::CommandLine::ForCurrentProcess()->AppendSwitchPath( + switches::kTraceConfigFile, trace_config_file); + + ASSERT_TRUE(TraceConfigFile::GetInstance()->IsEnabled()); + EXPECT_STREQ( + kTraceConfig, + TraceConfigFile::GetInstance()->GetTraceConfig().ToString().c_str()); + EXPECT_EQ(0, TraceConfigFile::GetInstance()->GetStartupDuration()); + EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("chrometrace.log")), + TraceConfigFile::GetInstance()->GetResultFile()); +} + +TEST(TraceConfigFileTest, ContentWithoutTraceConfig) { + base::ShadowingAtExitManager sem; + std::string content = GetTraceConfigFileContent( + "", "10", "trace_result_file.log"); + + base::FilePath trace_config_file; + base::ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + ASSERT_TRUE( + base::CreateTemporaryFileInDir(temp_dir.path(), &trace_config_file)); + ASSERT_NE(-1, base::WriteFile( + trace_config_file, content.c_str(), (int)content.length())); + base::CommandLine::ForCurrentProcess()->AppendSwitchPath( + switches::kTraceConfigFile, trace_config_file); + + EXPECT_FALSE(TraceConfigFile::GetInstance()->IsEnabled()); +} + +TEST(TraceConfigFileTest, InvalidContent) { + base::ShadowingAtExitManager sem; + std::string content = "invalid trace config file content"; + + base::FilePath trace_config_file; + base::ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + ASSERT_TRUE( + base::CreateTemporaryFileInDir(temp_dir.path(), &trace_config_file)); + ASSERT_NE(-1, base::WriteFile( + trace_config_file, content.c_str(), (int)content.length())); + base::CommandLine::ForCurrentProcess()->AppendSwitchPath( + switches::kTraceConfigFile, trace_config_file); + + EXPECT_FALSE(TraceConfigFile::GetInstance()->IsEnabled()); +} + +TEST(TraceConfigFileTest, EmptyContent) { + base::ShadowingAtExitManager sem; + base::FilePath trace_config_file; + base::ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + ASSERT_TRUE( + base::CreateTemporaryFileInDir(temp_dir.path(), &trace_config_file)); + base::CommandLine::ForCurrentProcess()->AppendSwitchPath( + switches::kTraceConfigFile, trace_config_file); + + EXPECT_FALSE(TraceConfigFile::GetInstance()->IsEnabled()); +} + +} // namespace tracing diff --git a/components/tracing/tracing_switches.cc b/components/tracing/tracing_switches.cc index fcec5ee..ba3c1b1 100644 --- a/components/tracing/tracing_switches.cc +++ b/components/tracing/tracing_switches.cc @@ -6,6 +6,10 @@ namespace switches { +// Causes TRACE_EVENT flags to be recorded from startup. +// This flag will be ignored if --trace-startup or --trace-shutdown is provided. +const char kTraceConfigFile[] = "trace-config-file"; + // Causes TRACE_EVENT flags to be recorded beginning with shutdown. Optionally, // can specify the specific trace categories to include (e.g. // --trace-shutdown=base,net) otherwise, all events are recorded. diff --git a/components/tracing/tracing_switches.h b/components/tracing/tracing_switches.h index dba13da..263a49b 100644 --- a/components/tracing/tracing_switches.h +++ b/components/tracing/tracing_switches.h @@ -9,6 +9,7 @@ namespace switches { +TRACING_EXPORT extern const char kTraceConfigFile[]; TRACING_EXPORT extern const char kTraceShutdown[]; TRACING_EXPORT extern const char kTraceShutdownFile[]; TRACING_EXPORT extern const char kTraceStartup[]; diff --git a/components/tracing_nacl.gyp b/components/tracing_nacl.gyp index 287b613..1260e85 100644 --- a/components/tracing_nacl.gyp +++ b/components/tracing_nacl.gyp @@ -37,8 +37,8 @@ 'tracing/child_memory_dump_manager_delegate_impl.h', 'tracing/child_trace_message_filter.cc', 'tracing/child_trace_message_filter.h', - 'tracing/startup_tracing.cc', - 'tracing/startup_tracing.h', + 'tracing/trace_config_file.cc', + 'tracing/trace_config_file.h', 'tracing/tracing_export.h', 'tracing/tracing_messages.cc', 'tracing/tracing_messages.h', diff --git a/content/app/android/library_loader_hooks.cc b/content/app/android/library_loader_hooks.cc index 39ef2b0..2a1a3df 100644 --- a/content/app/android/library_loader_hooks.cc +++ b/content/app/android/library_loader_hooks.cc @@ -16,7 +16,7 @@ #include "base/strings/string_util.h" #include "base/trace_event/trace_event.h" #include "base/tracked_objects.h" -#include "components/tracing/startup_tracing.h" +#include "components/tracing/trace_config_file.h" #include "components/tracing/tracing_switches.h" #include "content/app/android/app_jni_registrar.h" #include "content/browser/android/browser_jni_registrar.h" @@ -94,7 +94,11 @@ bool LibraryLoaded(JNIEnv* env, jclass clazz) { base::trace_event::TraceLog::GetInstance()->SetEnabled( trace_config, base::trace_event::TraceLog::RECORDING_MODE); } else { - tracing::EnableStartupTracingIfConfigFileExists(); + if (tracing::TraceConfigFile::GetInstance()->IsEnabled()) { + base::trace_event::TraceLog::GetInstance()->SetEnabled( + tracing::TraceConfigFile::GetInstance()->GetTraceConfig(), + base::trace_event::TraceLog::RECORDING_MODE); + } } // Android's main browser loop is custom so we set the browser diff --git a/content/app/content_main_runner.cc b/content/app/content_main_runner.cc index 1a5e950..f35ed29 100644 --- a/content/app/content_main_runner.cc +++ b/content/app/content_main_runner.cc @@ -28,7 +28,7 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/trace_event/trace_event.h" -#include "components/tracing/startup_tracing.h" +#include "components/tracing/trace_config_file.h" #include "components/tracing/tracing_switches.h" #include "content/browser/browser_main.h" #include "content/common/set_process_title.h" @@ -629,9 +629,11 @@ class ContentMainRunnerImpl : public ContentMainRunner { base::trace_event::TraceLog::RECORDING_MODE); } else if (process_type != switches::kZygoteProcess && process_type != switches::kRendererProcess) { - // There is no need to schedule stopping tracing in this case. Telemetry - // will stop tracing on demand later. - tracing::EnableStartupTracingIfConfigFileExists(); + if (tracing::TraceConfigFile::GetInstance()->IsEnabled()) { + base::trace_event::TraceLog::GetInstance()->SetEnabled( + tracing::TraceConfigFile::GetInstance()->GetTraceConfig(), + base::trace_event::TraceLog::RECORDING_MODE); + } } #if defined(OS_WIN) diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index b5159df..df19ee8 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc @@ -26,6 +26,7 @@ #include "base/timer/hi_res_timer_manager.h" #include "base/trace_event/memory_dump_manager.h" #include "base/trace_event/trace_event.h" +#include "components/tracing/trace_config_file.h" #include "components/tracing/tracing_switches.h" #include "content/browser/browser_thread_impl.h" #include "content/browser/device_sensors/device_inertial_sensor_service.h" @@ -390,9 +391,11 @@ BrowserMainLoop::BrowserMainLoop(const MainFunctionParams& parameters) result_code_(RESULT_CODE_NORMAL_EXIT), created_threads_(false), // ContentMainRunner should have enabled tracing of the browser process - // when kTraceStartup is in the command line. - is_tracing_startup_( - parameters.command_line.HasSwitch(switches::kTraceStartup)) { + // when kTraceStartup or kTraceConfigFile is in the command line. + is_tracing_startup_for_duration_( + parameters.command_line.HasSwitch(switches::kTraceStartup) || + (tracing::TraceConfigFile::GetInstance()->IsEnabled() && + tracing::TraceConfigFile::GetInstance()->GetStartupDuration() > 0)) { DCHECK(!g_current_browser_main_loop); g_current_browser_main_loop = this; } @@ -578,9 +581,9 @@ void BrowserMainLoop::PostMainMessageLoopStart() { // Start tracing to a file if needed. Only do this after starting the main // message loop to avoid calling MessagePumpForUI::ScheduleWork() before // MessagePumpForUI::Start() as it will crash the browser. - if (is_tracing_startup_) { - TRACE_EVENT0("startup", "BrowserMainLoop::InitStartupTracing"); - InitStartupTracing(parsed_command_line_); + if (is_tracing_startup_for_duration_) { + TRACE_EVENT0("startup", "BrowserMainLoop::InitStartupTracingForDuration"); + InitStartupTracingForDuration(parsed_command_line_); } #endif // !defined(OS_IOS) @@ -1316,39 +1319,52 @@ void BrowserMainLoop::MainMessageLoopRun() { base::FilePath BrowserMainLoop::GetStartupTraceFileName( const base::CommandLine& command_line) const { - base::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 == base::FilePath().AppendASCII("none")) - return trace_file; - - if (trace_file.empty()) { + base::FilePath trace_file; + if (command_line.HasSwitch(switches::kTraceStartup)) { + 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 == base::FilePath().AppendASCII("none")) + return trace_file; + + if (trace_file.empty()) { +#if defined(OS_ANDROID) + TracingControllerAndroid::GenerateTracingFilePath(&trace_file); +#else + // Default to saving the startup trace into the current dir. + trace_file = base::FilePath().AppendASCII("chrometrace.log"); +#endif + } + } else { #if defined(OS_ANDROID) TracingControllerAndroid::GenerateTracingFilePath(&trace_file); #else - // Default to saving the startup trace into the current dir. - trace_file = base::FilePath().AppendASCII("chrometrace.log"); + trace_file = tracing::TraceConfigFile::GetInstance()->GetResultFile(); #endif } return trace_file; } -void BrowserMainLoop::InitStartupTracing( +void BrowserMainLoop::InitStartupTracingForDuration( const base::CommandLine& command_line) { - DCHECK(is_tracing_startup_); + DCHECK(is_tracing_startup_for_duration_); startup_trace_file_ = GetStartupTraceFileName(parsed_command_line_); - 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; + if (command_line.HasSwitch(switches::kTraceStartup)) { + std::string delay_str = command_line.GetSwitchValueASCII( + switches::kTraceStartupDuration); + 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; + } + } else { + delay_secs = tracing::TraceConfigFile::GetInstance()->GetStartupDuration(); } startup_trace_timer_.Start(FROM_HERE, @@ -1358,9 +1374,9 @@ void BrowserMainLoop::InitStartupTracing( } void BrowserMainLoop::EndStartupTracing() { - DCHECK(is_tracing_startup_); + DCHECK(is_tracing_startup_for_duration_); - is_tracing_startup_ = false; + is_tracing_startup_for_duration_ = false; TracingController::GetInstance()->DisableRecording( TracingController::CreateFileSink( startup_trace_file_, diff --git a/content/browser/browser_main_loop.h b/content/browser/browser_main_loop.h index 5f87e69..822589e7 100644 --- a/content/browser/browser_main_loop.h +++ b/content/browser/browser_main_loop.h @@ -116,7 +116,9 @@ class CONTENT_EXPORT BrowserMainLoop { media::midi::MidiManager* midi_manager() const { return midi_manager_.get(); } base::Thread* indexed_db_thread() const { return indexed_db_thread_.get(); } - bool is_tracing_startup() const { return is_tracing_startup_; } + bool is_tracing_startup_for_duration() const { + return is_tracing_startup_for_duration_; + } const base::FilePath& startup_trace_file() const { return startup_trace_file_; @@ -152,7 +154,7 @@ class CONTENT_EXPORT BrowserMainLoop { base::FilePath GetStartupTraceFileName( const base::CommandLine& command_line) const; - void InitStartupTracing(const base::CommandLine& command_line); + void InitStartupTracingForDuration(const base::CommandLine& command_line); void EndStartupTracing(); bool UsingInProcessGpu() const; @@ -166,7 +168,7 @@ class CONTENT_EXPORT BrowserMainLoop { // MainMessageLoopStart() // InitializeMainThread() // PostMainMessageLoopStart() - // InitStartupTracing() + // InitStartupTracingForDuration() // CreateStartupTasks() // PreCreateThreads() // CreateThreads() @@ -177,7 +179,7 @@ class CONTENT_EXPORT BrowserMainLoop { const base::CommandLine& parsed_command_line_; int result_code_; bool created_threads_; // True if the non-UI threads were created. - bool is_tracing_startup_; + bool is_tracing_startup_for_duration_; // Members initialized in |MainMessageLoopStart()| --------------------------- scoped_ptr<base::MessageLoop> main_message_loop_; @@ -206,7 +208,7 @@ class CONTENT_EXPORT BrowserMainLoop { scoped_ptr<MemoryObserver> memory_observer_; scoped_ptr<base::trace_event::TraceMemoryController> trace_memory_controller_; - // Members initialized in |InitStartupTracing()| ----------------------------- + // Members initialized in |InitStartupTracingForDuration()| ------------------ base::FilePath startup_trace_file_; // This timer initiates trace file saving. diff --git a/content/browser/browser_main_runner.cc b/content/browser/browser_main_runner.cc index 9f8e5ef..8ab69d9 100644 --- a/content/browser/browser_main_runner.cc +++ b/content/browser/browser_main_runner.cc @@ -14,14 +14,20 @@ #include "base/profiler/scoped_tracker.h" #include "base/trace_event/trace_event.h" #include "base/tracked_objects.h" +#include "components/tracing/trace_config_file.h" #include "components/tracing/tracing_switches.h" #include "content/browser/browser_main_loop.h" #include "content/browser/browser_shutdown_profile_dumper.h" #include "content/browser/notification_service_impl.h" +#include "content/public/browser/tracing_controller.h" #include "content/public/common/content_switches.h" #include "content/public/common/main_function_params.h" #include "ui/base/ime/input_method_initializer.h" +#if defined(OS_ANDROID) +#include "content/browser/android/tracing_controller_android.h" +#endif + #if defined(OS_WIN) #include "base/win/win_util.h" #include "base/win/windows_version.h" @@ -228,14 +234,26 @@ class BrowserMainRunnerImpl : public BrowserMainRunner { // If startup tracing has not been finished yet, replace it's dumper // with special version, which would save trace file on exit (i.e. // startup tracing becomes a version of shutdown tracing). + // There are two cases: + // 1. Startup duration is not reached. + // 2. Or startup duration is not specified for --trace-config-file flag. scoped_ptr<BrowserShutdownProfileDumper> startup_profiler; - if (main_loop_->is_tracing_startup()) { + if (main_loop_->is_tracing_startup_for_duration()) { main_loop_->StopStartupTracingTimer(); if (main_loop_->startup_trace_file() != base::FilePath().AppendASCII("none")) { startup_profiler.reset( new BrowserShutdownProfileDumper(main_loop_->startup_trace_file())); } + } else if (tracing::TraceConfigFile::GetInstance()->IsEnabled() && + TracingController::GetInstance()->IsRecording()) { + base::FilePath result_file; +#if defined(OS_ANDROID) + TracingControllerAndroid::GenerateTracingFilePath(&result_file); +#else + result_file = tracing::TraceConfigFile::GetInstance()->GetResultFile(); +#endif + startup_profiler.reset(new BrowserShutdownProfileDumper(result_file)); } // The shutdown tracing got enabled in AttemptUserExit earlier, but someone diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc index 4c05b63..30446d2 100644 --- a/content/browser/gpu/gpu_process_host.cc +++ b/content/browser/gpu/gpu_process_host.cc @@ -113,6 +113,7 @@ static const char* const kSwitchNames[] = { switches::kNoSandbox, switches::kProfilerTiming, switches::kTestGLLib, + switches::kTraceConfigFile, switches::kTraceStartup, switches::kTraceToConsole, switches::kV, diff --git a/content/browser/plugin_process_host.cc b/content/browser/plugin_process_host.cc index 61deb77..3d73d26 100644 --- a/content/browser/plugin_process_host.cc +++ b/content/browser/plugin_process_host.cc @@ -222,6 +222,7 @@ bool PluginProcessHost::Init(const WebPluginInfo& info) { switches::kLogPluginMessages, switches::kNoSandbox, switches::kPluginStartupDialog, + switches::kTraceConfigFile, switches::kTraceStartup, switches::kUseGL, switches::kForceDeviceScaleFactor, diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index 25691d4..e1e506c 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc @@ -1347,6 +1347,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer( switches::kTestType, switches::kTouchEvents, switches::kTouchTextSelectionStrategy, + switches::kTraceConfigFile, switches::kTraceToConsole, // This flag needs to be propagated to the renderer process for // --in-process-webgl. @@ -1416,7 +1417,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer( arraysize(kSwitchNames)); if (browser_cmd.HasSwitch(switches::kTraceStartup) && - BrowserMainLoop::GetInstance()->is_tracing_startup()) { + BrowserMainLoop::GetInstance()->is_tracing_startup_for_duration()) { // Pass kTraceStartup switch to renderer only if startup tracing has not // finished. renderer_cmd->AppendSwitchASCII( diff --git a/mandoline/app/DEPS b/mandoline/app/DEPS index 788a657..44f4e66 100644 --- a/mandoline/app/DEPS +++ b/mandoline/app/DEPS @@ -1,5 +1,5 @@ include_rules = [ - "+components/tracing/startup_tracing.h", + "+components/tracing", "+mojo", "+third_party/mojo/src/mojo/edk", "-third_party/mojo/src/mojo/edk/system", diff --git a/mandoline/app/desktop/launcher_process.cc b/mandoline/app/desktop/launcher_process.cc index afa1d15..132d033 100644 --- a/mandoline/app/desktop/launcher_process.cc +++ b/mandoline/app/desktop/launcher_process.cc @@ -15,7 +15,7 @@ #include "base/message_loop/message_loop.h" #include "base/synchronization/waitable_event.h" #include "base/trace_event/trace_event.h" -#include "components/tracing/startup_tracing.h" +#include "components/tracing/trace_config_file.h" #include "components/tracing/tracing_switches.h" #include "mandoline/app/core_services_initialization.h" #include "mandoline/app/desktop/launcher_process.h" @@ -90,10 +90,11 @@ int LauncherProcessMain(int argc, char** argv) { base::trace_event::RECORD_UNTIL_FULL); base::trace_event::TraceLog::GetInstance()->SetEnabled( trace_config, base::trace_event::TraceLog::RECORDING_MODE); - } else { - // |g_tracing| is not touched in this case and Telemetry will stop tracing - // on demand later. - tracing::EnableStartupTracingIfConfigFileExists(); + } else if (tracing::TraceConfigFile::GetInstance()->IsEnabled()) { + g_tracing = true; + base::trace_event::TraceLog::GetInstance()->SetEnabled( + tracing::TraceConfigFile::GetInstance()->GetTraceConfig(), + base::trace_event::TraceLog::RECORDING_MODE); } // We want the runner::Context to outlive the MessageLoop so that pipes are diff --git a/mojo/runner/desktop/launcher_process.cc b/mojo/runner/desktop/launcher_process.cc index 946f61f..c2ed3c3 100644 --- a/mojo/runner/desktop/launcher_process.cc +++ b/mojo/runner/desktop/launcher_process.cc @@ -15,7 +15,7 @@ #include "base/message_loop/message_loop.h" #include "base/synchronization/waitable_event.h" #include "base/trace_event/trace_event.h" -#include "components/tracing/startup_tracing.h" +#include "components/tracing/trace_config_file.h" #include "components/tracing/tracing_switches.h" #include "mojo/runner/context.h" #include "mojo/runner/switches.h" @@ -89,10 +89,11 @@ int LauncherProcessMain(int argc, char** argv) { base::trace_event::RECORD_UNTIL_FULL); base::trace_event::TraceLog::GetInstance()->SetEnabled( trace_config, base::trace_event::TraceLog::RECORDING_MODE); - } else { - // |g_tracing| is not touched in this case and Telemetry will stop tracing - // on demand later. - tracing::EnableStartupTracingIfConfigFileExists(); + } else if (tracing::TraceConfigFile::GetInstance()->IsEnabled()) { + g_tracing = true; + base::trace_event::TraceLog::GetInstance()->SetEnabled( + tracing::TraceConfigFile::GetInstance()->GetTraceConfig(), + base::trace_event::TraceLog::RECORDING_MODE); } // We want the shell::Context to outlive the MessageLoop so that pipes are |