/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "src/perfetto_cmd/config.h" #include #include "perfetto/base/logging.h" #include "perfetto/ext/base/string_utils.h" #include "perfetto/tracing/core/data_source_config.h" #include "perfetto/tracing/core/trace_config.h" #include "protos/perfetto/config/ftrace/ftrace_config.gen.h" namespace perfetto { namespace { using ValueUnit = std::pair; using UnitMultipler = std::pair; bool SplitValueAndUnit(const std::string& arg, ValueUnit* out) { char* end; if (arg.empty()) return false; out->first = strtoull(arg.c_str(), &end, 10); if (end == arg.data()) return false; std::string unit = arg.substr(static_cast(end - arg.data())); out->second = std::move(unit); return true; } bool ConvertValue(const std::string& arg, std::vector units, uint64_t* out) { if (arg.empty()) { *out = 0; return true; } if (arg == "0") { *out = 0; return true; } ValueUnit value_unit{}; if (!SplitValueAndUnit(arg, &value_unit)) return false; for (const auto& unit_multiplier : units) { if (value_unit.second != unit_multiplier.first) continue; *out = value_unit.first * unit_multiplier.second; return true; } return false; } bool ConvertTimeToMs(const std::string& arg, uint64_t* out) { return ConvertValue( arg, { {"ms", 1}, {"s", 1000}, {"m", 1000 * 60}, {"h", 1000 * 60 * 60}, }, out); } bool ConvertSizeToKb(const std::string& arg, uint64_t* out) { return ConvertValue(arg, { {"kb", 1}, {"mb", 1024}, {"gb", 1024 * 1024}, {"k", 1}, {"m", 1024}, {"g", 1024 * 1024}, }, out); } } // namespace bool CreateConfigFromOptions(const ConfigOptions& options, TraceConfig* config) { uint64_t duration_ms = 0; if (!ConvertTimeToMs(options.time, &duration_ms)) { PERFETTO_ELOG("--time argument is invalid"); return false; } uint64_t buffer_size_kb = 0; if (!ConvertSizeToKb(options.buffer_size, &buffer_size_kb)) { PERFETTO_ELOG("--buffer argument is invalid"); return false; } uint64_t max_file_size_kb = 0; if (!ConvertSizeToKb(options.max_file_size, &max_file_size_kb)) { PERFETTO_ELOG("--size argument is invalid"); return false; } std::vector ftrace_events; std::vector atrace_categories; std::vector atrace_apps = options.atrace_apps; for (const auto& category : options.categories) { if (base::Contains(category, '/')) { ftrace_events.push_back(category); } else { atrace_categories.push_back(category); } // For the gfx category, also add the frame timeline data source // as it's very useful for debugging gfx issues. if (category == "gfx") { auto* frame_timeline = config->add_data_sources(); frame_timeline->mutable_config()->set_name( "android.surfaceflinger.frametimeline"); } } config->set_duration_ms(static_cast(duration_ms)); config->set_max_file_size_bytes(max_file_size_kb * 1024); config->set_flush_period_ms(30 * 1000); if (max_file_size_kb) config->set_write_into_file(true); config->add_buffers()->set_size_kb(static_cast(buffer_size_kb)); auto* ds_config = config->add_data_sources()->mutable_config(); ds_config->set_name("linux.ftrace"); protos::gen::FtraceConfig ftrace_cfg; for (const auto& evt : ftrace_events) ftrace_cfg.add_ftrace_events(evt); for (const auto& cat : atrace_categories) ftrace_cfg.add_atrace_categories(cat); for (const auto& app : atrace_apps) ftrace_cfg.add_atrace_apps(app); ds_config->set_ftrace_config_raw(ftrace_cfg.SerializeAsString()); auto* ps_config = config->add_data_sources()->mutable_config(); ps_config->set_name("linux.process_stats"); ps_config->set_target_buffer(0); return true; } } // namespace perfetto