1 // Copyright (C) 2021 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <getopt.h>
16
17 #include <ditto/embedded_benchmarks.h>
18
19 #include <ditto/arg_parser.h>
20
21 namespace dittosuite {
22
ArgToResultsOutput(const std::string_view optarg)23 ResultsOutput ArgToResultsOutput(const std::string_view optarg) {
24 if (optarg == "report" || optarg == "0") {
25 return ResultsOutput::kReport;
26 }
27 if (optarg == "csv" || optarg == "1") {
28 return ResultsOutput::kCsv;
29 }
30 if (optarg == "pb" || optarg == "2") {
31 return ResultsOutput::kPb;
32 }
33 if (optarg == "null" || optarg == "-1") {
34 return ResultsOutput::kNull;
35 }
36 return ResultsOutput::kReport; // by default, the results output is the report (= 0)
37 }
38
ArgToLogStream(const std::string_view optarg)39 LogStream ArgToLogStream(const std::string_view optarg) {
40 if (optarg == "logcat" || optarg == "1") {
41 #ifdef __ANDROID__
42 return LogStream::kLogcat;
43 #else
44 PLOGF("Cannot set log stream as logcat outside of Android");
45 #endif
46 }
47 return LogStream::kStdout; // by default, the log stream is stdout
48 }
49
ArgToLogLevel(const std::string_view optarg)50 LogLevel ArgToLogLevel(const std::string_view optarg) {
51 if (optarg == "VERBOSE" || optarg == "5") {
52 return LogLevel::kVerbose;
53 }
54 if (optarg == "DEBUG" || optarg == "4") {
55 return LogLevel::kDebug;
56 }
57 if (optarg == "INFO" || optarg == "3") {
58 return LogLevel::kInfo;
59 }
60 if (optarg == "WARNING" || optarg == "2") {
61 return LogLevel::kWarning;
62 }
63 if (optarg == "ERROR" || optarg == "1") {
64 return LogLevel::kError;
65 }
66 if (optarg == "FATAL" || optarg == "0") {
67 return LogLevel::kFatal;
68 }
69 return LogLevel::kInfo; // by default, the log level is info
70 }
71
PrintHelpAndExit(std::string_view program_name,const std::string & help_arg)72 void PrintHelpAndExit(std::string_view program_name, const std::string& help_arg) {
73 if (help_arg.compare("workloads") == 0) {
74 std::cerr << "The following workloads are available for execution:\n";
75 for (const auto& c : ditto_static_config) {
76 std::cerr << " - " << c.first << '\n';
77 }
78 } else {
79 std::cerr << "Usage: " << program_name << " [OPTION]... [FILE]\n"
80 << "Benchmarking tool for generic workloads.\n\n"
81
82 << " -w, --workload[=WORKLOAD]"
83 << " The workload to run. Full list with \"-h workloads\".\n"
84
85 << " -f, --format[=FMT]" << "\tresults output format, where FMT can be one of:\n"
86 << "\t\t\t - report (or 0, default): human readable summary;\n"
87 << "\t\t\t - csv (or 1): for comma-separated detailed stats;\n"
88 << "\t\t\t - pb (or 2): protocol-buffer text;\n"
89 << "\t\t\t - null (-1): do not print.\n"
90
91 << " -p, --param[=PAR]..."
92 << "\tif the benchmark is parametric, all the parameters can be passed\n"
93 << "\t\t\tthrough PAR (comma separated)\n"
94
95 << " -l, --log[=LOG]" << "\toutput stream for the log messages.\n"
96 << "\t\t\tLOG can be one of: stdout (or 0, default), logcat (or 1)\n"
97
98 << " -v, --verbosity[=VER]" << "\toutput messages verbosity.\n"
99 << "\t\t\tVER can be one of: VERBOSE (or 5), DEBUG (or 4), INFO (or 3, default),\n"
100 << "\t\t\tWARNING (or 2), ERROR (or 1), FATAL (or 0)\n"
101
102 << " -h, --help" << "\t\tdisplay this help and exit\n\n";
103 }
104
105 exit(EXIT_SUCCESS);
106 }
107
ParseArguments(int argc,char ** argv)108 CmdArguments ParseArguments(int argc, char** argv) {
109 CmdArguments arguments;
110 bool is_embedded = false;
111 std::string help_arg;
112
113 while (true) {
114 int option_index = 0;
115 static struct option long_options[] = {{"workload", required_argument, 0, 'w'},
116 {"format", required_argument, 0, 'f'},
117 {"param", required_argument, 0, 'p'},
118 {"log", required_argument, 0, 'l'},
119 {"verbosity", required_argument, 0, 'v'},
120 {"help", optional_argument, 0, 'h'},
121 {0, 0, 0, 0}};
122
123 int c = getopt_long(argc, argv, "w:f:l:v:p:h::", long_options, &option_index);
124 if (c == -1) break;
125
126 switch (c) {
127 case 'w':
128 arguments.embedded_benchmark = optarg;
129 is_embedded = true;
130 break;
131 case 'f':
132 arguments.results_output = ArgToResultsOutput(optarg);
133 break;
134 case 'l':
135 dittosuite::Logger::GetInstance().SetLogStream(ArgToLogStream(optarg));
136 break;
137 case 'v':
138 dittosuite::Logger::GetInstance().SetLogLevel(ArgToLogLevel(optarg));
139 break;
140 case 'p': {
141 char* token = strtok(optarg, ",");
142 while (token != nullptr) {
143 arguments.parameters.push_back(token);
144 token = strtok(nullptr, ",");
145 }
146 break;
147 }
148 case 'h':
149 if (!optarg && optind < argc // make sure optind is valid
150 && nullptr != argv[optind] // make sure it's not a null string
151 && '\0' != argv[optind][0] // ... or an empty string
152 && '-' != argv[optind][0] // ... or another option
153 ) {
154 help_arg = argv[optind++];
155 }
156 [[fallthrough]];
157 default: {
158 PrintHelpAndExit(argv[0], help_arg);
159 break;
160 }
161 }
162 }
163
164 if (is_embedded && optind < argc) {
165 LOGE("Unexpected both embedded benchmark and .ditto file");
166 PrintHelpAndExit(argv[0], help_arg);
167 }
168 if (!is_embedded) {
169 if (optind >= argc) {
170 LOGE("Expected either embedded benchmark or .ditto file");
171 PrintHelpAndExit(argv[0], help_arg);
172 } else {
173 arguments.file_path = argv[optind];
174 }
175 }
176
177 return arguments;
178 }
179
180 } // namespace dittosuite
181