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 <utility>
10
11 #include "base/json/json_reader.h"
12 #include "base/json/json_writer.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/strings/string_split.h"
15 #include "base/trace_event/memory_dump_manager.h"
16 #include "base/trace_event/memory_dump_request_args.h"
17 #include "base/trace_event/trace_event.h"
18
19 namespace base {
20 namespace trace_event {
21
22 namespace {
23
24 // String options that can be used to initialize TraceOptions.
25 const char kRecordUntilFull[] = "record-until-full";
26 const char kRecordContinuously[] = "record-continuously";
27 const char kRecordAsMuchAsPossible[] = "record-as-much-as-possible";
28 const char kTraceToConsole[] = "trace-to-console";
29 const char kEnableSystrace[] = "enable-systrace";
30 const char kEnableArgumentFilter[] = "enable-argument-filter";
31
32 // String parameters that can be used to parse the trace config string.
33 const char kRecordModeParam[] = "record_mode";
34 const char kEnableSystraceParam[] = "enable_systrace";
35 const char kEnableArgumentFilterParam[] = "enable_argument_filter";
36
37 // String parameters that is used to parse memory dump config in trace config
38 // string.
39 const char kMemoryDumpConfigParam[] = "memory_dump_config";
40 const char kAllowedDumpModesParam[] = "allowed_dump_modes";
41 const char kTriggersParam[] = "triggers";
42 const char kTriggerModeParam[] = "mode";
43 const char kMinTimeBetweenDumps[] = "min_time_between_dumps_ms";
44 const char kTriggerTypeParam[] = "type";
45 const char kPeriodicIntervalLegacyParam[] = "periodic_interval_ms";
46 const char kHeapProfilerOptions[] = "heap_profiler_options";
47 const char kBreakdownThresholdBytes[] = "breakdown_threshold_bytes";
48
49 // String parameters used to parse category event filters.
50 const char kEventFiltersParam[] = "event_filters";
51 const char kFilterPredicateParam[] = "filter_predicate";
52 const char kFilterArgsParam[] = "filter_args";
53
54 // Default configuration of memory dumps.
55 const TraceConfig::MemoryDumpConfig::Trigger kDefaultHeavyMemoryDumpTrigger = {
56 2000, // min_time_between_dumps_ms
57 MemoryDumpLevelOfDetail::DETAILED, MemoryDumpType::PERIODIC_INTERVAL};
58 const TraceConfig::MemoryDumpConfig::Trigger kDefaultLightMemoryDumpTrigger = {
59 250, // min_time_between_dumps_ms
60 MemoryDumpLevelOfDetail::LIGHT, MemoryDumpType::PERIODIC_INTERVAL};
61
62 class ConvertableTraceConfigToTraceFormat
63 : public base::trace_event::ConvertableToTraceFormat {
64 public:
ConvertableTraceConfigToTraceFormat(const TraceConfig & trace_config)65 explicit ConvertableTraceConfigToTraceFormat(const TraceConfig& trace_config)
66 : trace_config_(trace_config) {}
67
~ConvertableTraceConfigToTraceFormat()68 ~ConvertableTraceConfigToTraceFormat() override {}
69
AppendAsTraceFormat(std::string * out) const70 void AppendAsTraceFormat(std::string* out) const override {
71 out->append(trace_config_.ToString());
72 }
73
74 private:
75 const TraceConfig trace_config_;
76 };
77
GetDefaultAllowedMemoryDumpModes()78 std::set<MemoryDumpLevelOfDetail> GetDefaultAllowedMemoryDumpModes() {
79 std::set<MemoryDumpLevelOfDetail> all_modes;
80 for (uint32_t mode = static_cast<uint32_t>(MemoryDumpLevelOfDetail::FIRST);
81 mode <= static_cast<uint32_t>(MemoryDumpLevelOfDetail::LAST); mode++) {
82 all_modes.insert(static_cast<MemoryDumpLevelOfDetail>(mode));
83 }
84 return all_modes;
85 }
86
87 } // namespace
88
HeapProfiler()89 TraceConfig::MemoryDumpConfig::HeapProfiler::HeapProfiler()
90 : breakdown_threshold_bytes(kDefaultBreakdownThresholdBytes) {}
91
Clear()92 void TraceConfig::MemoryDumpConfig::HeapProfiler::Clear() {
93 breakdown_threshold_bytes = kDefaultBreakdownThresholdBytes;
94 }
95
ResetMemoryDumpConfig(const TraceConfig::MemoryDumpConfig & memory_dump_config)96 void TraceConfig::ResetMemoryDumpConfig(
97 const TraceConfig::MemoryDumpConfig& memory_dump_config) {
98 memory_dump_config_.Clear();
99 memory_dump_config_ = memory_dump_config;
100 }
101
MemoryDumpConfig()102 TraceConfig::MemoryDumpConfig::MemoryDumpConfig() {}
103
104 TraceConfig::MemoryDumpConfig::MemoryDumpConfig(
105 const MemoryDumpConfig& other) = default;
106
~MemoryDumpConfig()107 TraceConfig::MemoryDumpConfig::~MemoryDumpConfig() {}
108
Clear()109 void TraceConfig::MemoryDumpConfig::Clear() {
110 allowed_dump_modes.clear();
111 triggers.clear();
112 heap_profiler_options.Clear();
113 }
114
Merge(const TraceConfig::MemoryDumpConfig & config)115 void TraceConfig::MemoryDumpConfig::Merge(
116 const TraceConfig::MemoryDumpConfig& config) {
117 triggers.insert(triggers.end(), config.triggers.begin(),
118 config.triggers.end());
119 allowed_dump_modes.insert(config.allowed_dump_modes.begin(),
120 config.allowed_dump_modes.end());
121 heap_profiler_options.breakdown_threshold_bytes =
122 std::min(heap_profiler_options.breakdown_threshold_bytes,
123 config.heap_profiler_options.breakdown_threshold_bytes);
124 }
125
EventFilterConfig(const std::string & predicate_name)126 TraceConfig::EventFilterConfig::EventFilterConfig(
127 const std::string& predicate_name)
128 : predicate_name_(predicate_name) {}
129
~EventFilterConfig()130 TraceConfig::EventFilterConfig::~EventFilterConfig() {}
131
EventFilterConfig(const EventFilterConfig & tc)132 TraceConfig::EventFilterConfig::EventFilterConfig(const EventFilterConfig& tc) {
133 *this = tc;
134 }
135
operator =(const TraceConfig::EventFilterConfig & rhs)136 TraceConfig::EventFilterConfig& TraceConfig::EventFilterConfig::operator=(
137 const TraceConfig::EventFilterConfig& rhs) {
138 if (this == &rhs)
139 return *this;
140
141 predicate_name_ = rhs.predicate_name_;
142 category_filter_ = rhs.category_filter_;
143
144 if (rhs.args_)
145 args_ = rhs.args_->CreateDeepCopy();
146
147 return *this;
148 }
149
InitializeFromConfigDict(const base::DictionaryValue * event_filter)150 void TraceConfig::EventFilterConfig::InitializeFromConfigDict(
151 const base::DictionaryValue* event_filter) {
152 category_filter_.InitializeFromConfigDict(*event_filter);
153
154 const base::DictionaryValue* args_dict = nullptr;
155 if (event_filter->GetDictionary(kFilterArgsParam, &args_dict))
156 args_ = args_dict->CreateDeepCopy();
157 }
158
SetCategoryFilter(const TraceConfigCategoryFilter & category_filter)159 void TraceConfig::EventFilterConfig::SetCategoryFilter(
160 const TraceConfigCategoryFilter& category_filter) {
161 category_filter_ = category_filter;
162 }
163
ToDict(DictionaryValue * filter_dict) const164 void TraceConfig::EventFilterConfig::ToDict(
165 DictionaryValue* filter_dict) const {
166 filter_dict->SetString(kFilterPredicateParam, predicate_name());
167
168 category_filter_.ToDict(filter_dict);
169
170 if (args_)
171 filter_dict->Set(kFilterArgsParam, args_->CreateDeepCopy());
172 }
173
GetArgAsSet(const char * key,std::unordered_set<std::string> * out_set) const174 bool TraceConfig::EventFilterConfig::GetArgAsSet(
175 const char* key,
176 std::unordered_set<std::string>* out_set) const {
177 const ListValue* list = nullptr;
178 if (!args_->GetList(key, &list))
179 return false;
180 for (size_t i = 0; i < list->GetSize(); ++i) {
181 std::string value;
182 if (list->GetString(i, &value))
183 out_set->insert(value);
184 }
185 return true;
186 }
187
IsCategoryGroupEnabled(const StringPiece & category_group_name) const188 bool TraceConfig::EventFilterConfig::IsCategoryGroupEnabled(
189 const StringPiece& category_group_name) const {
190 return category_filter_.IsCategoryGroupEnabled(category_group_name);
191 }
192
TraceConfig()193 TraceConfig::TraceConfig() {
194 InitializeDefault();
195 }
196
TraceConfig(StringPiece category_filter_string,StringPiece trace_options_string)197 TraceConfig::TraceConfig(StringPiece category_filter_string,
198 StringPiece trace_options_string) {
199 InitializeFromStrings(category_filter_string, trace_options_string);
200 }
201
TraceConfig(StringPiece category_filter_string,TraceRecordMode record_mode)202 TraceConfig::TraceConfig(StringPiece category_filter_string,
203 TraceRecordMode record_mode) {
204 std::string trace_options_string;
205 switch (record_mode) {
206 case RECORD_UNTIL_FULL:
207 trace_options_string = kRecordUntilFull;
208 break;
209 case RECORD_CONTINUOUSLY:
210 trace_options_string = kRecordContinuously;
211 break;
212 case RECORD_AS_MUCH_AS_POSSIBLE:
213 trace_options_string = kRecordAsMuchAsPossible;
214 break;
215 case ECHO_TO_CONSOLE:
216 trace_options_string = kTraceToConsole;
217 break;
218 default:
219 NOTREACHED();
220 }
221 InitializeFromStrings(category_filter_string, trace_options_string);
222 }
223
TraceConfig(const DictionaryValue & config)224 TraceConfig::TraceConfig(const DictionaryValue& config) {
225 InitializeFromConfigDict(config);
226 }
227
TraceConfig(StringPiece config_string)228 TraceConfig::TraceConfig(StringPiece config_string) {
229 if (!config_string.empty())
230 InitializeFromConfigString(config_string);
231 else
232 InitializeDefault();
233 }
234
TraceConfig(const TraceConfig & tc)235 TraceConfig::TraceConfig(const TraceConfig& tc)
236 : record_mode_(tc.record_mode_),
237 enable_systrace_(tc.enable_systrace_),
238 enable_argument_filter_(tc.enable_argument_filter_),
239 category_filter_(tc.category_filter_),
240 memory_dump_config_(tc.memory_dump_config_),
241 event_filters_(tc.event_filters_) {}
242
~TraceConfig()243 TraceConfig::~TraceConfig() {
244 }
245
operator =(const TraceConfig & rhs)246 TraceConfig& TraceConfig::operator=(const TraceConfig& rhs) {
247 if (this == &rhs)
248 return *this;
249
250 record_mode_ = rhs.record_mode_;
251 enable_systrace_ = rhs.enable_systrace_;
252 enable_argument_filter_ = rhs.enable_argument_filter_;
253 category_filter_ = rhs.category_filter_;
254 memory_dump_config_ = rhs.memory_dump_config_;
255 event_filters_ = rhs.event_filters_;
256 return *this;
257 }
258
GetSyntheticDelayValues() const259 const TraceConfig::StringList& TraceConfig::GetSyntheticDelayValues() const {
260 return category_filter_.synthetic_delays();
261 }
262
ToString() const263 std::string TraceConfig::ToString() const {
264 std::unique_ptr<DictionaryValue> dict = ToDict();
265 std::string json;
266 JSONWriter::Write(*dict, &json);
267 return json;
268 }
269
270 std::unique_ptr<ConvertableToTraceFormat>
AsConvertableToTraceFormat() const271 TraceConfig::AsConvertableToTraceFormat() const {
272 return MakeUnique<ConvertableTraceConfigToTraceFormat>(*this);
273 }
274
ToCategoryFilterString() const275 std::string TraceConfig::ToCategoryFilterString() const {
276 return category_filter_.ToFilterString();
277 }
278
IsCategoryGroupEnabled(const StringPiece & category_group_name) const279 bool TraceConfig::IsCategoryGroupEnabled(
280 const StringPiece& category_group_name) const {
281 // TraceLog should call this method only as part of enabling/disabling
282 // categories.
283 return category_filter_.IsCategoryGroupEnabled(category_group_name);
284 }
285
Merge(const TraceConfig & config)286 void TraceConfig::Merge(const TraceConfig& config) {
287 if (record_mode_ != config.record_mode_
288 || enable_systrace_ != config.enable_systrace_
289 || enable_argument_filter_ != config.enable_argument_filter_) {
290 DLOG(ERROR) << "Attempting to merge trace config with a different "
291 << "set of options.";
292 }
293
294 category_filter_.Merge(config.category_filter_);
295
296 memory_dump_config_.Merge(config.memory_dump_config_);
297
298 event_filters_.insert(event_filters_.end(), config.event_filters().begin(),
299 config.event_filters().end());
300 }
301
Clear()302 void TraceConfig::Clear() {
303 record_mode_ = RECORD_UNTIL_FULL;
304 enable_systrace_ = false;
305 enable_argument_filter_ = false;
306 category_filter_.Clear();
307 memory_dump_config_.Clear();
308 event_filters_.clear();
309 }
310
InitializeDefault()311 void TraceConfig::InitializeDefault() {
312 record_mode_ = RECORD_UNTIL_FULL;
313 enable_systrace_ = false;
314 enable_argument_filter_ = false;
315 }
316
InitializeFromConfigDict(const DictionaryValue & dict)317 void TraceConfig::InitializeFromConfigDict(const DictionaryValue& dict) {
318 record_mode_ = RECORD_UNTIL_FULL;
319 std::string record_mode;
320 if (dict.GetString(kRecordModeParam, &record_mode)) {
321 if (record_mode == kRecordUntilFull) {
322 record_mode_ = RECORD_UNTIL_FULL;
323 } else if (record_mode == kRecordContinuously) {
324 record_mode_ = RECORD_CONTINUOUSLY;
325 } else if (record_mode == kTraceToConsole) {
326 record_mode_ = ECHO_TO_CONSOLE;
327 } else if (record_mode == kRecordAsMuchAsPossible) {
328 record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE;
329 }
330 }
331
332 bool val;
333 enable_systrace_ = dict.GetBoolean(kEnableSystraceParam, &val) ? val : false;
334 enable_argument_filter_ =
335 dict.GetBoolean(kEnableArgumentFilterParam, &val) ? val : false;
336
337 category_filter_.InitializeFromConfigDict(dict);
338
339 const base::ListValue* category_event_filters = nullptr;
340 if (dict.GetList(kEventFiltersParam, &category_event_filters))
341 SetEventFiltersFromConfigList(*category_event_filters);
342
343 if (category_filter_.IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
344 // If dump triggers not set, the client is using the legacy with just
345 // category enabled. So, use the default periodic dump config.
346 const DictionaryValue* memory_dump_config = nullptr;
347 if (dict.GetDictionary(kMemoryDumpConfigParam, &memory_dump_config))
348 SetMemoryDumpConfigFromConfigDict(*memory_dump_config);
349 else
350 SetDefaultMemoryDumpConfig();
351 }
352 }
353
InitializeFromConfigString(StringPiece config_string)354 void TraceConfig::InitializeFromConfigString(StringPiece config_string) {
355 auto dict = DictionaryValue::From(JSONReader::Read(config_string));
356 if (dict)
357 InitializeFromConfigDict(*dict);
358 else
359 InitializeDefault();
360 }
361
InitializeFromStrings(StringPiece category_filter_string,StringPiece trace_options_string)362 void TraceConfig::InitializeFromStrings(StringPiece category_filter_string,
363 StringPiece trace_options_string) {
364 if (!category_filter_string.empty())
365 category_filter_.InitializeFromString(category_filter_string);
366
367 record_mode_ = RECORD_UNTIL_FULL;
368 enable_systrace_ = false;
369 enable_argument_filter_ = false;
370 if (!trace_options_string.empty()) {
371 std::vector<std::string> split =
372 SplitString(trace_options_string, ",", TRIM_WHITESPACE, SPLIT_WANT_ALL);
373 for (const std::string& token : split) {
374 if (token == kRecordUntilFull) {
375 record_mode_ = RECORD_UNTIL_FULL;
376 } else if (token == kRecordContinuously) {
377 record_mode_ = RECORD_CONTINUOUSLY;
378 } else if (token == kTraceToConsole) {
379 record_mode_ = ECHO_TO_CONSOLE;
380 } else if (token == kRecordAsMuchAsPossible) {
381 record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE;
382 } else if (token == kEnableSystrace) {
383 enable_systrace_ = true;
384 } else if (token == kEnableArgumentFilter) {
385 enable_argument_filter_ = true;
386 }
387 }
388 }
389
390 if (category_filter_.IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
391 SetDefaultMemoryDumpConfig();
392 }
393 }
394
SetMemoryDumpConfigFromConfigDict(const DictionaryValue & memory_dump_config)395 void TraceConfig::SetMemoryDumpConfigFromConfigDict(
396 const DictionaryValue& memory_dump_config) {
397 // Set allowed dump modes.
398 memory_dump_config_.allowed_dump_modes.clear();
399 const ListValue* allowed_modes_list;
400 if (memory_dump_config.GetList(kAllowedDumpModesParam, &allowed_modes_list)) {
401 for (size_t i = 0; i < allowed_modes_list->GetSize(); ++i) {
402 std::string level_of_detail_str;
403 allowed_modes_list->GetString(i, &level_of_detail_str);
404 memory_dump_config_.allowed_dump_modes.insert(
405 StringToMemoryDumpLevelOfDetail(level_of_detail_str));
406 }
407 } else {
408 // If allowed modes param is not given then allow all modes by default.
409 memory_dump_config_.allowed_dump_modes = GetDefaultAllowedMemoryDumpModes();
410 }
411
412 // Set triggers
413 memory_dump_config_.triggers.clear();
414 const ListValue* trigger_list = nullptr;
415 if (memory_dump_config.GetList(kTriggersParam, &trigger_list) &&
416 trigger_list->GetSize() > 0) {
417 for (size_t i = 0; i < trigger_list->GetSize(); ++i) {
418 const DictionaryValue* trigger = nullptr;
419 if (!trigger_list->GetDictionary(i, &trigger))
420 continue;
421
422 MemoryDumpConfig::Trigger dump_config;
423 int interval = 0;
424 if (!trigger->GetInteger(kMinTimeBetweenDumps, &interval)) {
425 // If "min_time_between_dumps_ms" param was not given, then the trace
426 // config uses old format where only periodic dumps are supported.
427 trigger->GetInteger(kPeriodicIntervalLegacyParam, &interval);
428 dump_config.trigger_type = MemoryDumpType::PERIODIC_INTERVAL;
429 } else {
430 std::string trigger_type_str;
431 trigger->GetString(kTriggerTypeParam, &trigger_type_str);
432 dump_config.trigger_type = StringToMemoryDumpType(trigger_type_str);
433 }
434 DCHECK_GT(interval, 0);
435 dump_config.min_time_between_dumps_ms = static_cast<uint32_t>(interval);
436
437 std::string level_of_detail_str;
438 trigger->GetString(kTriggerModeParam, &level_of_detail_str);
439 dump_config.level_of_detail =
440 StringToMemoryDumpLevelOfDetail(level_of_detail_str);
441
442 memory_dump_config_.triggers.push_back(dump_config);
443 }
444 }
445
446 // Set heap profiler options
447 const DictionaryValue* heap_profiler_options = nullptr;
448 if (memory_dump_config.GetDictionary(kHeapProfilerOptions,
449 &heap_profiler_options)) {
450 int min_size_bytes = 0;
451 if (heap_profiler_options->GetInteger(kBreakdownThresholdBytes,
452 &min_size_bytes)
453 && min_size_bytes >= 0) {
454 memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes =
455 static_cast<size_t>(min_size_bytes);
456 } else {
457 memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes =
458 MemoryDumpConfig::HeapProfiler::kDefaultBreakdownThresholdBytes;
459 }
460 }
461 }
462
SetDefaultMemoryDumpConfig()463 void TraceConfig::SetDefaultMemoryDumpConfig() {
464 memory_dump_config_.Clear();
465 memory_dump_config_.triggers.push_back(kDefaultHeavyMemoryDumpTrigger);
466 memory_dump_config_.triggers.push_back(kDefaultLightMemoryDumpTrigger);
467 memory_dump_config_.allowed_dump_modes = GetDefaultAllowedMemoryDumpModes();
468 }
469
SetEventFiltersFromConfigList(const base::ListValue & category_event_filters)470 void TraceConfig::SetEventFiltersFromConfigList(
471 const base::ListValue& category_event_filters) {
472 event_filters_.clear();
473
474 for (size_t event_filter_index = 0;
475 event_filter_index < category_event_filters.GetSize();
476 ++event_filter_index) {
477 const base::DictionaryValue* event_filter = nullptr;
478 if (!category_event_filters.GetDictionary(event_filter_index,
479 &event_filter))
480 continue;
481
482 std::string predicate_name;
483 CHECK(event_filter->GetString(kFilterPredicateParam, &predicate_name))
484 << "Invalid predicate name in category event filter.";
485
486 EventFilterConfig new_config(predicate_name);
487 new_config.InitializeFromConfigDict(event_filter);
488 event_filters_.push_back(new_config);
489 }
490 }
491
ToDict() const492 std::unique_ptr<DictionaryValue> TraceConfig::ToDict() const {
493 auto dict = MakeUnique<DictionaryValue>();
494 switch (record_mode_) {
495 case RECORD_UNTIL_FULL:
496 dict->SetString(kRecordModeParam, kRecordUntilFull);
497 break;
498 case RECORD_CONTINUOUSLY:
499 dict->SetString(kRecordModeParam, kRecordContinuously);
500 break;
501 case RECORD_AS_MUCH_AS_POSSIBLE:
502 dict->SetString(kRecordModeParam, kRecordAsMuchAsPossible);
503 break;
504 case ECHO_TO_CONSOLE:
505 dict->SetString(kRecordModeParam, kTraceToConsole);
506 break;
507 default:
508 NOTREACHED();
509 }
510
511 dict->SetBoolean(kEnableSystraceParam, enable_systrace_);
512 dict->SetBoolean(kEnableArgumentFilterParam, enable_argument_filter_);
513
514 category_filter_.ToDict(dict.get());
515
516 if (!event_filters_.empty()) {
517 std::unique_ptr<base::ListValue> filter_list(new base::ListValue());
518 for (const EventFilterConfig& filter : event_filters_) {
519 std::unique_ptr<base::DictionaryValue> filter_dict(
520 new base::DictionaryValue());
521 filter.ToDict(filter_dict.get());
522 filter_list->Append(std::move(filter_dict));
523 }
524 dict->Set(kEventFiltersParam, std::move(filter_list));
525 }
526
527 if (category_filter_.IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
528 auto allowed_modes = MakeUnique<ListValue>();
529 for (auto dump_mode : memory_dump_config_.allowed_dump_modes)
530 allowed_modes->AppendString(MemoryDumpLevelOfDetailToString(dump_mode));
531
532 auto memory_dump_config = MakeUnique<DictionaryValue>();
533 memory_dump_config->Set(kAllowedDumpModesParam, std::move(allowed_modes));
534
535 auto triggers_list = MakeUnique<ListValue>();
536 for (const auto& config : memory_dump_config_.triggers) {
537 auto trigger_dict = MakeUnique<DictionaryValue>();
538 trigger_dict->SetString(kTriggerTypeParam,
539 MemoryDumpTypeToString(config.trigger_type));
540 trigger_dict->SetInteger(
541 kMinTimeBetweenDumps,
542 static_cast<int>(config.min_time_between_dumps_ms));
543 trigger_dict->SetString(
544 kTriggerModeParam,
545 MemoryDumpLevelOfDetailToString(config.level_of_detail));
546 triggers_list->Append(std::move(trigger_dict));
547 }
548
549 // Empty triggers will still be specified explicitly since it means that
550 // the periodic dumps are not enabled.
551 memory_dump_config->Set(kTriggersParam, std::move(triggers_list));
552
553 if (memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes !=
554 MemoryDumpConfig::HeapProfiler::kDefaultBreakdownThresholdBytes) {
555 auto options = MakeUnique<DictionaryValue>();
556 options->SetInteger(
557 kBreakdownThresholdBytes,
558 memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes);
559 memory_dump_config->Set(kHeapProfilerOptions, std::move(options));
560 }
561 dict->Set(kMemoryDumpConfigParam, std::move(memory_dump_config));
562 }
563 return dict;
564 }
565
ToTraceOptionsString() const566 std::string TraceConfig::ToTraceOptionsString() const {
567 std::string ret;
568 switch (record_mode_) {
569 case RECORD_UNTIL_FULL:
570 ret = kRecordUntilFull;
571 break;
572 case RECORD_CONTINUOUSLY:
573 ret = kRecordContinuously;
574 break;
575 case RECORD_AS_MUCH_AS_POSSIBLE:
576 ret = kRecordAsMuchAsPossible;
577 break;
578 case ECHO_TO_CONSOLE:
579 ret = kTraceToConsole;
580 break;
581 default:
582 NOTREACHED();
583 }
584 if (enable_systrace_)
585 ret = ret + "," + kEnableSystrace;
586 if (enable_argument_filter_)
587 ret = ret + "," + kEnableArgumentFilter;
588 return ret;
589 }
590
591 } // namespace trace_event
592 } // namespace base
593