Chromium Code Reviews| Index: base/trace_event/trace_event_impl.cc |
| diff --git a/base/trace_event/trace_event_impl.cc b/base/trace_event/trace_event_impl.cc |
| index f1c87ddac9bb87aab2778a45a318402bbfa10d8b..6eb1f3deebc6bf384d5428e525eb7bd5001191c9 100644 |
| --- a/base/trace_event/trace_event_impl.cc |
| +++ b/base/trace_event/trace_event_impl.cc |
| @@ -12,6 +12,8 @@ |
| #include "base/command_line.h" |
| #include "base/debug/leak_annotations.h" |
| #include "base/format_macros.h" |
| +#include "base/json/json_reader.h" |
| +#include "base/json/json_writer.h" |
| #include "base/json/string_escape.h" |
| #include "base/lazy_instance.h" |
| #include "base/location.h" |
| @@ -69,6 +71,15 @@ const char kTraceToConsole[] = "trace-to-console"; |
| const char kEnableSampling[] = "enable-sampling"; |
| const char kEnableSystrace[] = "enable-systrace"; |
| +// String parameters that can be used to parse the trace config string. |
| +const char kRecordModeParam[] = "record_mode"; |
| +const char kEnableSamplingParam[] = "enable_sampling"; |
| +const char kEnableSystraceParam[] = "enable_systrace"; |
| +const char kIncludedCategoriesParam[] = "included_categories"; |
| +const char kDisabledCategoriesParam[] = "disabled_categories"; |
| +const char kExcludedCategoriesParam[] = "excluded_categories"; |
| +const char kSyntheticDelaysParam[] = "synthetic_delays"; |
| + |
| // Controls the number of trace events we will buffer in-memory |
| // before throwing them away. |
| const size_t kTraceBufferChunkSize = TraceBufferChunk::kTraceBufferChunkSize; |
| @@ -2387,27 +2398,19 @@ void TraceLog::SetCurrentThreadBlocksMessageLoop() { |
| bool CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace( |
| const std::string& str) { |
| - return str.empty() || |
| - str.at(0) == ' ' || |
| - str.at(str.length() - 1) == ' '; |
| + return TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(str); |
| } |
| -CategoryFilter::CategoryFilter(const std::string& filter_string) { |
| - if (!filter_string.empty()) |
| - Initialize(filter_string); |
| - else |
| - Initialize(CategoryFilter::kDefaultCategoryFilterString); |
| +CategoryFilter::CategoryFilter(const std::string& filter_string) |
| + : config_(new TraceConfig(filter_string, "")) { |
| } |
| -CategoryFilter::CategoryFilter() { |
| - Initialize(CategoryFilter::kDefaultCategoryFilterString); |
| +CategoryFilter::CategoryFilter() |
| + : config_(new TraceConfig()) { |
| } |
| CategoryFilter::CategoryFilter(const CategoryFilter& cf) |
| - : included_(cf.included_), |
| - disabled_(cf.disabled_), |
| - excluded_(cf.excluded_), |
| - delays_(cf.delays_) { |
| + : config_(new TraceConfig(*(cf.config_))) { |
| } |
| CategoryFilter::~CategoryFilter() { |
| @@ -2417,47 +2420,10 @@ CategoryFilter& CategoryFilter::operator=(const CategoryFilter& rhs) { |
| if (this == &rhs) |
| return *this; |
| - included_ = rhs.included_; |
| - disabled_ = rhs.disabled_; |
| - excluded_ = rhs.excluded_; |
| - delays_ = rhs.delays_; |
| + config_.reset(new TraceConfig(*(rhs.config_))); |
| return *this; |
| } |
| -void CategoryFilter::Initialize(const std::string& filter_string) { |
| - // Tokenize list of categories, delimited by ','. |
| - StringTokenizer tokens(filter_string, ","); |
| - // Add each token to the appropriate list (included_,excluded_). |
| - while (tokens.GetNext()) { |
| - std::string category = tokens.token(); |
| - // Ignore empty categories. |
| - if (category.empty()) |
| - continue; |
| - // Synthetic delays are of the form 'DELAY(delay;option;option;...)'. |
| - if (category.find(kSyntheticDelayCategoryFilterPrefix) == 0 && |
| - category.at(category.size() - 1) == ')') { |
| - category = category.substr( |
| - strlen(kSyntheticDelayCategoryFilterPrefix), |
| - category.size() - strlen(kSyntheticDelayCategoryFilterPrefix) - 1); |
| - size_t name_length = category.find(';'); |
| - if (name_length != std::string::npos && name_length > 0 && |
| - name_length != category.size() - 1) { |
| - delays_.push_back(category); |
| - } |
| - } else if (category.at(0) == '-') { |
| - // Excluded categories start with '-'. |
| - // Remove '-' from category string. |
| - category = category.substr(1); |
| - excluded_.push_back(category); |
| - } else if (category.compare(0, strlen(TRACE_DISABLED_BY_DEFAULT("")), |
| - TRACE_DISABLED_BY_DEFAULT("")) == 0) { |
| - disabled_.push_back(category); |
| - } else { |
| - included_.push_back(category); |
| - } |
| - } |
| -} |
| - |
| void CategoryFilter::WriteString(const StringList& values, |
| std::string* out, |
| bool included) const { |
| @@ -2488,15 +2454,337 @@ void CategoryFilter::WriteString(const StringList& delays, |
| std::string CategoryFilter::ToString() const { |
| std::string filter_string; |
| - WriteString(included_, &filter_string, true); |
| - WriteString(disabled_, &filter_string, true); |
| - WriteString(excluded_, &filter_string, false); |
| - WriteString(delays_, &filter_string); |
| + WriteString(config_->included_categories_, &filter_string, true); |
| + WriteString(config_->disabled_categories_, &filter_string, true); |
| + WriteString(config_->excluded_categories_, &filter_string, false); |
| + WriteString(config_->synthetic_delays_, &filter_string); |
| return filter_string; |
| } |
| bool CategoryFilter::IsCategoryGroupEnabled( |
| const char* category_group_name) const { |
| + return config_->IsCategoryGroupEnabled(category_group_name); |
| +} |
| + |
| +bool CategoryFilter::IsCategoryEnabled(const char* category_name) const { |
| + return config_->IsCategoryEnabled(category_name); |
| +} |
| + |
| +bool CategoryFilter::HasIncludedPatterns() const { |
| + return config_->HasIncludedPatterns(); |
| +} |
| + |
| +void CategoryFilter::Merge(const CategoryFilter& nested_filter) { |
| + config_->Merge(*(nested_filter.config_)); |
| +} |
| + |
| +void CategoryFilter::Clear() { |
| + config_->included_categories_.clear(); |
| + config_->disabled_categories_.clear(); |
| + config_->excluded_categories_.clear(); |
| +} |
| + |
| +const CategoryFilter::StringList& |
| + CategoryFilter::GetSyntheticDelayValues() const { |
| + return config_->GetSyntheticDelayValues(); |
| +} |
| + |
| +//////////////////////////////////////////////////////////////////////////////// |
| +// |
| +// TraceConfig |
| +// |
| +//////////////////////////////////////////////////////////////////////////////// |
| + |
| +TraceConfig::TraceConfig() { |
| + Initialize(TraceConfig::kDefaultTraceConfigString); |
| +} |
| + |
| +TraceConfig::TraceConfig(const CategoryFilter& cf, |
| + const TraceOptions& options) { |
| + record_mode_ = options.record_mode; |
| + enable_sampling_ = options.enable_sampling; |
| + enable_systrace_ = options.enable_systrace; |
| + |
| + included_categories_ = cf.config_->included_categories_; |
| + disabled_categories_ = cf.config_->disabled_categories_; |
| + excluded_categories_ = cf.config_->excluded_categories_; |
| + synthetic_delays_ = cf.config_->synthetic_delays_; |
| +} |
| + |
| +TraceConfig::TraceConfig(const std::string& category_filter_string, |
| + const std::string& trace_options_string) { |
| + if (!category_filter_string.empty()) { |
| + // Tokenize list of categories, delimited by ','. |
| + StringTokenizer tokens(category_filter_string, ","); |
|
nednguyen
2015/05/11 17:59:28
nits: you want to be consistent about using single
Zhen Wang
2015/05/13 00:01:10
Use SplitString now.
|
| + // Add each token to the appropriate list (included_,excluded_). |
| + while (tokens.GetNext()) { |
| + std::string category = tokens.token(); |
| + // Ignore empty categories. |
| + if (category.empty()) |
| + continue; |
| + // Synthetic delays are of the form 'DELAY(delay;option;option;...)'. |
|
nednguyen
2015/05/11 17:59:28
What about cases like ' Delay(delay; option; opt
Zhen Wang
2015/05/13 00:01:10
Use SplitString now to get leading-and-trailing-sp
|
| + if (category.find(kSyntheticDelayCategoryFilterPrefix) == 0 && |
| + category.at(category.size() - 1) == ')') { |
| + category = category.substr( |
| + strlen(kSyntheticDelayCategoryFilterPrefix), |
| + category.size() - strlen(kSyntheticDelayCategoryFilterPrefix) - 1); |
| + size_t name_length = category.find(';'); |
| + if (name_length != std::string::npos && name_length > 0 && |
| + name_length != category.size() - 1) { |
| + synthetic_delays_.push_back(category); |
| + } |
| + } else if (category.at(0) == '-') { |
| + // Excluded categories start with '-'. |
| + // Remove '-' from category string. |
| + category = category.substr(1); |
| + excluded_categories_.push_back(category); |
| + } else if (category.compare(0, strlen(TRACE_DISABLED_BY_DEFAULT("")), |
| + TRACE_DISABLED_BY_DEFAULT("")) == 0) { |
| + disabled_categories_.push_back(category); |
| + } else { |
| + included_categories_.push_back(category); |
| + } |
| + } |
| + } else { |
| + Initialize(TraceConfig::kDefaultTraceConfigString); |
| + } |
| + |
| + record_mode_ = RECORD_UNTIL_FULL; |
| + enable_sampling_ = false; |
| + enable_systrace_ = false; |
| + if(!trace_options_string.empty()) { |
| + std::vector<std::string> split; |
| + std::vector<std::string>::iterator iter; |
| + base::SplitString(trace_options_string, ',', &split); |
|
nednguyen
2015/05/11 17:59:28
while use StringTokenizer above but use SplitStrin
Zhen Wang
2015/05/13 00:01:10
Updated above with SplitString, so that leading an
|
| + for (iter = split.begin(); iter != split.end(); ++iter) { |
| + if (*iter == kRecordUntilFull) { |
| + record_mode_ = RECORD_UNTIL_FULL; |
| + } else if (*iter == kRecordContinuously) { |
| + record_mode_ = RECORD_CONTINUOUSLY; |
| + } else if (*iter == kTraceToConsole) { |
| + record_mode_ = ECHO_TO_CONSOLE; |
| + } else if (*iter == kRecordAsMuchAsPossible) { |
| + record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE; |
| + } else if (*iter == kEnableSampling) { |
| + enable_sampling_ = true; |
| + } else if (*iter == kEnableSystrace) { |
| + enable_systrace_ = true; |
| + } |
| + } |
| + } |
| +} |
| + |
| +TraceConfig::TraceConfig(const std::string& config_string) { |
| + if (!config_string.empty()) |
| + Initialize(config_string); |
| + else |
| + Initialize(TraceConfig::kDefaultTraceConfigString); |
| +} |
| + |
| +TraceConfig::TraceConfig(const TraceConfig& tc) |
| + : record_mode_(tc.record_mode_), |
| + enable_sampling_(tc.enable_sampling_), |
| + enable_systrace_(tc.enable_systrace_), |
| + included_categories_(tc.included_categories_), |
| + disabled_categories_(tc.disabled_categories_), |
| + excluded_categories_(tc.excluded_categories_), |
| + synthetic_delays_(tc.synthetic_delays_) { |
| +} |
| + |
| +TraceConfig::~TraceConfig() { |
| +} |
| + |
| +TraceConfig& TraceConfig::operator=(const TraceConfig& rhs) { |
| + if (this == &rhs) |
| + return *this; |
| + |
| + record_mode_ = rhs.record_mode_; |
| + enable_sampling_ = rhs.enable_sampling_; |
| + enable_systrace_ = rhs.enable_systrace_; |
| + included_categories_ = rhs.included_categories_; |
| + disabled_categories_ = rhs.disabled_categories_; |
| + excluded_categories_ = rhs.excluded_categories_; |
| + synthetic_delays_ = rhs.synthetic_delays_; |
| + return *this; |
| +} |
| + |
| +const TraceConfig::StringList& TraceConfig::GetSyntheticDelayValues() const { |
| + return synthetic_delays_; |
| +} |
| + |
| +void TraceConfig::ToCategoryFilter(CategoryFilter& cf) const { |
| + cf.config_.reset(new TraceConfig(*this)); |
| +} |
| + |
| +void TraceConfig::ToTraceOptions(TraceOptions& options) const { |
| + options.record_mode = record_mode_; |
| + options.enable_sampling = enable_sampling_; |
| + options.enable_systrace = enable_systrace_; |
| +} |
| + |
| +void TraceConfig::ToDict(base::DictionaryValue& dict) const { |
| + switch (record_mode_) { |
| + case RECORD_UNTIL_FULL: |
| + dict.SetString(kRecordModeParam, kRecordUntilFull); |
| + break; |
| + case RECORD_CONTINUOUSLY: |
| + dict.SetString(kRecordModeParam, kRecordContinuously); |
| + break; |
| + case ECHO_TO_CONSOLE: |
| + dict.SetString(kRecordModeParam, kTraceToConsole); |
| + break; |
| + case RECORD_AS_MUCH_AS_POSSIBLE: |
| + dict.SetString(kRecordModeParam, kRecordAsMuchAsPossible); |
| + break; |
| + default: |
| + NOTREACHED(); |
| + } |
| + |
| + if (enable_sampling_) |
| + dict.SetBoolean(kEnableSamplingParam, true); |
| + else |
| + dict.SetBoolean(kEnableSamplingParam, false); |
| + |
| + if (enable_systrace_) |
| + dict.SetBoolean(kEnableSystraceParam, true); |
| + else |
| + dict.SetBoolean(kEnableSystraceParam, false); |
| + |
| + AddCategoryToDict(dict, kIncludedCategoriesParam, included_categories_); |
| + AddCategoryToDict(dict, kDisabledCategoriesParam, disabled_categories_); |
| + AddCategoryToDict(dict, kExcludedCategoriesParam, excluded_categories_); |
| + AddCategoryToDict(dict, kSyntheticDelaysParam, synthetic_delays_); |
| +} |
| + |
| +std::string TraceConfig::ToString() const { |
| + base::DictionaryValue dict; |
| + ToDict(dict); |
| + |
| + std::string json; |
| + base::JSONWriter::Write(&dict, &json); |
| + |
| + return json; |
| +} |
| + |
| +std::string TraceConfig::ToCategoryFilterString() const { |
| + CategoryFilter cf; |
| + ToCategoryFilter(cf); |
| + return cf.ToString(); |
| +} |
| + |
| +std::string TraceConfig::ToTraceOptionsString() const { |
| + TraceOptions to; |
| + ToTraceOptions(to); |
| + return to.ToString(); |
| +} |
| + |
| +void TraceConfig::AddCategoryToDict(base::DictionaryValue& dict, |
| + const char* param, |
| + const StringList& categories) const { |
| + if (categories.empty()) |
| + return; |
| + |
| + scoped_ptr<base::ListValue> list(new base::ListValue()); |
| + for (StringList::const_iterator ci = categories.begin(); |
| + ci != categories.end(); |
| + ++ci) { |
| + list->AppendString(*ci); |
| + } |
| + |
| + dict.Set(param, list.Pass()); |
| +} |
| + |
| +void TraceConfig::Merge(const TraceConfig& config) { |
| + if (record_mode_ != config.record_mode_ |
| + || enable_sampling_ != config.enable_sampling_ |
| + || enable_systrace_ != config.enable_systrace_) { |
| + DLOG(ERROR) << "Attempting to merge trace config with a different " |
| + << "set of options."; |
| + } |
| + |
| + // Keep included patterns only if both filters have an included entry. |
| + // Otherwise, one of the filter was specifying "*" and we want to honor the |
| + // broadest filter. |
| + if (HasIncludedPatterns() && config.HasIncludedPatterns()) { |
| + included_categories_.insert(included_categories_.end(), |
| + config.included_categories_.begin(), |
| + config.included_categories_.end()); |
| + } else { |
| + included_categories_.clear(); |
| + } |
| + |
| + disabled_categories_.insert(disabled_categories_.end(), |
| + config.disabled_categories_.begin(), |
| + config.disabled_categories_.end()); |
| + excluded_categories_.insert(excluded_categories_.end(), |
| + config.excluded_categories_.begin(), |
| + config.excluded_categories_.end()); |
| + synthetic_delays_.insert(synthetic_delays_.end(), |
| + config.synthetic_delays_.begin(), |
| + config.synthetic_delays_.end()); |
| +} |
| + |
| +void TraceConfig::Clear() { |
| + record_mode_ = RECORD_UNTIL_FULL; |
| + enable_sampling_ = false; |
| + enable_systrace_ = false; |
| + included_categories_.clear(); |
| + disabled_categories_.clear(); |
| + excluded_categories_.clear(); |
| + synthetic_delays_.clear(); |
| +} |
| + |
| + |
| +void TraceConfig::Initialize(const std::string& config_string) { |
|
dsinclair
2015/05/08 17:44:49
Can you move this up to just below the constructor
Zhen Wang
2015/05/13 00:01:10
Done.
|
| + scoped_ptr<base::Value> value(base::JSONReader::Read(config_string)); |
| + if (!value || !value->IsType(base::Value::TYPE_DICTIONARY)) |
| + return; |
| + scoped_ptr<base::DictionaryValue> dict( |
| + static_cast<base::DictionaryValue*>(value.release())); |
| + |
| + std::string record_mode; |
| + if (dict->GetString(kRecordModeParam, &record_mode)) { |
| + if (record_mode == kRecordUntilFull) { |
| + record_mode_ = RECORD_UNTIL_FULL; |
| + } else if (record_mode == kRecordContinuously) { |
| + record_mode_ = RECORD_CONTINUOUSLY; |
| + } else if (record_mode == kTraceToConsole) { |
| + record_mode_ = ECHO_TO_CONSOLE; |
| + } else if (record_mode == kRecordAsMuchAsPossible) { |
| + record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE; |
| + } |
| + } else { |
| + record_mode_ = RECORD_UNTIL_FULL; |
| + } |
| + |
| + if (!dict->GetBoolean(kEnableSamplingParam, &enable_sampling_)) |
| + enable_sampling_ = false; |
| + if (!dict->GetBoolean(kEnableSystraceParam, &enable_systrace_)) |
| + enable_systrace_ = false; |
| + |
| + base::ListValue* category_list = NULL; |
| + if (dict->GetList(kIncludedCategoriesParam, &category_list)) |
| + SetCategoriesFromList(included_categories_, *category_list); |
| + if (dict->GetList(kDisabledCategoriesParam, &category_list)) |
| + SetCategoriesFromList(disabled_categories_, *category_list); |
| + if (dict->GetList(kExcludedCategoriesParam, &category_list)) |
| + SetCategoriesFromList(excluded_categories_, *category_list); |
| + if (dict->GetList(kSyntheticDelaysParam, &category_list)) |
| + SetCategoriesFromList(synthetic_delays_, *category_list); |
| +} |
| + |
| +void TraceConfig::SetCategoriesFromList(StringList& categories, |
| + const base::ListValue& list) { |
| + categories.clear(); |
| + for (size_t i = 0; i < list.GetSize(); ++i) { |
| + std::string category; |
| + if (list.GetString(i, &category)) |
| + categories.push_back(category); |
| + } |
| +} |
| + |
| +bool TraceConfig::IsCategoryGroupEnabled( |
| + const char* category_group_name) const { |
| // TraceLog should call this method only as part of enabling/disabling |
| // categories. |
| @@ -2508,7 +2796,7 @@ bool CategoryFilter::IsCategoryGroupEnabled( |
| while (category_group_tokens.GetNext()) { |
| std::string category_group_token = category_group_tokens.token(); |
| // Don't allow empty tokens, nor tokens with leading or trailing space. |
| - DCHECK(!CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace( |
| + DCHECK(!TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace( |
| category_group_token)) |
| << "Disallowed category string"; |
| if (IsCategoryEnabled(category_group_token.c_str())) { |
| @@ -2524,8 +2812,9 @@ bool CategoryFilter::IsCategoryGroupEnabled( |
| bool category_group_disabled = false; |
| while (category_group_tokens.GetNext()) { |
| std::string category_group_token = category_group_tokens.token(); |
| - for (StringList::const_iterator ci = excluded_.begin(); |
| - ci != excluded_.end(); ++ci) { |
| + for (StringList::const_iterator ci = excluded_categories_.begin(); |
| + ci != excluded_categories_.end(); |
| + ++ci) { |
| if (MatchPattern(category_group_token.c_str(), ci->c_str())) { |
| // Current token of category_group_name is present in excluded_list. |
| // Flag the exclusion and proceed further to check if any of the |
| @@ -2549,15 +2838,17 @@ bool CategoryFilter::IsCategoryGroupEnabled( |
| // we consider this category group enabled, as long as it had categories |
| // other than disabled-by-default. |
| return !category_group_disabled && |
| - included_.empty() && had_enabled_by_default; |
| + included_categories_.empty() && had_enabled_by_default; |
| } |
| -bool CategoryFilter::IsCategoryEnabled(const char* category_name) const { |
| +bool TraceConfig::IsCategoryEnabled(const char* category_name) const { |
| StringList::const_iterator ci; |
| // Check the disabled- filters and the disabled-* wildcard first so that a |
| // "*" filter does not include the disabled. |
| - for (ci = disabled_.begin(); ci != disabled_.end(); ++ci) { |
| + for (ci = disabled_categories_.begin(); |
| + ci != disabled_categories_.end(); |
| + ++ci) { |
| if (MatchPattern(category_name, ci->c_str())) |
| return true; |
| } |
| @@ -2565,7 +2856,9 @@ bool CategoryFilter::IsCategoryEnabled(const char* category_name) const { |
| if (MatchPattern(category_name, TRACE_DISABLED_BY_DEFAULT("*"))) |
| return false; |
| - for (ci = included_.begin(); ci != included_.end(); ++ci) { |
| + for (ci = included_categories_.begin(); |
| + ci != included_categories_.end(); |
| + ++ci) { |
| if (MatchPattern(category_name, ci->c_str())) |
| return true; |
| } |
| @@ -2573,42 +2866,15 @@ bool CategoryFilter::IsCategoryEnabled(const char* category_name) const { |
| return false; |
| } |
| -bool CategoryFilter::HasIncludedPatterns() const { |
| - return !included_.empty(); |
| -} |
| - |
| -void CategoryFilter::Merge(const CategoryFilter& nested_filter) { |
| - // Keep included patterns only if both filters have an included entry. |
| - // Otherwise, one of the filter was specifying "*" and we want to honour the |
| - // broadest filter. |
| - if (HasIncludedPatterns() && nested_filter.HasIncludedPatterns()) { |
| - included_.insert(included_.end(), |
| - nested_filter.included_.begin(), |
| - nested_filter.included_.end()); |
| - } else { |
| - included_.clear(); |
| - } |
| - |
| - disabled_.insert(disabled_.end(), |
| - nested_filter.disabled_.begin(), |
| - nested_filter.disabled_.end()); |
| - excluded_.insert(excluded_.end(), |
| - nested_filter.excluded_.begin(), |
| - nested_filter.excluded_.end()); |
| - delays_.insert(delays_.end(), |
| - nested_filter.delays_.begin(), |
| - nested_filter.delays_.end()); |
| -} |
| - |
| -void CategoryFilter::Clear() { |
| - included_.clear(); |
| - disabled_.clear(); |
| - excluded_.clear(); |
| +bool TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace( |
| + const std::string& str) { |
| + return str.empty() || |
| + str.at(0) == ' ' || |
| + str.at(str.length() - 1) == ' '; |
| } |
| -const CategoryFilter::StringList& |
| - CategoryFilter::GetSyntheticDelayValues() const { |
| - return delays_; |
| +bool TraceConfig::HasIncludedPatterns() const { |
| + return !included_categories_.empty(); |
| } |
| } // namespace trace_event |