Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 62 additions & 94 deletions ddprof-lib/src/main/cpp/arguments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,32 @@ static const Multiplier UNIVERSAL[] = {
// alluser - include only user-mode events
//

// Parses the y/yes,t/true,1 vs n/no,f/false,0 boolean convention. A NULL value
// (bare option, no '=') enables the flag, matching the documented no-value-means-
// enable convention shared by every boolean option in this file. Returns false
// (leaving out untouched) when a non-NULL value matches none of the above, so the
// caller can raise "Invalid <option> value" instead of coercing garbage to a
// default. Takes out by reference since every caller passes a real bool.
static bool parseBoolOption(const char *value, bool &out) {
if (value == nullptr) {
out = true;
return true;
}
if (strcmp(value, "y") == 0 || strcmp(value, "yes") == 0 ||
strcmp(value, "t") == 0 || strcmp(value, "true") == 0 ||
strcmp(value, "1") == 0) {
out = true;
return true;
}
if (strcmp(value, "n") == 0 || strcmp(value, "no") == 0 ||
strcmp(value, "f") == 0 || strcmp(value, "false") == 0 ||
strcmp(value, "0") == 0) {
out = false;
return true;
}
return false;
}

Error Arguments::parse(const char *args) {
if (args == NULL) {
return Error::OK;
Expand Down Expand Up @@ -255,7 +281,9 @@ Error Arguments::parse(const char *args) {
}

CASE("generations")
_gc_generations = value != NULL && strcmp(value, "true") == 0;
if (!parseBoolOption(value, _gc_generations)) {
msg = "Invalid generations value";
}
if (_gc_generations && _memory <= 0) {
_memory =
4 * 1024 *
Expand Down Expand Up @@ -327,8 +355,10 @@ Error Arguments::parse(const char *args) {
_cstack = CSTACK_VM;
_features.mixed = 1;
_features.carrier_frames = 1;
} else {
} else if (strcmp(value, "no") == 0) {
_cstack = CSTACK_NO;
} else {
msg = "Invalid cstack value";
}
}

Expand All @@ -345,104 +375,48 @@ Error Arguments::parse(const char *args) {
}

CASE("lightweight")
if (value != NULL) {
switch (value[0]) {
case 'y': // yes
case 't': // true
_lightweight = true;
break;
default:
_lightweight = false;
}
if (value != NULL && !parseBoolOption(value, _lightweight)) {
msg = "Invalid lightweight value";
}

CASE("mcleanup")
if (value != NULL) {
switch (value[0]) {
case 'n': // no
case 'f': // false
case '0': // 0
_enable_method_cleanup = false;
break;
case 'y': // yes
case 't': // true
case '1': // 1
default:
_enable_method_cleanup = true;
}
} else {
// No value means enable
_enable_method_cleanup = true;
// No value means enable.
if (!parseBoolOption(value, _enable_method_cleanup)) {
msg = "Invalid mcleanup value";
}

CASE("remotesym")
if (value != NULL) {
switch (value[0]) {
case 'n': // no
case 'f': // false
case '0': // 0
_remote_symbolication = false;
break;
case 'y': // yes
case 't': // true
case '1': // 1
default:
_remote_symbolication = true;
}
} else {
// No value means enable
_remote_symbolication = true;
// No value means enable.
if (!parseBoolOption(value, _remote_symbolication)) {
msg = "Invalid remotesym value";
}

CASE("jvmtistacks")
if (value != NULL) {
switch (value[0]) {
case 'y': // yes
case 't': // true
case '1': // 1
_jvmtistacks = true;
break;
default:
_jvmtistacks = false;
}
} else {
_jvmtistacks = true;
if (!parseBoolOption(value, _jvmtistacks)) {
msg = "Invalid jvmtistacks value";
}

CASE("wallprecheck")
if (value != NULL) {
_wall_precheck = strcmp(value, "false") != 0 && strcmp(value, "0") != 0;
} else {
// No value means enable
_wall_precheck = true;
// No value means enable.
if (!parseBoolOption(value, _wall_precheck)) {
msg = "Invalid wallprecheck value";
}

CASE("wallsampler")
if (value != NULL) {
switch (value[0]) {
case 'j':
_wallclock_sampler = JVMTI;
break;
case 'a':
default:
_wallclock_sampler = ASGCT;
if (strcasecmp(value, "jvmti") == 0) {
_wallclock_sampler = JVMTI;
} else if (strcasecmp(value, "asgct") == 0) {
_wallclock_sampler = ASGCT;
} else {
msg = "Invalid wallsampler value";
}
}

CASE("nosanity")
if (value != NULL) {
switch (value[0]) {
case 'n': // no
case 'f': // false
case '0': // 0
_skip_sanity_checks = false;
break;
default:
_skip_sanity_checks = true;
}
} else {
// A bare 'nosanity' with no value skips the checks.
_skip_sanity_checks = true;
// A bare 'nosanity' with no value skips the checks.
if (!parseBoolOption(value, _skip_sanity_checks)) {
msg = "Invalid nosanity value";
}

CASE("nativemem")
Expand Down Expand Up @@ -474,18 +448,9 @@ Error Arguments::parse(const char *args) {
if (config) {
*(config++) = 0;
}
if (value != NULL) {
switch (value[0]) {
case 'n': // no
case 'f': // false
case '0': // 0
_reference_chains = false;
break;
default:
_reference_chains = true;
}
} else {
_reference_chains = true;
// A bare 'referencechains' with no value means enable.
if (!parseBoolOption(value, _reference_chains)) {
msg = "Invalid referencechains value";
}
char *cursor = config;
while (cursor != NULL) {
Expand Down Expand Up @@ -528,15 +493,18 @@ Error Arguments::parse(const char *args) {
_reference_chains_first_pass_budget = std::min(
std::max(atoi(eq), 0), MAX_REFERENCE_CHAINS_FIRST_PASS_BUDGET);
_reference_chains_tuned_mask |= REF_CHAINS_TUNED_FIRST_PASS_BUDGET;
} else {
_unknown_args.push_back(cursor);
}
} else if (*cursor != 0) {
_unknown_args.push_back(cursor);
}
cursor = next;
}
}

DEFAULT()
if (_unknown_arg == NULL)
_unknown_arg = arg;
_unknown_args.push_back(arg);
}
}

Expand Down
8 changes: 4 additions & 4 deletions ddprof-lib/src/main/cpp/arguments.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,9 @@ class Error {

explicit Error(const char *message) : _message(message) {}

const char *message() { return _message; }
const char *message() const { return _message; }

operator bool() { return _message != NULL; }
operator bool() const { return _message != NULL; }
};

class Arguments {
Expand Down Expand Up @@ -260,7 +260,7 @@ class Arguments {
const char* _file;
const char* _log;
const char* _loglevel;
const char* _unknown_arg;
std::vector<std::string> _unknown_args;
const char* _filter;
CStack _cstack;
Clock _clock;
Expand Down Expand Up @@ -311,7 +311,7 @@ class Arguments {
_file(NULL),
_log(NULL),
_loglevel(NULL),
_unknown_arg(NULL),
_unknown_args({}),
_filter(NULL),
_cstack(CSTACK_DEFAULT),
_clock(CLK_DEFAULT),
Expand Down
4 changes: 2 additions & 2 deletions ddprof-lib/src/main/cpp/javaApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,13 @@ Java_com_datadoghq_profiler_JavaProfiler_execute0(JNIEnv *env, jobject unused,
JniString command_str(env, command);
Error error = args.parse(command_str.c_str());

Log::open(args);
Comment thread
kaahos marked this conversation as resolved.

if (error) {
throwNew(env, "java/lang/IllegalArgumentException", error.message());
return NULL;
}

Log::open(args);

std::ostringstream out;

// Attach ProfiledThread
Expand Down
13 changes: 11 additions & 2 deletions ddprof-lib/src/main/cpp/log.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright 2021 Andrei Pangin
* Copyright 2026, Datadog, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -27,12 +28,20 @@ LogLevel Log::_level = LOG_NONE;
void Log::open(Arguments &args) {
open(args._log, args._loglevel);

if (args._unknown_arg != NULL) {
warn("Unknown argument: %s", args._unknown_arg);
for (const std::string &arg : args._unknown_args) {
warn("Unknown argument: %s", arg.c_str());
}
}

void Log::open(const char *file_name, const char *level) {
if (file_name == NULL && level == NULL) {
// Nothing to reconfigure. In particular, this keeps a rejected execute0()
// command (which parses to _log == NULL, _loglevel == NULL when the
// caller didn't ask to change logging) from resetting an active custom
// log file back to stdout/LOG_NONE before the parse error is thrown.
return;
}

if (_file != stdout && _file != stderr) {
fclose(_file);
}
Expand Down
Loading
Loading