Granulate / gprofiler

gProfiler is a system-wide profiler, combining multiple sampling profilers to produce unified visualization of what your CPU is spending time on.
https://profiler.granulate.io
Apache License 2.0
741 stars 54 forks source link

java: Uprade to AP 3.0 #855

Closed Jongy closed 5 months ago

Jongy commented 9 months ago

This is a PR to test gProfiler with current "master" of async-profiler (rebased on top of https://github.com/async-profiler/async-profiler/commit/d29cb86bd0d663ffe65010c412ee360c67fbb274)

Not planning to merge, just checking if everything still works :)

Jongy commented 5 months ago

I will update this to AP 3.0

Jongy commented 5 months ago

Rebase diff:

$ git range-diff v2.10..v2.10g2 v3.0..v3.0g1
 1:  d3a863a =  1:  c789d80 Remove the "Profiling started" message
 2:  a0a9633 =  2:  5c79c9f Remove the "Profiling stopped" message
 3:  f71df14 =  3:  5fdf0d2 Compile statically with libstdc++
 4:  bf4337c =  4:  33ebc48 Compile statically with libgcc
 5:  8ebf525 !  5:  a01841b Fix -static-* args passed only in non-MERGE case :(
    @@ Commit message

      ## Makefile ##
     @@ Makefile: 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) -DPROFILER_VERSION=\"$(PROFILER_VERSION)\" -o $@ src/launcher/*.cpp src/jattach/*.c
        strip $@

     +PROFILER_STATIC_FLAGS=-static-libstdc++ -static-libgcc
 6:  98280ba =  6:  8b45ff8 Close standard streams after forking in fdtransfer
 7:  87f9dff !  7:  0bfb81e -static-libstdc++ only on musl
    @@ Commit message

      ## Makefile ##
     @@ Makefile: 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) -DPROFILER_VERSION=\"$(PROFILER_VERSION)\" -o $@ src/launcher/*.cpp src/jattach/*.c
        strip $@

     -PROFILER_STATIC_FLAGS=-static-libstdc++ -static-libgcc
 8:  99e87c8 !  8:  a174a70 Convert frame name format to 'function (DSO)' for LIB style (#2)
    @@ Commit message

      ## src/codeCache.cpp ##
     @@ src/codeCache.cpp: size_t NativeFunc::usedMemory(const char* name) {
    - 
    - CodeCache::CodeCache(const char* name, short lib_index, const void* min_address, const void* max_address) {
    + CodeCache::CodeCache(const char* name, short lib_index, bool imports_patchable,
    +                      const void* min_address, const void* max_address) {
          _name = NativeFunc::create(name, -1);
     +    char *tmp = (char*)malloc(strlen(name) + 3);
     +    snprintf(tmp, strlen(name) + 3, "(%s)", name);
    @@ src/codeCache.cpp: const char* CodeCache::binarySearch(const void* address) {
      ## src/codeCache.h ##
     @@ src/codeCache.h: class FrameDesc;
      class CodeCache {
    -   protected:
    +   private:
          char* _name;
     +    char* _lib_symbol;
          short _lib_index;
    @@ src/codeCache.h: class FrameDesc;

      ## src/frameName.cpp ##
     @@ src/frameName.cpp: const char* FrameName::decodeNativeSymbol(const char* name) {
    -         char* demangled = Demangle::demangle(name);
    +         char* demangled = Demangle::demangle(name, _style & STYLE_SIGNATURES);
              if (demangled != NULL) {
                  if (lib_name != NULL) {
     -                _str.assign(lib_name).append("`").append(demangled);
 9:  f83d0dc !  9:  0cdd114 Use compat-glibc on x86_64 glibc
    @@ Commit message

      ## Makefile ##
     @@ Makefile: 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) -DPROFILER_VERSION=\"$(PROFILER_VERSION)\" -o $@ src/launcher/*.cpp src/jattach/*.c
        strip $@

     -PROFILER_STATIC_FLAGS=-static-libgcc
10:  6778799 ! 10:  bdf95a7 dump stats on stop
    @@ src/arguments.h: class Arguments {
     +    // Granulate Extra
     +    bool _log_meminfo_on_dump;

    -     Arguments(bool persistent = false) :
    +     Arguments() :
              _buf(NULL),
     @@ src/arguments.h: class Arguments {
              _end(NULL),
    @@ src/profiler.cpp: void Profiler::shutdown(Arguments& args) {

      ## src/profiler.h ##
     @@ src/profiler.h: class Profiler {
    -     Error stop();
    +     Error stop(bool restart = false);
          Error flushJfr();
          Error dump(std::ostream& out, Arguments& args);
     +    void logUsedMemory();
11:  1f31fdc ! 11:  37963c0 Add option to include method modifiers in frame name (#5)
    @@ src/arguments.h: class Arguments {
     +    bool _includemm;
          const char* _fdtransfer_path;
          int _style;
    -     CStack _cstack;
    +     StackWalkFeatures _features;
     @@ src/arguments.h: class Arguments {
              _title(NULL),
              _minwidth(0),
12:  b3baf60 ! 12:  af215c5 Export gProfiler-needed functionality from asprof (#7)
    @@ Metadata
      ## Commit message ##
         Export gProfiler-needed functionality from asprof (#7)

    +    In AP 3.0, @Jongy edited this commit to export fdtransfer from asprof, as jattach
    +    and jcmd were added in https://github.com/async-profiler/async-profiler/commit/b8a60e66de5399a5c8a8b84397578f5e3ab85def
    +    to upstream.
    +
      ## Makefile ##
     @@ Makefile: 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) -DPROFILER_VERSION=\"$(PROFILER_VERSION)\" -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
    -@@ Makefile: 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

      ## src/launcher/fdtransferServer.h ##
     @@ src/launcher/fdtransferServer.h: class FdTransferServer {
    @@ src/launcher/fdtransferServer_linux.cpp: bool FdTransferServer::runOnce(int pid,

      ## src/launcher/main.cpp ##
     @@ src/launcher/main.cpp: static const char USAGE_STRING[] =
    -     "  list              list profiling events supported by the target JVM\n"
    +     "  jcmd              run JVM diagnostic command (jattach action)\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"
    @@ src/launcher/main.cpp: 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"
    @@ src/launcher/main.cpp: static const char USAGE_STRING[] =

     +static const unsigned int DEFAULT_FDTRANSFER_TIMEOUT = 30;

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

     @@ src/launcher/main.cpp: class String {
              return strcmp(_str, other._str) == 0;
          }

    -+    bool operator!=(const String& other) const {
    -+        return !(*this == other);
    ++    bool operator!=(const char* other) const {
    ++        return !operator==(other);
     +    }
     +
          String& operator<<(const char* tail) {
              size_t len = strlen(_str);
              _str = (char*)realloc(_str, len + strlen(tail) + 1);
    -@@ src/launcher/main.cpp: 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;
    +@@ src/launcher/main.cpp: 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 fdtransfer_timeout = DEFAULT_FDTRANSFER_TIMEOUT;
    ++static unsigned int fdtransfer_timeout = DEFAULT_FDTRANSFER_TIMEOUT;  // gprofiler-specific: holds timeout value for fdtransfer command

      static void sigint_handler(int sig) {
          end_time = 0;
    @@ src/launcher/main.cpp: static void run_fdtransfer(int pid, String& fdtransfer) {
          } else {
              int ret = wait_for_exit(child);
              if (ret != 0) {
    -@@ src/launcher/main.cpp: 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 { exit (1); }
    -     } 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);
    -     }
    - }
    -@@ src/launcher/main.cpp: static void run_jattach(int pid, String& cmd) {
    - 
    - int main(int argc, const char** argv) {
    -     Args args(argc, argv);
    -+    String jattach_cmd;
    -     while (args.hasNext()) {
    +@@ src/launcher/main.cpp: int main(int argc, const char** argv) {
              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") {
    ++            arg == "fdtransfer") {
                  action = arg;

    -         } else if (arg == "-h" || arg == "--help") {
    +         } else if (arg == "load" || arg == "jcmd" || arg == "threaddump" || arg == "dumpheap" || arg == "inspectheap") {
     @@ src/launcher/main.cpp: int main(int argc, const char** argv) {
    - 
    -         } else if (arg == "--timeout" || arg == "--loop") {
                  params << "," << (arg.str() + 2) << "=" << args.next();
    -+
                  if (action == "collect") action = "start";

     +        } else if (arg == "--fdtransfer-timeout") {
    @@ src/launcher/main.cpp: int main(int argc, const char** argv) {
     +
              } 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());
    - 
    +             snprintf(buf, sizeof(buf), "@asprof-%d-%08x", getpid(), (unsigned int)time_micros());
     @@ src/launcher/main.cpp: 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;
    -@@ src/launcher/main.cpp: 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, "Argument --jattach-cmd was given, need no other parameters\n");
    -+        return 1;
    -+    }
    -+
    -+    if (libpath == kEmpty) {
    -+        setup_lib_path();
    -+    }
    +     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);
    +         run_jattach(pid, String("start,file=") << file << "," << output << format << params << ",log=" << logfile);

              fprintf(stderr, "Profiling for %d seconds\n", duration);
    -         end_time = time_micros() + duration * 1000000ULL;
     @@ src/launcher/main.cpp: int main(int argc, const char** argv) {
    -         signal(SIGINT, SIG_DFL);
    -         fprintf(stderr, "Done\n");
    +         // Do not reset SIGTERM handler to allow graceful shutdown

    --        run_jattach(pid, String("stop,file=") << file << "," << output << format << ",log=" << logfile);
    -+        run_jattach(pid, kJattachLoad, String("stop,file=") << file << "," << output << format << ",log=" << logfile);
    +         run_jattach(pid, String("stop,file=") << file << "," << output << format << ",log=" << logfile);
     +    } else if (action == "fdtransfer") {
    -+        if (params != kEmpty) {
    -+            fprintf(stderr, "Action fdtransfer was given, all parameters are to be passed with --jattach-cmd\n");
    ++        if (params != "") {
    ++            fprintf(stderr, "fdtransfer mode does not support parameters besides --fd-path and --fdtransfer-timeout");
     +            return 1;
     +        }
     +        run_fdtransfer(pid, fdtransfer, 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);
    +         run_jattach(pid, String(action) << ",file=" << file << "," << output << format << params << ",log=" << logfile);
          }

    -     return 0;
13:  40b850a ! 13:  952b30f Add includeln argument which includes method line number to frame (#8)
    @@ src/arguments.h: class Arguments {
     +    bool _includeln;
          const char* _fdtransfer_path;
          int _style;
    -     CStack _cstack;
    +     StackWalkFeatures _features;
     @@ src/arguments.h: class Arguments {
              _minwidth(0),
              _reverse(false),

was smooth, only Export gProfiler-needed functionality from asprof needed some modifications - I removed our addition of "jattach from asprof" and we're using the same functionality added to vanilla AP in b8a60e6.