1 // Copyright 2015 The Chromium OS 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 #include "perf_option_parser.h"
5 
6 #include <algorithm>
7 #include <map>
8 
9 #include "compat/string.h"
10 
11 namespace quipper {
12 
13 namespace {
14 
15 enum class OptionType {
16   Boolean,  // has no value
17   Value,    // Uses another argument.
18 };
19 
20 const std::map<string, OptionType>& GetPerfRecordOptions() {
21   static const auto* kPerfRecordOptions = new std::map<string, OptionType>{
22       {"-e", OptionType::Value},
23       {"--event", OptionType::Value},
24       {"--filter", OptionType::Value},
25       {"-p", OptionType::Value},
26       {"--pid", OptionType::Value},
27       {"-t", OptionType::Value},
28       {"--tid", OptionType::Value},
29       {"-r", OptionType::Value},
30       {"--realtime", OptionType::Value},
31       /* Banned: {"--no-buffering", OptionType::Boolean}, */
32       {"-R", OptionType::Boolean},
33       {"--raw-samples", OptionType::Boolean},
34       {"-a", OptionType::Boolean},
35       {"--all-cpus", OptionType::Boolean},
36       {"-C", OptionType::Value},
37       {"--cpu", OptionType::Value},
38       {"-c", OptionType::Value},
39       {"--count", OptionType::Value},
40       /* Banned: {"-o", OptionType::Value},
41        * {"--output", OptionType::Value}, */
42       {"-i", OptionType::Boolean},
43       {"--no-inherit", OptionType::Boolean},
44       {"-F", OptionType::Value},
45       {"--freq", OptionType::Value},
46       /* Banned: {"-m", OptionType::Value},
47        * {"--mmap-pages", OptionType::Value}, */
48       {"--group", OptionType::Boolean}, /* new? */
49       {"-g", OptionType::Boolean}, /* NB: in stat, this is short for --group */
50       {"--call-graph", OptionType::Value},
51       /* Banned: {"-v", OptionType::Boolean},
52        * {"--verbose", OptionType::Boolean}, */
53       /* Banned: {"-q", OptionType::Boolean},
54        * {"--quiet", OptionType::Boolean}, */
55       {"-s", OptionType::Boolean},
56       {"--stat", OptionType::Boolean},
57       {"-d", OptionType::Boolean},
58       {"--data", OptionType::Boolean},
59       {"-T", OptionType::Boolean},
60       {"--timestamp", OptionType::Boolean},
61       {"-P", OptionType::Boolean},       /* new? */
62       {"--period", OptionType::Boolean}, /* new? */
63       {"-n", OptionType::Boolean},
64       {"--no-samples", OptionType::Boolean},
65       {"-N", OptionType::Boolean},
66       {"--no-buildid-cache", OptionType::Boolean},
67       {"-B", OptionType::Boolean},           /* new? */
68       {"--no-buildid", OptionType::Boolean}, /* new? */
69       {"-G", OptionType::Value},
70       {"--cgroup", OptionType::Value},
71       /* Changed between v3.13 to v3.14 from:
72       {"-D", OptionType::Boolean},
73       {"--no-delay", OptionType::Boolean},
74        * to:
75       {"-D", OptionType::Value},
76       {"--delay", OptionType::Value},
77        * ... So just ban it until the new option is universal on ChromeOS perf.
78        */
79       {"-u", OptionType::Value},
80       {"--uid", OptionType::Value},
81       {"-b", OptionType::Boolean},
82       {"--branch-any", OptionType::Boolean},
83       {"-j", OptionType::Value},
84       {"--branch-filter", OptionType::Value},
85       {"-W", OptionType::Boolean},
86       {"--weight", OptionType::Boolean},
87       {"--transaction", OptionType::Boolean},
88       /* Banned: {"--per-thread", OptionType::Boolean},
89        * Only briefly present in v3.12-v3.13, but also banned:
90        * {"--force-per-cpu", OptionType::Boolean}, */
91       /* Banned: {"-I", OptionType::Boolean},  // may reveal PII
92       {"--intr-regs", OptionType::Boolean}, */
93       {"--running-time", OptionType::Boolean},
94       {"-k", OptionType::Value},
95       {"--clockid", OptionType::Value},
96       {"-S", OptionType::Value},
97       {"--snapshot", OptionType::Value},
98 
99       {"--pfm-events", OptionType::Value},
100   };
101   return *kPerfRecordOptions;
102 }
103 
104 const std::map<string, OptionType>& GetPerfStatOptions() {
105   static const auto* kPerfStatOptions = new std::map<string, OptionType>{
106       {"-T", OptionType::Boolean},
107       {"--transaction", OptionType::Boolean},
108       {"-e", OptionType::Value},
109       {"--event", OptionType::Value},
110       {"--filter", OptionType::Value},
111       {"-i", OptionType::Boolean},
112       {"--no-inherit", OptionType::Boolean},
113       {"-p", OptionType::Value},
114       {"--pid", OptionType::Value},
115       {"-t", OptionType::Value},
116       {"--tid", OptionType::Value},
117       {"-a", OptionType::Boolean},
118       {"--all-cpus", OptionType::Boolean},
119       {"-g", OptionType::Boolean},
120       {"--group", OptionType::Boolean},
121       {"-c", OptionType::Boolean},
122       {"--scale", OptionType::Boolean},
123       /* Banned: {"-v", OptionType::Boolean},
124        * {"--verbose", OptionType::Boolean}, */
125       /* Banned: {"-r", OptionType::Value},
126        * {"--repeat", OptionType::Value}, */
127       /* Banned: {"-n", OptionType::Boolean},
128        * {"--null", OptionType::Boolean}, */
129       /* Banned: {"-d", OptionType::Boolean},
130        * {"--detailed", OptionType::Boolean}, */
131       /* Banned: {"-S", OptionType::Boolean},
132        * {"--sync", OptionType::Boolean}, */
133       /* Banned: {"-B", OptionType::Boolean},
134        * {"--big-num", OptionType::Boolean}, */
135       {"-C", OptionType::Value},
136       {"--cpu", OptionType::Value},
137       {"-A", OptionType::Boolean},
138       {"--no-aggr", OptionType::Boolean},
139       /* Banned: {"-x", OptionType::Value},
140        * {"--field-separator", OptionType::Value}, */
141       {"-G", OptionType::Value},
142       {"--cgroup", OptionType::Value},
143       /* Banned: {"-o", OptionType::Value},
144        * {"--output", OptionType::Value}, */
145       /* Banned: {"--append", OptionType::Value}, */
146       /* Banned: {"--log-fd", OptionType::Value}, */
147       /* Banned: {"--pre", OptionType::Value}, */
148       /* Banned: {"--post", OptionType::Value}, */
149       /* Banned: {"-I", OptionType::Value},
150        * {"--interval-print", OptionType::Value}, */
151       {"--per-socket", OptionType::Boolean},
152       {"--per-core", OptionType::Boolean},
153       {"-D", OptionType::Value},
154       {"--delay", OptionType::Value},
155   };
156   return *kPerfStatOptions;
157 }
158 
159 const std::map<string, OptionType>& GetPerfMemOptions() {
160   static const auto* kPerfMemOptions = new std::map<string, OptionType>{
161       {"-t", OptionType::Value},   {"--type", OptionType::Value},
162       {"-D", OptionType::Boolean}, {"--dump-raw-samples", OptionType::Boolean},
163       {"-x", OptionType::Value},   {"--field-separator", OptionType::Value},
164       {"-C", OptionType::Value},   {"--cpu-list", OptionType::Value},
165   };
166   return *kPerfMemOptions;
167 }
168 
169 bool ValidatePerfCommandLineOptions(
170     std::vector<string>::const_iterator begin_arg,
171     std::vector<string>::const_iterator end_arg,
172     const std::map<string, OptionType>& options) {
173   for (auto args_iter = begin_arg; args_iter != end_arg; ++args_iter) {
174     const auto& it = options.find(*args_iter);
175     if (it == options.end()) {
176       return false;
177     }
178     if (it->second == OptionType::Value) {
179       ++args_iter;
180       if (args_iter == end_arg) {
181         return false;  // missing value
182       }
183     }
184   }
185   return true;
186 }
187 
188 }  // namespace
189 
190 bool ValidatePerfCommandLine(const std::vector<string>& args) {
191   if (args.size() < 2) {
192     return false;
193   }
194   if (args[0] != "perf") {
195     return false;
196   }
197   if (args[1] == "record") {
198     return ValidatePerfCommandLineOptions(args.begin() + 2, args.end(),
199                                           GetPerfRecordOptions());
200   }
201   if (args[1] == "mem") {
202     auto record_arg_iter = std::find(args.begin(), args.end(), "record");
203     if (record_arg_iter == args.end()) return false;
204 
205     return ValidatePerfCommandLineOptions(args.begin() + 2, record_arg_iter,
206                                           GetPerfMemOptions()) &&
207            ValidatePerfCommandLineOptions(record_arg_iter + 1, args.end(),
208                                           GetPerfRecordOptions());
209   }
210   if (args[1] == "stat") {
211     return ValidatePerfCommandLineOptions(args.begin() + 2, args.end(),
212                                           GetPerfStatOptions());
213   }
214   return false;
215 }
216 
217 }  // namespace quipper
218