Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Export gProfiler-needed functionality from asprof #7

Merged
Show file tree
Hide file tree
Changes from 6 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
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ build/%:
mkdir -p $@

build/$(LAUNCHER): src/launcher/* src/jattach/* src/fdtransfer.h
$(CC) $(CPPFLAGS) $(CFLAGS) -DPROFILER_VERSION=\"$(PROFILER_VERSION)\" -DSUPPRESS_OUTPUT -o $@ src/launcher/*.cpp src/jattach/*.c
$(CC) $(CPPFLAGS) $(CFLAGS) -static -DPROFILER_VERSION=\"$(PROFILER_VERSION)\" -o $@ src/launcher/*.cpp src/jattach/*.c
strip $@

PROFILER_FLAGS=-static-libgcc
Expand Down Expand Up @@ -155,7 +155,7 @@ build/$(CONVERTER_JAR): $(CONVERTER_SOURCES) $(RESOURCES)
$(RM) -r build/converter

%.class: %.java
$(JAVAC) --source $(JAVA_TARGET) -target $(JAVA_TARGET) -Xlint:-options -g:none $^
$(JAVAC) -source $(JAVA_TARGET) -target $(JAVA_TARGET) -Xlint:-options -g:none $^

test: all
test/smoke-test.sh
Expand Down
4 changes: 2 additions & 2 deletions src/launcher/fdtransferServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class FdTransferServer {
public:
static bool supported() { return true; }

static bool runOnce(int pid, const char *path);
static bool runOnce(int pid, const char *path, unsigned int timeout);
static bool runLoop(const char *path);
};

Expand All @@ -46,7 +46,7 @@ class FdTransferServer {
public:
static bool supported() { return false; }

static bool runOnce(int pid, const char *path) { return false; }
static bool runOnce(int pid, const char *path, unsigned int timeout) { return false; }
static bool runLoop(const char *path) { return false; }
};

Expand Down
4 changes: 2 additions & 2 deletions src/launcher/fdtransferServer_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ bool FdTransferServer::sendFd(int fd, struct fd_response *resp, size_t resp_size
return true;
}

bool FdTransferServer::runOnce(int pid, const char *path) {
bool FdTransferServer::runOnce(int pid, const char *path, unsigned int timeout) {
// get its nspid prior to moving to its PID namespace.
int nspid;
uid_t target_uid;
Expand All @@ -287,7 +287,7 @@ bool FdTransferServer::runOnce(int pid, const char *path) {
}
}

if (!bindServer(&sun, addrlen, 30)) {
if (!bindServer(&sun, addrlen, timeout)) {
return false;
}

Expand Down
97 changes: 81 additions & 16 deletions src/launcher/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ static const char USAGE_STRING[] =
" list list profiling events supported by the target JVM\n"
" collect collect profile for the specified period of time\n"
" and then stop (default action)\n"
" fdtransfer start fdtransfer to serve perf requests on behalf of profiled process\n"
" jattach invoke jattach directly; requires --jattach-cmd,\n"
" ignores all arguments except --lib-path\n"
"\n"
"Options:\n"
" -e event profiling event: cpu|alloc|lock|cache-misses etc.\n"
" -d duration run profiling for <duration> seconds\n"
Expand Down Expand Up @@ -87,6 +91,11 @@ static const char USAGE_STRING[] =
" --jfrsync config synchronize profiler with JFR recording\n"
" --fdtransfer use fdtransfer to serve perf requests\n"
" from the non-privileged target\n"
" --jattach-cmd string\n"
" arguments to use with jattach action\n"
" -L|--lib-path string\n"
" path to async-profiler's shared lib\n"
" --fd-path string socket path for fdtransfer to bind to\n"
"\n"
"<pid> is a numeric process ID of the target JVM\n"
" or 'jps' keyword to find running JVM automatically\n"
Expand All @@ -97,6 +106,7 @@ static const char USAGE_STRING[] =
" " APP_BINARY " stop -o flat jps\n"
" " APP_BINARY " -d 5 -e alloc MyAppName\n";

static const unsigned int DEFAULT_FDTRANSFER_TIMEOUT = 30;

extern "C" int jattach(int pid, int argc, const char** argv);

Expand Down Expand Up @@ -170,6 +180,10 @@ class String {
return strcmp(_str, other._str) == 0;
}

bool operator!=(const String& other) const {
return !(*this == other);
}

String& operator<<(const char* tail) {
size_t len = strlen(_str);
_str = (char*)realloc(_str, len + strlen(tail) + 1);
Expand Down Expand Up @@ -205,11 +219,16 @@ class String {


static String action = "collect";
static const String kEmpty;
static const String kJattachLoad = "load";
static const String kJattachJcmd = "jcmd";
static String file, logfile, output, params, format, fdtransfer, libpath;
static bool use_tmp_file = false;
static int duration = 60;
static int pid = 0;
static volatile unsigned long long end_time;
// gprofiler-specific: holds timeout value for fdtransfer command
static unsigned int timeout = DEFAULT_FDTRANSFER_TIMEOUT;

static void sigint_handler(int sig) {
end_time = 0;
Expand Down Expand Up @@ -314,7 +333,7 @@ static int jps(const char* cmd, const char* app_name = NULL) {
return pid;
}

static void run_fdtransfer(int pid, String& fdtransfer) {
static void run_fdtransfer(int pid, String& fdtransfer, unsigned int timeout) {
if (!FdTransferServer::supported() || fdtransfer == "") return;

pid_t child = fork();
Expand All @@ -323,7 +342,7 @@ static void run_fdtransfer(int pid, String& fdtransfer) {
}

if (child == 0) {
exit(FdTransferServer::runOnce(pid, fdtransfer.str()) ? 0 : 1);
exit(FdTransferServer::runOnce(pid, fdtransfer.str(), timeout) ? 0 : 1);
} else {
int ret = wait_for_exit(child);
if (ret != 0) {
Expand All @@ -332,38 +351,45 @@ static void run_fdtransfer(int pid, String& fdtransfer) {
}
}

static void run_jattach(int pid, String& cmd) {
static void run_jattach(int pid, const String& verb, String& cmd) {
pid_t child = fork();
if (child == -1) {
error("fork failed", errno);
}

if (child == 0) {
const char* argv[] = {"load", libpath.str(), libpath.str()[0] == '/' ? "true" : "false", cmd.str()};
exit(jattach(pid, 4, argv));
if (verb == kJattachLoad) {
const char* args[] = {kJattachLoad.str(), libpath.str(), libpath.str()[0] == '/' ? "true" : "false", cmd.str()};
exit(jattach(pid, 4, args));
} else if (verb == kJattachJcmd) {
const char* args[] = {kJattachJcmd.str(), cmd.str()};
exit(jattach(pid, 2, args));
}
} else {
int ret = wait_for_exit(child);
if (ret != 0) {
if (WEXITSTATUS(ret) == 255) {
fprintf(stderr, "Target JVM failed to load %s\n", libpath.str());
}
print_file(logfile, STDERR_FILENO);
if (logfile != kEmpty) print_file(logfile, STDERR_FILENO);
exit(WEXITSTATUS(ret));
}

print_file(logfile, STDERR_FILENO);
if (logfile != kEmpty) print_file(logfile, STDERR_FILENO);
if (use_tmp_file) print_file(file, STDOUT_FILENO);
}
}


int main(int argc, const char** argv) {
Args args(argc, argv);
String jattach_cmd;
while (args.hasNext()) {
String arg = args.next();

if (arg == "start" || arg == "resume" || arg == "stop" || arg == "dump" || arg == "check" ||
arg == "status" || arg == "meminfo" || arg == "list" || arg == "collect") {
arg == "status" || arg == "meminfo" || arg == "list" || arg == "collect" ||
arg == "fdtransfer" || arg == "jattach" || arg == "jcmd") {
action = arg;

} else if (arg == "-h" || arg == "--help") {
Expand Down Expand Up @@ -453,15 +479,24 @@ int main(int argc, const char** argv) {
output = "jfr";

} else if (arg == "--timeout" || arg == "--loop") {
params << "," << (arg.str() + 2) << "=" << args.next();
const char* value = args.next();
params << "," << (arg.str() + 2) << "=" << value;
// gprofiler-specific: borrow timeout parameter to configure socket timeout for fdtransfer action
timeout = atoi(value);
if (action == "collect") action = "start";

} else if (arg == "--fd-path") {
fdtransfer = String(args.next());

} else if (arg == "--fdtransfer") {
char buf[64];
snprintf(buf, sizeof(buf), "@async-profiler-%d-%08x", getpid(), (unsigned int)time_micros());
fdtransfer = buf;
params << ",fdtransfer=" << fdtransfer;

} else if (arg == "--jattach-cmd") {
jattach_cmd = String(args.next());

} else if (arg.str()[0] >= '0' && arg.str()[0] <= '9' && pid == 0) {
pid = atoi(arg.str());

Expand All @@ -474,6 +509,9 @@ int main(int argc, const char** argv) {
// The last argument is the application name as it would appear in the jps tool
pid = jps("jps -J-XX:+PerfDisableSharedMem", arg.str());

} else if (arg == "-L" || arg == "--lib-path") {
libpath = String(args.next());

} else {
fprintf(stderr, "Unrecognized option: %s\n", arg.str());
return 1;
Expand All @@ -485,12 +523,19 @@ int main(int argc, const char** argv) {
return 1;
}

setup_output_files(pid);
setup_lib_path();
if (jattach_cmd == kEmpty) {
setup_output_files(pid);
} else if (params != kEmpty) {
fprintf(stderr, "Warning: --jattach-cmd was given, these parameters will be ignored: %s\n", params.str());
}

if (libpath == kEmpty) {
setup_lib_path();
}

if (action == "collect") {
run_fdtransfer(pid, fdtransfer);
run_jattach(pid, String("start,file=") << file << "," << output << format << params << ",log=" << logfile);
run_fdtransfer(pid, fdtransfer, 0);
run_jattach(pid, kJattachLoad, String("start,file=") << file << "," << output << format << params << ",log=" << logfile);

fprintf(stderr, "Profiling for %d seconds\n", duration);
end_time = time_micros() + duration * 1000000ULL;
Expand All @@ -508,10 +553,30 @@ int main(int argc, const char** argv) {
signal(SIGINT, SIG_DFL);
fprintf(stderr, "Done\n");

run_jattach(pid, String("stop,file=") << file << "," << output << format << ",log=" << logfile);
run_jattach(pid, kJattachLoad, String("stop,file=") << file << "," << output << format << ",log=" << logfile);
} else if (action == "fdtransfer") {
if (params != kEmpty) {
fprintf(stderr, "Warning: action fdtransfer was given, these parameters will be ignored: %s\n", params.str());
}
run_fdtransfer(pid, fdtransfer, timeout);

} else if (action == "jattach") {
if (jattach_cmd == kEmpty) {
fprintf(stderr, "Action jattach was given, missing required --jattach-cmd argument\n");
return 1;
}
run_jattach(pid, kJattachLoad, jattach_cmd);

} else if (action == "jcmd") {
if (jattach_cmd == kEmpty) {
fprintf(stderr, "Action jcmd was given, missing required --jattach-cmd argument\n");
return 1;
}
run_jattach(pid, kJattachJcmd, jattach_cmd);

} else {
if (action == "start" || action == "resume") run_fdtransfer(pid, fdtransfer);
run_jattach(pid, String(action) << ",file=" << file << "," << output << format << params << ",log=" << logfile);
if (action == "start" || action == "resume") run_fdtransfer(pid, fdtransfer, 0);
run_jattach(pid, kJattachLoad, String(action) << ",file=" << file << "," << output << format << params << ",log=" << logfile);
}

return 0;
Expand Down