// Copyright 2015 The Chromium OS 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 "perf_option_parser.h"
#include <algorithm>
#include <map>
#include "compat/string.h"
namespace quipper {
namespace {
enum class OptionType {
Boolean, // has no value
Value, // Uses another argument.
};
const std::map<string, OptionType>& GetPerfRecordOptions() {
static const auto* kPerfRecordOptions = new std::map<string, OptionType>{
{"-e", OptionType::Value},
{"--event", OptionType::Value},
{"--filter", OptionType::Value},
{"-p", OptionType::Value},
{"--pid", OptionType::Value},
{"-t", OptionType::Value},
{"--tid", OptionType::Value},
{"-r", OptionType::Value},
{"--realtime", OptionType::Value},
/* Banned: {"--no-buffering", OptionType::Boolean}, */
{"-R", OptionType::Boolean},
{"--raw-samples", OptionType::Boolean},
{"-a", OptionType::Boolean},
{"--all-cpus", OptionType::Boolean},
{"-C", OptionType::Value},
{"--cpu", OptionType::Value},
{"-c", OptionType::Value},
{"--count", OptionType::Value},
/* Banned: {"-o", OptionType::Value},
* {"--output", OptionType::Value}, */
{"-i", OptionType::Boolean},
{"--no-inherit", OptionType::Boolean},
{"-F", OptionType::Value},
{"--freq", OptionType::Value},
/* Banned: {"-m", OptionType::Value},
* {"--mmap-pages", OptionType::Value}, */
{"--group", OptionType::Boolean}, /* new? */
{"-g", OptionType::Boolean}, /* NB: in stat, this is short for --group */
{"--call-graph", OptionType::Value},
/* Banned: {"-v", OptionType::Boolean},
* {"--verbose", OptionType::Boolean}, */
/* Banned: {"-q", OptionType::Boolean},
* {"--quiet", OptionType::Boolean}, */
{"-s", OptionType::Boolean},
{"--stat", OptionType::Boolean},
{"-d", OptionType::Boolean},
{"--data", OptionType::Boolean},
{"-T", OptionType::Boolean},
{"--timestamp", OptionType::Boolean},
{"-P", OptionType::Boolean}, /* new? */
{"--period", OptionType::Boolean}, /* new? */
{"-n", OptionType::Boolean},
{"--no-samples", OptionType::Boolean},
{"-N", OptionType::Boolean},
{"--no-buildid-cache", OptionType::Boolean},
{"-B", OptionType::Boolean}, /* new? */
{"--no-buildid", OptionType::Boolean}, /* new? */
{"-G", OptionType::Value},
{"--cgroup", OptionType::Value},
/* Changed between v3.13 to v3.14 from:
{"-D", OptionType::Boolean},
{"--no-delay", OptionType::Boolean},
* to:
{"-D", OptionType::Value},
{"--delay", OptionType::Value},
* ... So just ban it until the new option is universal on ChromeOS perf.
*/
{"-u", OptionType::Value},
{"--uid", OptionType::Value},
{"-b", OptionType::Boolean},
{"--branch-any", OptionType::Boolean},
{"-j", OptionType::Value},
{"--branch-filter", OptionType::Value},
{"-W", OptionType::Boolean},
{"--weight", OptionType::Boolean},
{"--transaction", OptionType::Boolean},
/* Banned: {"--per-thread", OptionType::Boolean},
* Only briefly present in v3.12-v3.13, but also banned:
* {"--force-per-cpu", OptionType::Boolean}, */
/* Banned: {"-I", OptionType::Boolean}, // may reveal PII
{"--intr-regs", OptionType::Boolean}, */
{"--running-time", OptionType::Boolean},
{"-k", OptionType::Value},
{"--clockid", OptionType::Value},
{"-S", OptionType::Value},
{"--snapshot", OptionType::Value},
{"--pfm-events", OptionType::Value},
};
return *kPerfRecordOptions;
}
const std::map<string, OptionType>& GetPerfStatOptions() {
static const auto* kPerfStatOptions = new std::map<string, OptionType>{
{"-T", OptionType::Boolean},
{"--transaction", OptionType::Boolean},
{"-e", OptionType::Value},
{"--event", OptionType::Value},
{"--filter", OptionType::Value},
{"-i", OptionType::Boolean},
{"--no-inherit", OptionType::Boolean},
{"-p", OptionType::Value},
{"--pid", OptionType::Value},
{"-t", OptionType::Value},
{"--tid", OptionType::Value},
{"-a", OptionType::Boolean},
{"--all-cpus", OptionType::Boolean},
{"-g", OptionType::Boolean},
{"--group", OptionType::Boolean},
{"-c", OptionType::Boolean},
{"--scale", OptionType::Boolean},
/* Banned: {"-v", OptionType::Boolean},
* {"--verbose", OptionType::Boolean}, */
/* Banned: {"-r", OptionType::Value},
* {"--repeat", OptionType::Value}, */
/* Banned: {"-n", OptionType::Boolean},
* {"--null", OptionType::Boolean}, */
/* Banned: {"-d", OptionType::Boolean},
* {"--detailed", OptionType::Boolean}, */
/* Banned: {"-S", OptionType::Boolean},
* {"--sync", OptionType::Boolean}, */
/* Banned: {"-B", OptionType::Boolean},
* {"--big-num", OptionType::Boolean}, */
{"-C", OptionType::Value},
{"--cpu", OptionType::Value},
{"-A", OptionType::Boolean},
{"--no-aggr", OptionType::Boolean},
/* Banned: {"-x", OptionType::Value},
* {"--field-separator", OptionType::Value}, */
{"-G", OptionType::Value},
{"--cgroup", OptionType::Value},
/* Banned: {"-o", OptionType::Value},
* {"--output", OptionType::Value}, */
/* Banned: {"--append", OptionType::Value}, */
/* Banned: {"--log-fd", OptionType::Value}, */
/* Banned: {"--pre", OptionType::Value}, */
/* Banned: {"--post", OptionType::Value}, */
/* Banned: {"-I", OptionType::Value},
* {"--interval-print", OptionType::Value}, */
{"--per-socket", OptionType::Boolean},
{"--per-core", OptionType::Boolean},
{"-D", OptionType::Value},
{"--delay", OptionType::Value},
};
return *kPerfStatOptions;
}
const std::map<string, OptionType>& GetPerfMemOptions() {
static const auto* kPerfMemOptions = new std::map<string, OptionType>{
{"-t", OptionType::Value}, {"--type", OptionType::Value},
{"-D", OptionType::Boolean}, {"--dump-raw-samples", OptionType::Boolean},
{"-x", OptionType::Value}, {"--field-separator", OptionType::Value},
{"-C", OptionType::Value}, {"--cpu-list", OptionType::Value},
};
return *kPerfMemOptions;
}
bool ValidatePerfCommandLineOptions(
std::vector<string>::const_iterator begin_arg,
std::vector<string>::const_iterator end_arg,
const std::map<string, OptionType>& options) {
for (auto args_iter = begin_arg; args_iter != end_arg; ++args_iter) {
const auto& it = options.find(*args_iter);
if (it == options.end()) {
return false;
}
if (it->second == OptionType::Value) {
++args_iter;
if (args_iter == end_arg) {
return false; // missing value
}
}
}
return true;
}
} // namespace
bool ValidatePerfCommandLine(const std::vector<string>& args) {
if (args.size() < 2) {
return false;
}
if (args[0] != "perf") {
return false;
}
if (args[1] == "record") {
return ValidatePerfCommandLineOptions(args.begin() + 2, args.end(),
GetPerfRecordOptions());
}
if (args[1] == "mem") {
auto record_arg_iter = std::find(args.begin(), args.end(), "record");
if (record_arg_iter == args.end()) return false;
return ValidatePerfCommandLineOptions(args.begin() + 2, record_arg_iter,
GetPerfMemOptions()) &&
ValidatePerfCommandLineOptions(record_arg_iter + 1, args.end(),
GetPerfRecordOptions());
}
if (args[1] == "stat") {
return ValidatePerfCommandLineOptions(args.begin() + 2, args.end(),
GetPerfStatOptions());
}
return false;
}
} // namespace quipper