blob: 4797540c355674ebc3c9642ba2571dac45bbbbc0 [file] [log] [blame]
Igor Murashkinaaebaa02015-01-26 10:55:53 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#ifndef ART_CMDLINE_CMDLINE_TYPES_H_
17#define ART_CMDLINE_CMDLINE_TYPES_H_
18
19#define CMDLINE_NDEBUG 1 // Do not output any debugging information for parsing.
20
Vladimir Marko88b2b802015-12-04 14:19:04 +000021#include "memory_representation.h"
22#include "detail/cmdline_debug_detail.h"
Igor Murashkinaaebaa02015-01-26 10:55:53 -080023#include "cmdline_type_parser.h"
24
25// Includes for the types that are being specialized
26#include <string>
27#include "unit.h"
28#include "jdwp/jdwp.h"
Vladimir Marko88b2b802015-12-04 14:19:04 +000029#include "base/logging.h"
30#include "base/time_utils.h"
31#include "experimental_flags.h"
Igor Murashkinaaebaa02015-01-26 10:55:53 -080032#include "gc/collector_type.h"
33#include "gc/space/large_object_space.h"
34#include "profiler_options.h"
35
36namespace art {
37
38// The default specialization will always fail parsing the type from a string.
39// Provide your own specialization that inherits from CmdlineTypeParser<T>
40// and implements either Parse or ParseAndAppend
41// (only if the argument was defined with ::AppendValues()) but not both.
42template <typename T>
43struct CmdlineType : CmdlineTypeParser<T> {
44};
45
46// Specializations for CmdlineType<T> follow:
47
48// Parse argument definitions for Unit-typed arguments.
49template <>
50struct CmdlineType<Unit> : CmdlineTypeParser<Unit> {
51 Result Parse(const std::string& args) {
52 if (args == "") {
53 return Result::Success(Unit{}); // NOLINT [whitespace/braces] [5]
54 }
55 return Result::Failure("Unexpected extra characters " + args);
56 }
57};
58
59template <>
60struct CmdlineType<JDWP::JdwpOptions> : CmdlineTypeParser<JDWP::JdwpOptions> {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +010061 /*
62 * Handle one of the JDWP name/value pairs.
63 *
64 * JDWP options are:
65 * help: if specified, show help message and bail
66 * transport: may be dt_socket or dt_shmem
67 * address: for dt_socket, "host:port", or just "port" when listening
68 * server: if "y", wait for debugger to attach; if "n", attach to debugger
69 * timeout: how long to wait for debugger to connect / listen
70 *
71 * Useful with server=n (these aren't supported yet):
72 * onthrow=<exception-name>: connect to debugger when exception thrown
73 * onuncaught=y|n: connect to debugger when uncaught exception thrown
74 * launch=<command-line>: launch the debugger itself
75 *
76 * The "transport" option is required, as is "address" if server=n.
77 */
Igor Murashkinaaebaa02015-01-26 10:55:53 -080078 Result Parse(const std::string& options) {
79 VLOG(jdwp) << "ParseJdwpOptions: " << options;
80
81 if (options == "help") {
82 return Result::Usage(
83 "Example: -Xrunjdwp:transport=dt_socket,address=8000,server=y\n"
84 "Example: -Xrunjdwp:transport=dt_socket,address=localhost:6500,server=n\n");
85 }
86
87 const std::string s;
88
89 std::vector<std::string> pairs;
90 Split(options, ',', &pairs);
91
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +010092 JDWP::JdwpOptions jdwp_options;
Igor Murashkinaaebaa02015-01-26 10:55:53 -080093
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +010094 for (const std::string& jdwp_option : pairs) {
95 std::string::size_type equals_pos = jdwp_option.find('=');
96 if (equals_pos == std::string::npos) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -080097 return Result::Failure(s +
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +010098 "Can't parse JDWP option '" + jdwp_option + "' in '" + options + "'");
Igor Murashkinaaebaa02015-01-26 10:55:53 -080099 }
100
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100101 Result parse_attempt = ParseJdwpOption(jdwp_option.substr(0, equals_pos),
102 jdwp_option.substr(equals_pos + 1),
103 &jdwp_options);
104 if (parse_attempt.IsError()) {
105 // We fail to parse this JDWP option.
106 return parse_attempt;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800107 }
108 }
109
110 if (jdwp_options.transport == JDWP::kJdwpTransportUnknown) {
111 return Result::Failure(s + "Must specify JDWP transport: " + options);
112 }
113 if (!jdwp_options.server && (jdwp_options.host.empty() || jdwp_options.port == 0)) {
114 return Result::Failure(s + "Must specify JDWP host and port when server=n: " + options);
115 }
116
117 return Result::Success(std::move(jdwp_options));
118 }
119
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100120 Result ParseJdwpOption(const std::string& name, const std::string& value,
121 JDWP::JdwpOptions* jdwp_options) {
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800122 if (name == "transport") {
123 if (value == "dt_socket") {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100124 jdwp_options->transport = JDWP::kJdwpTransportSocket;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800125 } else if (value == "dt_android_adb") {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100126 jdwp_options->transport = JDWP::kJdwpTransportAndroidAdb;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800127 } else {
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100128 return Result::Failure("JDWP transport not supported: " + value);
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800129 }
130 } else if (name == "server") {
131 if (value == "n") {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100132 jdwp_options->server = false;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800133 } else if (value == "y") {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100134 jdwp_options->server = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800135 } else {
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100136 return Result::Failure("JDWP option 'server' must be 'y' or 'n'");
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800137 }
138 } else if (name == "suspend") {
139 if (value == "n") {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100140 jdwp_options->suspend = false;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800141 } else if (value == "y") {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100142 jdwp_options->suspend = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800143 } else {
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100144 return Result::Failure("JDWP option 'suspend' must be 'y' or 'n'");
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800145 }
146 } else if (name == "address") {
147 /* this is either <port> or <host>:<port> */
148 std::string port_string;
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100149 jdwp_options->host.clear();
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800150 std::string::size_type colon = value.find(':');
151 if (colon != std::string::npos) {
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100152 jdwp_options->host = value.substr(0, colon);
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800153 port_string = value.substr(colon + 1);
154 } else {
155 port_string = value;
156 }
157 if (port_string.empty()) {
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100158 return Result::Failure("JDWP address missing port: " + value);
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800159 }
160 char* end;
161 uint64_t port = strtoul(port_string.c_str(), &end, 10);
162 if (*end != '\0' || port > 0xffff) {
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100163 return Result::Failure("JDWP address has junk in port field: " + value);
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800164 }
Sebastien Hertz3be6e9d2015-02-05 16:30:58 +0100165 jdwp_options->port = port;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800166 } else if (name == "launch" || name == "onthrow" || name == "oncaught" || name == "timeout") {
167 /* valid but unsupported */
168 LOG(INFO) << "Ignoring JDWP option '" << name << "'='" << value << "'";
169 } else {
170 LOG(INFO) << "Ignoring unrecognized JDWP option '" << name << "'='" << value << "'";
171 }
172
Sebastien Hertzb3b173b2015-02-06 09:16:32 +0100173 return Result::SuccessNoValue();
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800174 }
175
176 static const char* Name() { return "JdwpOptions"; }
177};
178
179template <size_t Divisor>
180struct CmdlineType<Memory<Divisor>> : CmdlineTypeParser<Memory<Divisor>> {
181 using typename CmdlineTypeParser<Memory<Divisor>>::Result;
182
183 Result Parse(const std::string arg) {
184 CMDLINE_DEBUG_LOG << "Parsing memory: " << arg << std::endl;
185 size_t val = ParseMemoryOption(arg.c_str(), Divisor);
186 CMDLINE_DEBUG_LOG << "Memory parsed to size_t value: " << val << std::endl;
187
188 if (val == 0) {
189 return Result::Failure(std::string("not a valid memory value, or not divisible by ")
190 + std::to_string(Divisor));
191 }
192
193 return Result::Success(Memory<Divisor>(val));
194 }
195
196 // Parse a string of the form /[0-9]+[kKmMgG]?/, which is used to specify
197 // memory sizes. [kK] indicates kilobytes, [mM] megabytes, and
198 // [gG] gigabytes.
199 //
200 // "s" should point just past the "-Xm?" part of the string.
201 // "div" specifies a divisor, e.g. 1024 if the value must be a multiple
202 // of 1024.
203 //
204 // The spec says the -Xmx and -Xms options must be multiples of 1024. It
205 // doesn't say anything about -Xss.
206 //
207 // Returns 0 (a useless size) if "s" is malformed or specifies a low or
208 // non-evenly-divisible value.
209 //
210 static size_t ParseMemoryOption(const char* s, size_t div) {
211 // strtoul accepts a leading [+-], which we don't want,
212 // so make sure our string starts with a decimal digit.
213 if (isdigit(*s)) {
214 char* s2;
215 size_t val = strtoul(s, &s2, 10);
216 if (s2 != s) {
217 // s2 should be pointing just after the number.
218 // If this is the end of the string, the user
219 // has specified a number of bytes. Otherwise,
220 // there should be exactly one more character
221 // that specifies a multiplier.
222 if (*s2 != '\0') {
223 // The remainder of the string is either a single multiplier
224 // character, or nothing to indicate that the value is in
225 // bytes.
226 char c = *s2++;
227 if (*s2 == '\0') {
228 size_t mul;
229 if (c == '\0') {
230 mul = 1;
231 } else if (c == 'k' || c == 'K') {
232 mul = KB;
233 } else if (c == 'm' || c == 'M') {
234 mul = MB;
235 } else if (c == 'g' || c == 'G') {
236 mul = GB;
237 } else {
238 // Unknown multiplier character.
239 return 0;
240 }
241
242 if (val <= std::numeric_limits<size_t>::max() / mul) {
243 val *= mul;
244 } else {
245 // Clamp to a multiple of 1024.
246 val = std::numeric_limits<size_t>::max() & ~(1024-1);
247 }
248 } else {
249 // There's more than one character after the numeric part.
250 return 0;
251 }
252 }
253 // The man page says that a -Xm value must be a multiple of 1024.
254 if (val % div == 0) {
255 return val;
256 }
257 }
258 }
259 return 0;
260 }
261
262 static const char* Name() { return Memory<Divisor>::Name(); }
263};
264
265template <>
266struct CmdlineType<double> : CmdlineTypeParser<double> {
267 Result Parse(const std::string& str) {
268 char* end = nullptr;
269 errno = 0;
270 double value = strtod(str.c_str(), &end);
271
272 if (*end != '\0') {
273 return Result::Failure("Failed to parse double from " + str);
274 }
275 if (errno == ERANGE) {
276 return Result::OutOfRange(
277 "Failed to parse double from " + str + "; overflow/underflow occurred");
278 }
279
280 return Result::Success(value);
281 }
282
283 static const char* Name() { return "double"; }
284};
285
286template <>
287struct CmdlineType<unsigned int> : CmdlineTypeParser<unsigned int> {
288 Result Parse(const std::string& str) {
289 const char* begin = str.c_str();
290 char* end;
291
292 // Parse into a larger type (long long) because we can't use strtoul
293 // since it silently converts negative values into unsigned long and doesn't set errno.
294 errno = 0;
295 long long int result = strtoll(begin, &end, 10); // NOLINT [runtime/int] [4]
296 if (begin == end || *end != '\0' || errno == EINVAL) {
297 return Result::Failure("Failed to parse integer from " + str);
298 } else if ((errno == ERANGE) || // NOLINT [runtime/int] [4]
299 result < std::numeric_limits<int>::min()
300 || result > std::numeric_limits<unsigned int>::max() || result < 0) {
301 return Result::OutOfRange(
302 "Failed to parse integer from " + str + "; out of unsigned int range");
303 }
304
305 return Result::Success(static_cast<unsigned int>(result));
306 }
307
308 static const char* Name() { return "unsigned integer"; }
309};
310
311// Lightweight nanosecond value type. Allows parser to convert user-input from milliseconds
312// to nanoseconds automatically after parsing.
313//
314// All implicit conversion from uint64_t uses nanoseconds.
315struct MillisecondsToNanoseconds {
316 // Create from nanoseconds.
317 MillisecondsToNanoseconds(uint64_t nanoseconds) : nanoseconds_(nanoseconds) { // NOLINT [runtime/explicit] [5]
318 }
319
320 // Create from milliseconds.
321 static MillisecondsToNanoseconds FromMilliseconds(unsigned int milliseconds) {
322 return MillisecondsToNanoseconds(MsToNs(milliseconds));
323 }
324
325 // Get the underlying nanoseconds value.
326 uint64_t GetNanoseconds() const {
327 return nanoseconds_;
328 }
329
330 // Get the milliseconds value [via a conversion]. Loss of precision will occur.
331 uint64_t GetMilliseconds() const {
332 return NsToMs(nanoseconds_);
333 }
334
335 // Get the underlying nanoseconds value.
336 operator uint64_t() const {
337 return GetNanoseconds();
338 }
339
340 // Default constructors/copy-constructors.
341 MillisecondsToNanoseconds() : nanoseconds_(0ul) {}
Andreas Gampec801f0d2015-02-24 20:55:16 -0800342 MillisecondsToNanoseconds(const MillisecondsToNanoseconds&) = default;
343 MillisecondsToNanoseconds(MillisecondsToNanoseconds&&) = default;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800344
345 private:
346 uint64_t nanoseconds_;
347};
348
349template <>
350struct CmdlineType<MillisecondsToNanoseconds> : CmdlineTypeParser<MillisecondsToNanoseconds> {
351 Result Parse(const std::string& str) {
352 CmdlineType<unsigned int> uint_parser;
353 CmdlineParseResult<unsigned int> res = uint_parser.Parse(str);
354
355 if (res.IsSuccess()) {
356 return Result::Success(MillisecondsToNanoseconds::FromMilliseconds(res.GetValue()));
357 } else {
358 return Result::CastError(res);
359 }
360 }
361
362 static const char* Name() { return "MillisecondsToNanoseconds"; }
363};
364
365template <>
366struct CmdlineType<std::string> : CmdlineTypeParser<std::string> {
367 Result Parse(const std::string& args) {
368 return Result::Success(args);
369 }
370
371 Result ParseAndAppend(const std::string& args,
372 std::string& existing_value) {
373 if (existing_value.empty()) {
374 existing_value = args;
375 } else {
376 existing_value += ' ';
377 existing_value += args;
378 }
379 return Result::SuccessNoValue();
380 }
381};
382
383template <>
384struct CmdlineType<std::vector<std::string>> : CmdlineTypeParser<std::vector<std::string>> {
385 Result Parse(const std::string& args) {
386 assert(false && "Use AppendValues() for a string vector type");
387 return Result::Failure("Unconditional failure: string vector must be appended: " + args);
388 }
389
390 Result ParseAndAppend(const std::string& args,
391 std::vector<std::string>& existing_value) {
392 existing_value.push_back(args);
393 return Result::SuccessNoValue();
394 }
395
396 static const char* Name() { return "std::vector<std::string>"; }
397};
398
399template <char Separator>
400struct ParseStringList {
401 explicit ParseStringList(std::vector<std::string>&& list) : list_(list) {}
402
403 operator std::vector<std::string>() const {
404 return list_;
405 }
406
407 operator std::vector<std::string>&&() && {
408 return std::move(list_);
409 }
410
411 size_t Size() const {
412 return list_.size();
413 }
414
415 std::string Join() const {
416 return art::Join(list_, Separator);
417 }
418
419 static ParseStringList<Separator> Split(const std::string& str) {
420 std::vector<std::string> list;
421 art::Split(str, Separator, &list);
422 return ParseStringList<Separator>(std::move(list));
423 }
424
425 ParseStringList() = default;
Andreas Gampec801f0d2015-02-24 20:55:16 -0800426 ParseStringList(const ParseStringList&) = default;
427 ParseStringList(ParseStringList&&) = default;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800428
429 private:
430 std::vector<std::string> list_;
431};
432
433template <char Separator>
434struct CmdlineType<ParseStringList<Separator>> : CmdlineTypeParser<ParseStringList<Separator>> {
435 using Result = CmdlineParseResult<ParseStringList<Separator>>;
436
437 Result Parse(const std::string& args) {
438 return Result::Success(ParseStringList<Separator>::Split(args));
439 }
440
441 static const char* Name() { return "ParseStringList<Separator>"; }
442};
443
444static gc::CollectorType ParseCollectorType(const std::string& option) {
445 if (option == "MS" || option == "nonconcurrent") {
446 return gc::kCollectorTypeMS;
447 } else if (option == "CMS" || option == "concurrent") {
448 return gc::kCollectorTypeCMS;
449 } else if (option == "SS") {
450 return gc::kCollectorTypeSS;
451 } else if (option == "GSS") {
452 return gc::kCollectorTypeGSS;
453 } else if (option == "CC") {
454 return gc::kCollectorTypeCC;
455 } else if (option == "MC") {
456 return gc::kCollectorTypeMC;
457 } else {
458 return gc::kCollectorTypeNone;
459 }
460}
461
462struct XGcOption {
463 // These defaults are used when the command line arguments for -Xgc:
464 // are either omitted completely or partially.
465 gc::CollectorType collector_type_ = kUseReadBarrier ?
466 // If RB is enabled (currently a build-time decision),
467 // use CC as the default GC.
468 gc::kCollectorTypeCC :
469 gc::kCollectorTypeDefault;
470 bool verify_pre_gc_heap_ = false;
471 bool verify_pre_sweeping_heap_ = kIsDebugBuild;
472 bool verify_post_gc_heap_ = false;
473 bool verify_pre_gc_rosalloc_ = kIsDebugBuild;
474 bool verify_pre_sweeping_rosalloc_ = false;
475 bool verify_post_gc_rosalloc_ = false;
Mathieu Chartier31000802015-06-14 14:14:37 -0700476 bool gcstress_ = false;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800477};
478
479template <>
480struct CmdlineType<XGcOption> : CmdlineTypeParser<XGcOption> {
481 Result Parse(const std::string& option) { // -Xgc: already stripped
482 XGcOption xgc{}; // NOLINT [readability/braces] [4]
483
484 std::vector<std::string> gc_options;
485 Split(option, ',', &gc_options);
486 for (const std::string& gc_option : gc_options) {
487 gc::CollectorType collector_type = ParseCollectorType(gc_option);
488 if (collector_type != gc::kCollectorTypeNone) {
489 xgc.collector_type_ = collector_type;
490 } else if (gc_option == "preverify") {
491 xgc.verify_pre_gc_heap_ = true;
492 } else if (gc_option == "nopreverify") {
493 xgc.verify_pre_gc_heap_ = false;
494 } else if (gc_option == "presweepingverify") {
495 xgc.verify_pre_sweeping_heap_ = true;
496 } else if (gc_option == "nopresweepingverify") {
497 xgc.verify_pre_sweeping_heap_ = false;
498 } else if (gc_option == "postverify") {
499 xgc.verify_post_gc_heap_ = true;
500 } else if (gc_option == "nopostverify") {
501 xgc.verify_post_gc_heap_ = false;
502 } else if (gc_option == "preverify_rosalloc") {
503 xgc.verify_pre_gc_rosalloc_ = true;
504 } else if (gc_option == "nopreverify_rosalloc") {
505 xgc.verify_pre_gc_rosalloc_ = false;
506 } else if (gc_option == "presweepingverify_rosalloc") {
507 xgc.verify_pre_sweeping_rosalloc_ = true;
508 } else if (gc_option == "nopresweepingverify_rosalloc") {
509 xgc.verify_pre_sweeping_rosalloc_ = false;
510 } else if (gc_option == "postverify_rosalloc") {
511 xgc.verify_post_gc_rosalloc_ = true;
512 } else if (gc_option == "nopostverify_rosalloc") {
513 xgc.verify_post_gc_rosalloc_ = false;
Mathieu Chartier31000802015-06-14 14:14:37 -0700514 } else if (gc_option == "gcstress") {
515 xgc.gcstress_ = true;
516 } else if (gc_option == "nogcstress") {
517 xgc.gcstress_ = false;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800518 } else if ((gc_option == "precise") ||
519 (gc_option == "noprecise") ||
520 (gc_option == "verifycardtable") ||
521 (gc_option == "noverifycardtable")) {
522 // Ignored for backwards compatibility.
523 } else {
524 return Result::Usage(std::string("Unknown -Xgc option ") + gc_option);
525 }
526 }
527
528 return Result::Success(std::move(xgc));
529 }
530
531 static const char* Name() { return "XgcOption"; }
532};
533
534struct BackgroundGcOption {
535 // If background_collector_type_ is kCollectorTypeNone, it defaults to the
536 // XGcOption::collector_type_ after parsing options. If you set this to
537 // kCollectorTypeHSpaceCompact then we will do an hspace compaction when
538 // we transition to background instead of a normal collector transition.
539 gc::CollectorType background_collector_type_;
540
541 BackgroundGcOption(gc::CollectorType background_collector_type) // NOLINT [runtime/explicit] [5]
542 : background_collector_type_(background_collector_type) {}
543 BackgroundGcOption()
544 : background_collector_type_(gc::kCollectorTypeNone) {
545
546 if (kUseReadBarrier) {
547 background_collector_type_ = gc::kCollectorTypeCC; // Disable background compaction for CC.
548 }
549 }
550
551 operator gc::CollectorType() const { return background_collector_type_; }
552};
553
554template<>
555struct CmdlineType<BackgroundGcOption>
556 : CmdlineTypeParser<BackgroundGcOption>, private BackgroundGcOption {
557 Result Parse(const std::string& substring) {
558 // Special handling for HSpaceCompact since this is only valid as a background GC type.
559 if (substring == "HSpaceCompact") {
560 background_collector_type_ = gc::kCollectorTypeHomogeneousSpaceCompact;
561 } else {
562 gc::CollectorType collector_type = ParseCollectorType(substring);
563 if (collector_type != gc::kCollectorTypeNone) {
564 background_collector_type_ = collector_type;
565 } else {
566 return Result::Failure();
567 }
568 }
569
570 BackgroundGcOption res = *this;
571 return Result::Success(res);
572 }
573
574 static const char* Name() { return "BackgroundGcOption"; }
575};
576
577template <>
578struct CmdlineType<LogVerbosity> : CmdlineTypeParser<LogVerbosity> {
579 Result Parse(const std::string& options) {
580 LogVerbosity log_verbosity = LogVerbosity();
581
582 std::vector<std::string> verbose_options;
583 Split(options, ',', &verbose_options);
584 for (size_t j = 0; j < verbose_options.size(); ++j) {
585 if (verbose_options[j] == "class") {
586 log_verbosity.class_linker = true;
Mathieu Chartiera6e1c122016-02-19 10:25:39 -0800587 } else if (verbose_options[j] == "collector") {
588 log_verbosity.collector = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800589 } else if (verbose_options[j] == "compiler") {
590 log_verbosity.compiler = true;
Andreas Gampef3d1f942015-05-18 21:41:13 -0700591 } else if (verbose_options[j] == "deopt") {
592 log_verbosity.deopt = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800593 } else if (verbose_options[j] == "gc") {
594 log_verbosity.gc = true;
595 } else if (verbose_options[j] == "heap") {
596 log_verbosity.heap = true;
597 } else if (verbose_options[j] == "jdwp") {
598 log_verbosity.jdwp = true;
Mathieu Chartiere5f13e52015-02-24 09:37:21 -0800599 } else if (verbose_options[j] == "jit") {
600 log_verbosity.jit = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800601 } else if (verbose_options[j] == "jni") {
602 log_verbosity.jni = true;
603 } else if (verbose_options[j] == "monitor") {
604 log_verbosity.monitor = true;
Richard Uhler66d874d2015-01-15 09:37:19 -0800605 } else if (verbose_options[j] == "oat") {
606 log_verbosity.oat = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800607 } else if (verbose_options[j] == "profiler") {
608 log_verbosity.profiler = true;
609 } else if (verbose_options[j] == "signals") {
610 log_verbosity.signals = true;
Phil Wang751beff2015-08-28 15:17:15 +0800611 } else if (verbose_options[j] == "simulator") {
612 log_verbosity.simulator = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800613 } else if (verbose_options[j] == "startup") {
614 log_verbosity.startup = true;
615 } else if (verbose_options[j] == "third-party-jni") {
616 log_verbosity.third_party_jni = true;
617 } else if (verbose_options[j] == "threads") {
618 log_verbosity.threads = true;
619 } else if (verbose_options[j] == "verifier") {
620 log_verbosity.verifier = true;
Mathieu Chartierfbc31082016-01-24 11:59:56 -0800621 } else if (verbose_options[j] == "image") {
622 log_verbosity.image = true;
Andreas Gampefc689872016-04-25 20:08:55 -0700623 } else if (verbose_options[j] == "systrace-locks") {
624 log_verbosity.systrace_lock_logging = true;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800625 } else {
626 return Result::Usage(std::string("Unknown -verbose option ") + verbose_options[j]);
627 }
628 }
629
630 return Result::Success(log_verbosity);
631 }
632
633 static const char* Name() { return "LogVerbosity"; }
634};
635
636// TODO: Replace with art::ProfilerOptions for the real thing.
637struct TestProfilerOptions {
638 // Whether or not the applications should be profiled.
639 bool enabled_;
640 // Destination file name where the profiling data will be saved into.
641 std::string output_file_name_;
642 // Generate profile every n seconds.
643 uint32_t period_s_;
644 // Run profile for n seconds.
645 uint32_t duration_s_;
646 // Microseconds between samples.
647 uint32_t interval_us_;
648 // Coefficient to exponential backoff.
649 double backoff_coefficient_;
650 // Whether the profile should start upon app startup or be delayed by some random offset.
651 bool start_immediately_;
652 // Top K% of samples that are considered relevant when deciding if the app should be recompiled.
653 double top_k_threshold_;
654 // How much the top K% samples needs to change in order for the app to be recompiled.
655 double top_k_change_threshold_;
656 // The type of profile data dumped to the disk.
657 ProfileDataType profile_type_;
658 // The max depth of the stack collected by the profiler
659 uint32_t max_stack_depth_;
660
661 TestProfilerOptions() :
662 enabled_(false),
663 output_file_name_(),
664 period_s_(0),
665 duration_s_(0),
666 interval_us_(0),
667 backoff_coefficient_(0),
668 start_immediately_(0),
669 top_k_threshold_(0),
670 top_k_change_threshold_(0),
671 profile_type_(ProfileDataType::kProfilerMethod),
672 max_stack_depth_(0) {
673 }
674
Andreas Gampec801f0d2015-02-24 20:55:16 -0800675 TestProfilerOptions(const TestProfilerOptions&) = default;
676 TestProfilerOptions(TestProfilerOptions&&) = default;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800677};
678
679static inline std::ostream& operator<<(std::ostream& stream, const TestProfilerOptions& options) {
680 stream << "TestProfilerOptions {" << std::endl;
681
682#define PRINT_TO_STREAM(field) \
683 stream << #field << ": '" << options.field << "'" << std::endl;
684
685 PRINT_TO_STREAM(enabled_);
686 PRINT_TO_STREAM(output_file_name_);
687 PRINT_TO_STREAM(period_s_);
688 PRINT_TO_STREAM(duration_s_);
689 PRINT_TO_STREAM(interval_us_);
690 PRINT_TO_STREAM(backoff_coefficient_);
691 PRINT_TO_STREAM(start_immediately_);
692 PRINT_TO_STREAM(top_k_threshold_);
693 PRINT_TO_STREAM(top_k_change_threshold_);
694 PRINT_TO_STREAM(profile_type_);
695 PRINT_TO_STREAM(max_stack_depth_);
696
697 stream << "}";
698
699 return stream;
700#undef PRINT_TO_STREAM
701}
702
703template <>
704struct CmdlineType<TestProfilerOptions> : CmdlineTypeParser<TestProfilerOptions> {
705 using Result = CmdlineParseResult<TestProfilerOptions>;
706
707 private:
708 using StringResult = CmdlineParseResult<std::string>;
709 using DoubleResult = CmdlineParseResult<double>;
710
711 template <typename T>
712 static Result ParseInto(TestProfilerOptions& options,
713 T TestProfilerOptions::*pField,
714 CmdlineParseResult<T>&& result) {
715 assert(pField != nullptr);
716
717 if (result.IsSuccess()) {
718 options.*pField = result.ReleaseValue();
719 return Result::SuccessNoValue();
720 }
721
722 return Result::CastError(result);
723 }
724
725 template <typename T>
726 static Result ParseIntoRangeCheck(TestProfilerOptions& options,
727 T TestProfilerOptions::*pField,
728 CmdlineParseResult<T>&& result,
729 T min,
730 T max) {
731 if (result.IsSuccess()) {
732 const T& value = result.GetValue();
733
734 if (value < min || value > max) {
735 CmdlineParseResult<T> out_of_range = CmdlineParseResult<T>::OutOfRange(value, min, max);
736 return Result::CastError(out_of_range);
737 }
738 }
739
740 return ParseInto(options, pField, std::forward<CmdlineParseResult<T>>(result));
741 }
742
743 static StringResult ParseStringAfterChar(const std::string& s, char c) {
744 std::string parsed_value;
745
746 std::string::size_type colon = s.find(c);
747 if (colon == std::string::npos) {
748 return StringResult::Usage(std::string() + "Missing char " + c + " in option " + s);
749 }
750 // Add one to remove the char we were trimming until.
751 parsed_value = s.substr(colon + 1);
752 return StringResult::Success(parsed_value);
753 }
754
755 static std::string RemovePrefix(const std::string& source) {
756 size_t prefix_idx = source.find(":");
757
758 if (prefix_idx == std::string::npos) {
759 return "";
760 }
761
762 return source.substr(prefix_idx + 1);
763 }
764
765 public:
766 Result ParseAndAppend(const std::string& option, TestProfilerOptions& existing) {
767 // Special case which doesn't include a wildcard argument definition.
768 // We pass-it through as-is.
769 if (option == "-Xenable-profiler") {
770 existing.enabled_ = true;
771 return Result::SuccessNoValue();
772 }
773
774 // The rest of these options are always the wildcard from '-Xprofile-*'
775 std::string suffix = RemovePrefix(option);
776
777 if (StartsWith(option, "filename:")) {
778 CmdlineType<std::string> type_parser;
779
780 return ParseInto(existing,
781 &TestProfilerOptions::output_file_name_,
782 type_parser.Parse(suffix));
783 } else if (StartsWith(option, "period:")) {
784 CmdlineType<unsigned int> type_parser;
785
786 return ParseInto(existing,
787 &TestProfilerOptions::period_s_,
788 type_parser.Parse(suffix));
789 } else if (StartsWith(option, "duration:")) {
790 CmdlineType<unsigned int> type_parser;
791
792 return ParseInto(existing,
793 &TestProfilerOptions::duration_s_,
794 type_parser.Parse(suffix));
795 } else if (StartsWith(option, "interval:")) {
796 CmdlineType<unsigned int> type_parser;
797
798 return ParseInto(existing,
799 &TestProfilerOptions::interval_us_,
800 type_parser.Parse(suffix));
801 } else if (StartsWith(option, "backoff:")) {
802 CmdlineType<double> type_parser;
803
804 return ParseIntoRangeCheck(existing,
805 &TestProfilerOptions::backoff_coefficient_,
806 type_parser.Parse(suffix),
807 1.0,
808 10.0);
809
810 } else if (option == "start-immediately") {
811 existing.start_immediately_ = true;
812 return Result::SuccessNoValue();
813 } else if (StartsWith(option, "top-k-threshold:")) {
814 CmdlineType<double> type_parser;
815
816 return ParseIntoRangeCheck(existing,
817 &TestProfilerOptions::top_k_threshold_,
818 type_parser.Parse(suffix),
819 0.0,
820 100.0);
821 } else if (StartsWith(option, "top-k-change-threshold:")) {
822 CmdlineType<double> type_parser;
823
824 return ParseIntoRangeCheck(existing,
825 &TestProfilerOptions::top_k_change_threshold_,
826 type_parser.Parse(suffix),
827 0.0,
828 100.0);
829 } else if (option == "type:method") {
830 existing.profile_type_ = kProfilerMethod;
831 return Result::SuccessNoValue();
832 } else if (option == "type:stack") {
833 existing.profile_type_ = kProfilerBoundedStack;
834 return Result::SuccessNoValue();
835 } else if (StartsWith(option, "max-stack-depth:")) {
836 CmdlineType<unsigned int> type_parser;
837
838 return ParseInto(existing,
839 &TestProfilerOptions::max_stack_depth_,
840 type_parser.Parse(suffix));
841 } else {
842 return Result::Failure(std::string("Invalid suboption '") + option + "'");
843 }
844 }
845
846 static const char* Name() { return "TestProfilerOptions"; }
847 static constexpr bool kCanParseBlankless = true;
848};
849
Alex Lighteb7c1442015-08-31 13:17:42 -0700850template<>
851struct CmdlineType<ExperimentalFlags> : CmdlineTypeParser<ExperimentalFlags> {
852 Result ParseAndAppend(const std::string& option, ExperimentalFlags& existing) {
853 if (option == "none") {
Neil Fuller9724c632016-01-07 15:42:47 +0000854 existing = ExperimentalFlags::kNone;
Alex Lighteb7c1442015-08-31 13:17:42 -0700855 } else if (option == "lambdas") {
856 existing = existing | ExperimentalFlags::kLambdas;
Alex Lighteb7c1442015-08-31 13:17:42 -0700857 } else {
858 return Result::Failure(std::string("Unknown option '") + option + "'");
859 }
860 return Result::SuccessNoValue();
861 }
862
863 static const char* Name() { return "ExperimentalFlags"; }
864};
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800865
866} // namespace art
867#endif // ART_CMDLINE_CMDLINE_TYPES_H_