1 // Copyright (c) 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/trace_event/trace_config.h"
6
7 #include <stddef.h>
8
9 #include <algorithm>
10 #include <utility>
11
12 #include "base/json/json_reader.h"
13 #include "base/json/json_writer.h"
14 #include "base/memory/ptr_util.h"
15 #include "base/strings/string_split.h"
16 #include "base/trace_event/memory_dump_manager.h"
17 #include "base/trace_event/memory_dump_request_args.h"
18 #include "base/trace_event/trace_event.h"
19
20 namespace base {
21 namespace trace_event {
22
23 namespace {
24
25 // String options that can be used to initialize TraceOptions.
26 const char kRecordUntilFull[] = "record-until-full";
27 const char kRecordContinuously[] = "record-continuously";
28 const char kRecordAsMuchAsPossible[] = "record-as-much-as-possible";
29 const char kTraceToConsole[] = "trace-to-console";
30 const char kEnableSystrace[] = "enable-systrace";
31 constexpr int kEnableSystraceLength = sizeof(kEnableSystrace) - 1;
32
33 const char kEnableArgumentFilter[] = "enable-argument-filter";
34
35 // String parameters that can be used to parse the trace config string.
36 const char kRecordModeParam[] = "record_mode";
37 const char kTraceBufferSizeInEvents[] = "trace_buffer_size_in_events";
38 const char kTraceBufferSizeInKb[] = "trace_buffer_size_in_kb";
39 const char kEnableSystraceParam[] = "enable_systrace";
40 const char kSystraceEventsParam[] = "enable_systrace_events";
41 const char kEnableArgumentFilterParam[] = "enable_argument_filter";
42
43 // String parameters that is used to parse memory dump config in trace config
44 // string.
45 const char kMemoryDumpConfigParam[] = "memory_dump_config";
46 const char kAllowedDumpModesParam[] = "allowed_dump_modes";
47 const char kTriggersParam[] = "triggers";
48 const char kTriggerModeParam[] = "mode";
49 const char kMinTimeBetweenDumps[] = "min_time_between_dumps_ms";
50 const char kTriggerTypeParam[] = "type";
51 const char kPeriodicIntervalLegacyParam[] = "periodic_interval_ms";
52 const char kHeapProfilerOptions[] = "heap_profiler_options";
53 const char kBreakdownThresholdBytes[] = "breakdown_threshold_bytes";
54
55 // String parameters used to parse category event filters.
56 const char kEventFiltersParam[] = "event_filters";
57 const char kFilterPredicateParam[] = "filter_predicate";
58 const char kFilterArgsParam[] = "filter_args";
59
60 // String parameter used to parse process filter.
61 const char kIncludedProcessesParam[] = "included_process_ids";
62
63 const char kHistogramNamesParam[] = "histogram_names";
64
65 class ConvertableTraceConfigToTraceFormat
66 : public base::trace_event::ConvertableToTraceFormat {
67 public:
ConvertableTraceConfigToTraceFormat(const TraceConfig & trace_config)68 explicit ConvertableTraceConfigToTraceFormat(const TraceConfig& trace_config)
69 : trace_config_(trace_config) {}
70
71 ~ConvertableTraceConfigToTraceFormat() override = default;
72
AppendAsTraceFormat(std::string * out) const73 void AppendAsTraceFormat(std::string* out) const override {
74 out->append(trace_config_.ToString());
75 }
76
77 private:
78 const TraceConfig trace_config_;
79 };
80
GetDefaultAllowedMemoryDumpModes()81 std::set<MemoryDumpLevelOfDetail> GetDefaultAllowedMemoryDumpModes() {
82 std::set<MemoryDumpLevelOfDetail> all_modes;
83 for (uint32_t mode = static_cast<uint32_t>(MemoryDumpLevelOfDetail::FIRST);
84 mode <= static_cast<uint32_t>(MemoryDumpLevelOfDetail::LAST); mode++) {
85 all_modes.insert(static_cast<MemoryDumpLevelOfDetail>(mode));
86 }
87 return all_modes;
88 }
89
90 } // namespace
91
HeapProfiler()92 TraceConfig::MemoryDumpConfig::HeapProfiler::HeapProfiler()
93 : breakdown_threshold_bytes(kDefaultBreakdownThresholdBytes) {}
94
Clear()95 void TraceConfig::MemoryDumpConfig::HeapProfiler::Clear() {
96 breakdown_threshold_bytes = kDefaultBreakdownThresholdBytes;
97 }
98
ResetMemoryDumpConfig(const TraceConfig::MemoryDumpConfig & memory_dump_config)99 void TraceConfig::ResetMemoryDumpConfig(
100 const TraceConfig::MemoryDumpConfig& memory_dump_config) {
101 memory_dump_config_.Clear();
102 memory_dump_config_ = memory_dump_config;
103 }
104
105 TraceConfig::MemoryDumpConfig::MemoryDumpConfig() = default;
106
107 TraceConfig::MemoryDumpConfig::MemoryDumpConfig(
108 const MemoryDumpConfig& other) = default;
109
110 TraceConfig::MemoryDumpConfig::~MemoryDumpConfig() = default;
111
Clear()112 void TraceConfig::MemoryDumpConfig::Clear() {
113 allowed_dump_modes.clear();
114 triggers.clear();
115 heap_profiler_options.Clear();
116 }
117
Merge(const TraceConfig::MemoryDumpConfig & config)118 void TraceConfig::MemoryDumpConfig::Merge(
119 const TraceConfig::MemoryDumpConfig& config) {
120 triggers.insert(triggers.end(), config.triggers.begin(),
121 config.triggers.end());
122 allowed_dump_modes.insert(config.allowed_dump_modes.begin(),
123 config.allowed_dump_modes.end());
124 heap_profiler_options.breakdown_threshold_bytes =
125 std::min(heap_profiler_options.breakdown_threshold_bytes,
126 config.heap_profiler_options.breakdown_threshold_bytes);
127 }
128
129 TraceConfig::ProcessFilterConfig::ProcessFilterConfig() = default;
130
131 TraceConfig::ProcessFilterConfig::ProcessFilterConfig(
132 const ProcessFilterConfig& other) = default;
133
ProcessFilterConfig(const std::unordered_set<base::ProcessId> & included_process_ids)134 TraceConfig::ProcessFilterConfig::ProcessFilterConfig(
135 const std::unordered_set<base::ProcessId>& included_process_ids)
136 : included_process_ids_(included_process_ids) {}
137
138 TraceConfig::ProcessFilterConfig::~ProcessFilterConfig() = default;
139
Clear()140 void TraceConfig::ProcessFilterConfig::Clear() {
141 included_process_ids_.clear();
142 }
143
Merge(const ProcessFilterConfig & config)144 void TraceConfig::ProcessFilterConfig::Merge(
145 const ProcessFilterConfig& config) {
146 included_process_ids_.insert(config.included_process_ids_.begin(),
147 config.included_process_ids_.end());
148 }
149
InitializeFromConfigDict(const Value & dict)150 void TraceConfig::ProcessFilterConfig::InitializeFromConfigDict(
151 const Value& dict) {
152 included_process_ids_.clear();
153 const Value* value = dict.FindListKey(kIncludedProcessesParam);
154 if (!value)
155 return;
156 for (auto& pid_value : value->GetList()) {
157 if (pid_value.is_int())
158 included_process_ids_.insert(pid_value.GetInt());
159 }
160 }
161
ToDict(Value * dict) const162 void TraceConfig::ProcessFilterConfig::ToDict(Value* dict) const {
163 if (included_process_ids_.empty())
164 return;
165 Value* list = dict->SetKey(kIncludedProcessesParam, Value(Value::Type::LIST));
166 std::set<base::ProcessId> ordered_set(included_process_ids_.begin(),
167 included_process_ids_.end());
168 for (auto process_id : ordered_set)
169 list->Append(static_cast<int>(process_id));
170 }
171
IsEnabled(base::ProcessId process_id) const172 bool TraceConfig::ProcessFilterConfig::IsEnabled(
173 base::ProcessId process_id) const {
174 return included_process_ids_.empty() ||
175 included_process_ids_.count(process_id);
176 }
177
EventFilterConfig(const std::string & predicate_name)178 TraceConfig::EventFilterConfig::EventFilterConfig(
179 const std::string& predicate_name)
180 : predicate_name_(predicate_name) {}
181
182 TraceConfig::EventFilterConfig::~EventFilterConfig() = default;
183
EventFilterConfig(const EventFilterConfig & tc)184 TraceConfig::EventFilterConfig::EventFilterConfig(const EventFilterConfig& tc) {
185 *this = tc;
186 }
187
operator =(const TraceConfig::EventFilterConfig & rhs)188 TraceConfig::EventFilterConfig& TraceConfig::EventFilterConfig::operator=(
189 const TraceConfig::EventFilterConfig& rhs) {
190 if (this == &rhs)
191 return *this;
192
193 predicate_name_ = rhs.predicate_name_;
194 category_filter_ = rhs.category_filter_;
195
196 if (!rhs.args_.is_none())
197 args_ = rhs.args_.Clone();
198
199 return *this;
200 }
201
InitializeFromConfigDict(const Value & event_filter)202 void TraceConfig::EventFilterConfig::InitializeFromConfigDict(
203 const Value& event_filter) {
204 category_filter_.InitializeFromConfigDict(event_filter);
205
206 const Value* args_dict = event_filter.FindDictKey(kFilterArgsParam);
207 if (args_dict)
208 args_ = args_dict->Clone();
209 }
210
SetCategoryFilter(const TraceConfigCategoryFilter & category_filter)211 void TraceConfig::EventFilterConfig::SetCategoryFilter(
212 const TraceConfigCategoryFilter& category_filter) {
213 category_filter_ = category_filter;
214 }
215
ToDict(Value * filter_dict) const216 void TraceConfig::EventFilterConfig::ToDict(Value* filter_dict) const {
217 filter_dict->SetStringKey(kFilterPredicateParam, predicate_name());
218
219 category_filter_.ToDict(filter_dict);
220
221 if (!args_.is_none())
222 filter_dict->SetKey(kFilterArgsParam, args_.Clone());
223 }
224
GetArgAsSet(const char * key,std::unordered_set<std::string> * out_set) const225 bool TraceConfig::EventFilterConfig::GetArgAsSet(
226 const char* key,
227 std::unordered_set<std::string>* out_set) const {
228 const Value* list = args_.FindListPath(key);
229 if (!list)
230 return false;
231 for (const Value& item : list->GetList()) {
232 if (item.is_string())
233 out_set->insert(item.GetString());
234 }
235 return true;
236 }
237
IsCategoryGroupEnabled(const StringPiece & category_group_name) const238 bool TraceConfig::EventFilterConfig::IsCategoryGroupEnabled(
239 const StringPiece& category_group_name) const {
240 return category_filter_.IsCategoryGroupEnabled(category_group_name);
241 }
242
243 // static
TraceRecordModeToStr(TraceRecordMode record_mode)244 std::string TraceConfig::TraceRecordModeToStr(TraceRecordMode record_mode) {
245 switch (record_mode) {
246 case RECORD_UNTIL_FULL:
247 return kRecordUntilFull;
248 case RECORD_CONTINUOUSLY:
249 return kRecordContinuously;
250 case RECORD_AS_MUCH_AS_POSSIBLE:
251 return kRecordAsMuchAsPossible;
252 case ECHO_TO_CONSOLE:
253 return kTraceToConsole;
254 default:
255 NOTREACHED();
256 }
257 return kRecordUntilFull;
258 }
259
TraceConfig()260 TraceConfig::TraceConfig() {
261 InitializeDefault();
262 }
263
TraceConfig(StringPiece category_filter_string,StringPiece trace_options_string)264 TraceConfig::TraceConfig(StringPiece category_filter_string,
265 StringPiece trace_options_string) {
266 InitializeFromStrings(category_filter_string, trace_options_string);
267 }
268
TraceConfig(StringPiece category_filter_string,TraceRecordMode record_mode)269 TraceConfig::TraceConfig(StringPiece category_filter_string,
270 TraceRecordMode record_mode) {
271 InitializeFromStrings(category_filter_string,
272 TraceConfig::TraceRecordModeToStr(record_mode));
273 }
274
TraceConfig(const Value & config)275 TraceConfig::TraceConfig(const Value& config) {
276 InitializeFromConfigDict(config);
277 }
278
TraceConfig(StringPiece config_string)279 TraceConfig::TraceConfig(StringPiece config_string) {
280 if (!config_string.empty())
281 InitializeFromConfigString(config_string);
282 else
283 InitializeDefault();
284 }
285
286 TraceConfig::TraceConfig(const TraceConfig& tc) = default;
287
288 TraceConfig::~TraceConfig() = default;
289
operator =(const TraceConfig & rhs)290 TraceConfig& TraceConfig::operator=(const TraceConfig& rhs) {
291 if (this == &rhs)
292 return *this;
293
294 record_mode_ = rhs.record_mode_;
295 trace_buffer_size_in_events_ = rhs.trace_buffer_size_in_events_;
296 trace_buffer_size_in_kb_ = rhs.trace_buffer_size_in_kb_;
297 enable_systrace_ = rhs.enable_systrace_;
298 enable_argument_filter_ = rhs.enable_argument_filter_;
299 category_filter_ = rhs.category_filter_;
300 process_filter_config_ = rhs.process_filter_config_;
301 memory_dump_config_ = rhs.memory_dump_config_;
302 event_filters_ = rhs.event_filters_;
303 histogram_names_ = rhs.histogram_names_;
304 systrace_events_ = rhs.systrace_events_;
305 return *this;
306 }
307
ToString() const308 std::string TraceConfig::ToString() const {
309 Value dict = ToValue();
310 std::string json;
311 JSONWriter::Write(dict, &json);
312 return json;
313 }
314
315 std::unique_ptr<ConvertableToTraceFormat>
AsConvertableToTraceFormat() const316 TraceConfig::AsConvertableToTraceFormat() const {
317 return std::make_unique<ConvertableTraceConfigToTraceFormat>(*this);
318 }
319
ToCategoryFilterString() const320 std::string TraceConfig::ToCategoryFilterString() const {
321 return category_filter_.ToFilterString();
322 }
323
IsCategoryGroupEnabled(const StringPiece & category_group_name) const324 bool TraceConfig::IsCategoryGroupEnabled(
325 const StringPiece& category_group_name) const {
326 // TraceLog should call this method only as part of enabling/disabling
327 // categories.
328 return category_filter_.IsCategoryGroupEnabled(category_group_name);
329 }
330
Merge(const TraceConfig & config)331 void TraceConfig::Merge(const TraceConfig& config) {
332 if (record_mode_ != config.record_mode_
333 || enable_systrace_ != config.enable_systrace_
334 || enable_argument_filter_ != config.enable_argument_filter_) {
335 DLOG(ERROR) << "Attempting to merge trace config with a different "
336 << "set of options.";
337 }
338 DCHECK_EQ(trace_buffer_size_in_events_, config.trace_buffer_size_in_events_)
339 << "Cannot change trace buffer size";
340
341 category_filter_.Merge(config.category_filter_);
342 memory_dump_config_.Merge(config.memory_dump_config_);
343 process_filter_config_.Merge(config.process_filter_config_);
344
345 event_filters_.insert(event_filters_.end(), config.event_filters().begin(),
346 config.event_filters().end());
347 histogram_names_.insert(config.histogram_names().begin(),
348 config.histogram_names().end());
349 }
350
Clear()351 void TraceConfig::Clear() {
352 record_mode_ = RECORD_UNTIL_FULL;
353 trace_buffer_size_in_events_ = 0;
354 trace_buffer_size_in_kb_ = 0;
355 enable_systrace_ = false;
356 enable_argument_filter_ = false;
357 category_filter_.Clear();
358 memory_dump_config_.Clear();
359 process_filter_config_.Clear();
360 event_filters_.clear();
361 histogram_names_.clear();
362 systrace_events_.clear();
363 }
364
InitializeDefault()365 void TraceConfig::InitializeDefault() {
366 record_mode_ = RECORD_UNTIL_FULL;
367 trace_buffer_size_in_events_ = 0;
368 trace_buffer_size_in_kb_ = 0;
369 enable_systrace_ = false;
370 enable_argument_filter_ = false;
371 }
372
InitializeFromConfigDict(const Value & dict)373 void TraceConfig::InitializeFromConfigDict(const Value& dict) {
374 record_mode_ = RECORD_UNTIL_FULL;
375 const std::string* record_mode = dict.FindStringKey(kRecordModeParam);
376 if (record_mode) {
377 if (*record_mode == kRecordUntilFull) {
378 record_mode_ = RECORD_UNTIL_FULL;
379 } else if (*record_mode == kRecordContinuously) {
380 record_mode_ = RECORD_CONTINUOUSLY;
381 } else if (*record_mode == kTraceToConsole) {
382 record_mode_ = ECHO_TO_CONSOLE;
383 } else if (*record_mode == kRecordAsMuchAsPossible) {
384 record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE;
385 }
386 }
387 trace_buffer_size_in_events_ =
388 dict.FindIntKey(kTraceBufferSizeInEvents).value_or(0);
389 trace_buffer_size_in_kb_ = dict.FindIntKey(kTraceBufferSizeInKb).value_or(0);
390
391 enable_systrace_ = dict.FindBoolKey(kEnableSystraceParam).value_or(false);
392 enable_argument_filter_ =
393 dict.FindBoolKey(kEnableArgumentFilterParam).value_or(false);
394
395 category_filter_.InitializeFromConfigDict(dict);
396 process_filter_config_.InitializeFromConfigDict(dict);
397
398 const Value* category_event_filters = dict.FindListKey(kEventFiltersParam);
399 if (category_event_filters)
400 SetEventFiltersFromConfigList(*category_event_filters);
401 const Value* histogram_names = dict.FindListKey(kHistogramNamesParam);
402 if (histogram_names)
403 SetHistogramNamesFromConfigList(*histogram_names);
404
405 if (category_filter_.IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
406 // If dump triggers not set, the client is using the legacy with just
407 // category enabled. So, use the default periodic dump config.
408 const Value* memory_dump_config = dict.FindDictKey(kMemoryDumpConfigParam);
409 if (memory_dump_config)
410 SetMemoryDumpConfigFromConfigDict(*memory_dump_config);
411 else
412 SetDefaultMemoryDumpConfig();
413 }
414
415 systrace_events_.clear();
416 if (enable_systrace_) {
417 const Value* systrace_events = dict.FindListKey(kSystraceEventsParam);
418 if (systrace_events) {
419 for (const Value& value : systrace_events->GetList())
420 systrace_events_.insert(value.GetString());
421 }
422 }
423 }
424
InitializeFromConfigString(StringPiece config_string)425 void TraceConfig::InitializeFromConfigString(StringPiece config_string) {
426 base::Optional<Value> dict = JSONReader::Read(config_string);
427 if (dict && dict->is_dict())
428 InitializeFromConfigDict(*dict);
429 else
430 InitializeDefault();
431 }
432
InitializeFromStrings(StringPiece category_filter_string,StringPiece trace_options_string)433 void TraceConfig::InitializeFromStrings(StringPiece category_filter_string,
434 StringPiece trace_options_string) {
435 if (!category_filter_string.empty())
436 category_filter_.InitializeFromString(category_filter_string);
437
438 record_mode_ = RECORD_UNTIL_FULL;
439 trace_buffer_size_in_events_ = 0;
440 trace_buffer_size_in_kb_ = 0;
441 enable_systrace_ = false;
442 systrace_events_.clear();
443 enable_argument_filter_ = false;
444 if (!trace_options_string.empty()) {
445 std::vector<std::string> split =
446 SplitString(trace_options_string, ",", TRIM_WHITESPACE, SPLIT_WANT_ALL);
447 for (const std::string& token : split) {
448 if (token == kRecordUntilFull) {
449 record_mode_ = RECORD_UNTIL_FULL;
450 } else if (token == kRecordContinuously) {
451 record_mode_ = RECORD_CONTINUOUSLY;
452 } else if (token == kTraceToConsole) {
453 record_mode_ = ECHO_TO_CONSOLE;
454 } else if (token == kRecordAsMuchAsPossible) {
455 record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE;
456 } else if (token.find(kEnableSystrace) == 0) {
457 // Find optional events list.
458 const size_t length = token.length();
459 if (length == kEnableSystraceLength) {
460 // Use all predefined categories.
461 enable_systrace_ = true;
462 continue;
463 }
464 const auto system_events_not_trimmed =
465 token.substr(kEnableSystraceLength);
466 const auto system_events =
467 TrimString(system_events_not_trimmed, kWhitespaceASCII, TRIM_ALL);
468 if (system_events[0] != '=') {
469 LOG(ERROR) << "Failed to parse " << token;
470 continue;
471 }
472 enable_systrace_ = true;
473 const std::vector<std::string> split_systrace_events = SplitString(
474 system_events.substr(1), " ", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
475 for (const std::string& systrace_event : split_systrace_events)
476 systrace_events_.insert(systrace_event);
477 } else if (token == kEnableArgumentFilter) {
478 enable_argument_filter_ = true;
479 }
480 }
481 }
482
483 if (category_filter_.IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
484 SetDefaultMemoryDumpConfig();
485 }
486 }
487
SetMemoryDumpConfigFromConfigDict(const Value & memory_dump_config)488 void TraceConfig::SetMemoryDumpConfigFromConfigDict(
489 const Value& memory_dump_config) {
490 // Set allowed dump modes.
491 memory_dump_config_.allowed_dump_modes.clear();
492 const Value* allowed_modes_list =
493 memory_dump_config.FindListKey(kAllowedDumpModesParam);
494 if (allowed_modes_list) {
495 for (const Value& item : allowed_modes_list->GetList()) {
496 DCHECK(item.is_string());
497 memory_dump_config_.allowed_dump_modes.insert(
498 StringToMemoryDumpLevelOfDetail(item.GetString()));
499 }
500 } else {
501 // If allowed modes param is not given then allow all modes by default.
502 memory_dump_config_.allowed_dump_modes = GetDefaultAllowedMemoryDumpModes();
503 }
504
505 // Set triggers
506 memory_dump_config_.triggers.clear();
507 const Value* trigger_list = memory_dump_config.FindListKey(kTriggersParam);
508 if (trigger_list) {
509 for (const Value& trigger : trigger_list->GetList()) {
510 if (!trigger.is_dict())
511 continue;
512
513 MemoryDumpConfig::Trigger dump_config;
514 base::Optional<int> interval = trigger.FindIntKey(kMinTimeBetweenDumps);
515 if (!interval) {
516 // If "min_time_between_dumps_ms" param was not given, then the trace
517 // config uses old format where only periodic dumps are supported.
518 interval = trigger.FindIntKey(kPeriodicIntervalLegacyParam);
519 dump_config.trigger_type = MemoryDumpType::PERIODIC_INTERVAL;
520 } else {
521 const std::string* trigger_type_str =
522 trigger.FindStringKey(kTriggerTypeParam);
523 DCHECK(trigger_type_str);
524 dump_config.trigger_type = StringToMemoryDumpType(*trigger_type_str);
525 }
526 DCHECK(interval.has_value());
527 DCHECK_GT(*interval, 0);
528 dump_config.min_time_between_dumps_ms = static_cast<uint32_t>(*interval);
529
530 const std::string* level_of_detail_str =
531 trigger.FindStringKey(kTriggerModeParam);
532 DCHECK(level_of_detail_str);
533 dump_config.level_of_detail =
534 StringToMemoryDumpLevelOfDetail(*level_of_detail_str);
535
536 memory_dump_config_.triggers.push_back(dump_config);
537 }
538 }
539
540 // Set heap profiler options
541 const Value* heap_profiler_options =
542 memory_dump_config.FindDictKey(kHeapProfilerOptions);
543 if (heap_profiler_options) {
544 base::Optional<int> min_size_bytes =
545 heap_profiler_options->FindIntKey(kBreakdownThresholdBytes);
546 if (min_size_bytes && *min_size_bytes >= 0) {
547 memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes =
548 *min_size_bytes;
549 } else {
550 memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes =
551 MemoryDumpConfig::HeapProfiler::kDefaultBreakdownThresholdBytes;
552 }
553 }
554 }
555
SetDefaultMemoryDumpConfig()556 void TraceConfig::SetDefaultMemoryDumpConfig() {
557 memory_dump_config_.Clear();
558 memory_dump_config_.allowed_dump_modes = GetDefaultAllowedMemoryDumpModes();
559 }
560
SetProcessFilterConfig(const ProcessFilterConfig & config)561 void TraceConfig::SetProcessFilterConfig(const ProcessFilterConfig& config) {
562 process_filter_config_ = config;
563 }
564
SetHistogramNamesFromConfigList(const Value & histogram_names)565 void TraceConfig::SetHistogramNamesFromConfigList(
566 const Value& histogram_names) {
567 histogram_names_.clear();
568 for (const Value& value : histogram_names.GetList())
569 histogram_names_.insert(value.GetString());
570 }
571
SetEventFiltersFromConfigList(const Value & category_event_filters)572 void TraceConfig::SetEventFiltersFromConfigList(
573 const Value& category_event_filters) {
574 event_filters_.clear();
575
576 for (const Value& event_filter : category_event_filters.GetList()) {
577 if (!event_filter.is_dict())
578 continue;
579
580 const std::string* predicate_name =
581 event_filter.FindStringKey(kFilterPredicateParam);
582 CHECK(predicate_name) << "Invalid predicate name in category event filter.";
583
584 EventFilterConfig new_config(*predicate_name);
585 new_config.InitializeFromConfigDict(event_filter);
586 event_filters_.push_back(new_config);
587 }
588 }
589
ToValue() const590 Value TraceConfig::ToValue() const {
591 Value dict(Value::Type::DICTIONARY);
592 dict.SetStringKey(kRecordModeParam,
593 TraceConfig::TraceRecordModeToStr(record_mode_));
594 dict.SetBoolKey(kEnableSystraceParam, enable_systrace_);
595 dict.SetBoolKey(kEnableArgumentFilterParam, enable_argument_filter_);
596 if (trace_buffer_size_in_events_ > 0)
597 dict.SetIntKey(kTraceBufferSizeInEvents, trace_buffer_size_in_events_);
598 if (trace_buffer_size_in_kb_ > 0)
599 dict.SetIntKey(kTraceBufferSizeInKb, trace_buffer_size_in_kb_);
600
601 category_filter_.ToDict(&dict);
602 process_filter_config_.ToDict(&dict);
603
604 if (!event_filters_.empty()) {
605 std::vector<Value> filter_list;
606 for (const EventFilterConfig& filter : event_filters_) {
607 filter_list.emplace_back(Value::Type::DICTIONARY);
608 filter.ToDict(&filter_list.back());
609 }
610 dict.SetKey(kEventFiltersParam, Value(std::move(filter_list)));
611 }
612
613 if (category_filter_.IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
614 std::vector<Value> allowed_modes;
615 for (auto dump_mode : memory_dump_config_.allowed_dump_modes)
616 allowed_modes.emplace_back(MemoryDumpLevelOfDetailToString(dump_mode));
617
618 Value memory_dump_config(Value::Type::DICTIONARY);
619 memory_dump_config.SetKey(kAllowedDumpModesParam,
620 Value(std::move(allowed_modes)));
621
622 std::vector<Value> triggers_list;
623 for (const auto& config : memory_dump_config_.triggers) {
624 triggers_list.emplace_back(Value::Type::DICTIONARY);
625 Value& trigger_dict = triggers_list.back();
626
627 trigger_dict.SetStringKey(kTriggerTypeParam,
628 MemoryDumpTypeToString(config.trigger_type));
629 trigger_dict.SetIntKey(
630 kMinTimeBetweenDumps,
631 static_cast<int>(config.min_time_between_dumps_ms));
632 trigger_dict.SetStringKey(
633 kTriggerModeParam,
634 MemoryDumpLevelOfDetailToString(config.level_of_detail));
635 }
636
637 // Empty triggers will still be specified explicitly since it means that
638 // the periodic dumps are not enabled.
639 memory_dump_config.SetKey(kTriggersParam, Value(std::move(triggers_list)));
640
641 if (memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes !=
642 MemoryDumpConfig::HeapProfiler::kDefaultBreakdownThresholdBytes) {
643 Value options(Value::Type::DICTIONARY);
644 options.SetIntKey(
645 kBreakdownThresholdBytes,
646 memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes);
647 memory_dump_config.SetKey(kHeapProfilerOptions, std::move(options));
648 }
649 dict.SetKey(kMemoryDumpConfigParam, std::move(memory_dump_config));
650 }
651
652 if (!histogram_names_.empty()) {
653 std::vector<Value> histogram_names;
654 for (const std::string& histogram_name : histogram_names_)
655 histogram_names.emplace_back(histogram_name);
656 dict.SetKey(kHistogramNamesParam, Value(std::move(histogram_names)));
657 }
658
659 if (enable_systrace_) {
660 if (!systrace_events_.empty()) {
661 std::vector<Value> systrace_events;
662 for (const std::string& systrace_event : systrace_events_)
663 systrace_events.emplace_back(systrace_event);
664 dict.SetKey(kSystraceEventsParam, Value(std::move(systrace_events)));
665 }
666 }
667
668 return dict;
669 }
670
EnableSystraceEvent(const std::string & systrace_event)671 void TraceConfig::EnableSystraceEvent(const std::string& systrace_event) {
672 systrace_events_.insert(systrace_event);
673 }
674
EnableHistogram(const std::string & histogram_name)675 void TraceConfig::EnableHistogram(const std::string& histogram_name) {
676 histogram_names_.insert(histogram_name);
677 }
678
ToTraceOptionsString() const679 std::string TraceConfig::ToTraceOptionsString() const {
680 std::string ret;
681 switch (record_mode_) {
682 case RECORD_UNTIL_FULL:
683 ret = kRecordUntilFull;
684 break;
685 case RECORD_CONTINUOUSLY:
686 ret = kRecordContinuously;
687 break;
688 case RECORD_AS_MUCH_AS_POSSIBLE:
689 ret = kRecordAsMuchAsPossible;
690 break;
691 case ECHO_TO_CONSOLE:
692 ret = kTraceToConsole;
693 break;
694 default:
695 NOTREACHED();
696 }
697 if (enable_systrace_) {
698 ret += ",";
699 ret += kEnableSystrace;
700 bool first_param = true;
701 for (const std::string& systrace_event : systrace_events_) {
702 if (first_param) {
703 ret += "=";
704 first_param = false;
705 } else {
706 ret += " ";
707 }
708 ret = ret + systrace_event;
709 }
710 }
711 if (enable_argument_filter_) {
712 ret += ",";
713 ret += kEnableArgumentFilter;
714 }
715 return ret;
716 }
717
718 } // namespace trace_event
719 } // namespace base
720