Coder Social home page Coder Social logo

clojure-goes-fast / clj-async-profiler Goto Github PK

View Code? Open in Web Editor NEW
379.0 10.0 17.0 4.66 MB

Embedded high-precision Clojure profiler

Home Page: http://clojure-goes-fast.com/kb/profiling/clj-async-profiler/

Clojure 53.66% JavaScript 32.00% HTML 8.28% Java 6.06%
clojure profiling flamegraphs

clj-async-profiler's Introduction

clj-async-profiler CircleCI

clj-async-profiler is an embedded high-precision performance profiler for Clojure. Embedded means there is no software to install on your system, instead you add the profiler to your application as a dependency. From there, you can operate the profiler either programmatically or via a web UI. During profiling, clj-async-profiler has very low overhead, so it is suitable for usage even in highly loaded production scenarios.

clj-async-profiler presents the profiling results as an interactive flamegraph. You can navigate the flamegraph, query it, change parameters and adapt the results for easier interpretation.

Example flamegraph. Click to open the interactive version.

To collect the profiling data, clj-async-profiler utilizes async-profiler which is a low overhead sampling profiler for Java. Current version of async-profiler that is used by clj-async-profiler is 3.0.

Usage

Tip

Comprehensive usage guide and in-depth documentation are available at Clojure Goes Fast knowledge base.

clj-async-profiler has the following requirements:

  • Linux or MacOS
  • JDK 1.8+. Note that clj-async-profiler requires JDK, it won't run on JRE.
  • Clojure 1.10+

On Linux, you need to allow async-profiler to use kernel profiling data by setting these two variables (see also):

sudo sysctl -w kernel.perf_event_paranoid=1
sudo sysctl -w kernel.kptr_restrict=0

Next, add com.clojure-goes-fast/clj-async-profiler to your dependencies. This is the latest version:

On JDK 11 and later, you must start your application with JVM option -Djdk.attach.allowAttachSelf, otherwise the profiling agent will not be able to dynamically attach to the running process.

  • With tools.deps, add :jvm-opts ["-Djdk.attach.allowAttachSelf"] to an alias in deps.edn and enable that alias, or add -J-Djdk.attach.allowAttachSelf explicitly to your REPL command.
  • With Leiningen, add :jvm-opts ["-Djdk.attach.allowAttachSelf"] to project.clj.

clj-async-profiler.core exposes an all-in-one facade for generating profiling flame graphs. The most common usage scenario looks like this:

(require '[clj-async-profiler.core :as prof])

;; Profile the following expression:
(prof/profile (dotimes [i 10000] (reduce + (range i))))

;; The resulting flamegraph will be stored in /tmp/clj-async-profiler/results/
;; You can view the HTML file directly from there or start a local web UI:

(prof/serve-ui 8080) ; Serve on port 8080

You can also start and stop the profiler manually with prof/start and prof/stop.

Each profiling command accepts a map of options. See docstrings for each command for the list of supported options, or Functions and options.

Option map for each profiling command can have a :pid value. If it is provided, an external JVM process with this PID will be sampled, otherwise the current process is targeted.

For a detailed description of clj-async-profiler's more advanced features, see the documentation pages:

Also check out this video from London Clojurians meetup:

Clojure Goes Brrr: a quest for performance

Tuning for better accuracy

From async-profiler README: It is highly recommended to use -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints JVM flags. Without those flags the profiler will still work correctly but results might be less accurate. Without these options, there is a high chance that simple inlined methods will not appear in the profile. When agent is attached at runtime, CompiledMethodLoad JVMTI event enables debug info, but only for methods compiled after the event is turned on.

If you see stackframes like /usr/lib/.../libjvm.so in the flamegraph, it means that you have to install JDK debug symbols. E.g., on Ubuntu that would be the package openjdk-11-dbg.

Output directory

By default, clj-async-profiler writes its output files to /tmp/clj-async-profiler/. You can change it to a custom directory (e.g., if you run clj-async-profiler in an environment where /tmp is not sufficiently large) by setting Java property clj-async-profiler.output-dir:

clojure -J-Dclj-async-profiler.output-dir=./data ...

Platform support

clj-async-profiler ships with the precompiled native libraries that async-profiler itself distributes. These include:

  • Linux: x64, aarch64 (arm64)
  • MacOS: x64/aarch64 (universal binary)

To use clj-async-profiler on other supported platforms, you should do the following:

  1. Build async-profiler for the desired platform.

  2. Put the resulting libasyncProfiler.so in a place accessible by your JVM process (and which also allows code execution from).

  3. Execute from Clojure:

    (reset! prof/async-profiler-agent-path "/path/to/libasyncProfiler.so")

Development

tools.deps is used as a build tool. Regular build tasks are inside build.clj and invoked as clojure -T:build test, clojure -T:build jar, etc.

When starting the REPL, you should add dev alias on the list so that virgil is loaded. Then, to compile Java classes in the REPL, do:

user> ((requiring-resolve 'virgil/compile-java) ["src"])

License

async-profiler is distributed under Apache-2.0. See APACHE_PUBLIC_LICENSE file. The location of the original repository is https://github.com/jvm-profiling-tools/async-profiler.

Copyright 2017-2024 Andrei Pangin


clj-async-profiler is distributed under the Eclipse Public License. See ECLIPSE_PUBLIC_LICENSE.

Copyright 2017-2024 Alexander Yakushev

clj-async-profiler's People

Contributors

alexander-yakushev avatar avocade avatar imrekoszo avatar jeaye avatar jumarko avatar r6eve avatar samrat avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

clj-async-profiler's Issues

unable to run profiling due to invalid module access in java 17?

java.lang.reflect.InaccessibleObjectException: Unable to make field private final sun.management.VMManagement sun.management.RuntimeImpl.jvm accessible: module java.management does not "opens sun.management" to unnamed module @38dacb78

this is after adding "--add-opens=java.management/sun.management=ALL-UNNAMED" to the command line (via project.clj jvm-opts) and confirming that it is being added to the command line.

Errors generating flamegraph using java-temurin-20.0.1+9 with 1.2.0

Consistently get this error after stopping profiling. I can use the brendan gregg's flamegraph perl script to generate usable (static) svg flamegraphs, so I have reasonable confidence that the data in the raw .txt file isn't garbage.

java.lang.IncompatibleClassChangeError: Method 'java.util.Comparator java.util.Map$Entry.comparingByKey()' must be InterfaceMethodref constant              
        at clj_async_profiler.post_processing$raw_profile__GT_compact_profile.invoke(post_processing.clj:72)                                                                                  
        at clj_async_profiler.post_processing$read_raw_profile_file_to_compact_profile.invoke(post_processing.clj:95)                                                                         
        at clj_async_profiler.core$generate_flamegraph.invoke(core.clj:286)                                                                                                                   
        at clj_async_profiler.core$stop.invoke(core.clj:347)                                                                                                                                  
        at clj_async_profiler.core$stop.invoke(core.clj:331)                                                                                                                                  
        ....the rest of the frames are app code that I can't disclose...

I'm currently trying to wade through the code to understand enough to either solve it or give better information.

Troubleshooting section

I'm not sure if this is the right place, but I struggled to use the library with Docker Compose.

I was able to overcome the issue; however, when I received the error message "Cannot attach to current VM" and searched the internet, I didn't find anything really useful and struggled to fix it.

My suggestion is to have a troubleshooting section in the README.md that would have saved me time.

I will try contributing with this troubleshooting, but will need a time to make it efficient.

Really good project.

Execution error (FileNotFoundException) at clojure-rte.rte-core/eval13090

I'm trying to run this library for the first time on Mac
Screenshot 2020-10-16 at 12 41 44

  Model Name:	MacBook Pro
  Model Identifier:	MacBookPro15,2
  Processor Name:	Quad-Core Intel Core i7
  Processor Speed:	2.7 GHz
  Number of Processors:	1
  Total Number of Cores:	4
  L2 Cache (per Core):	256 KB
  L3 Cache:	8 MB
  Hyper-Threading Technology:	Enabled
  Memory:	16 GB

I see that code seems to have been downloaded. But when I try to evaluate (require '[clj-async-profiler.core :as prof]) I get a strange error. I retried with lein clean before and then lein repl, but the same problem seems to happen.

[geminiani:~/Repos/clojure-rte] jimka% lein repl
Retrieving com/clojure-goes-fast/clj-async-profiler/0.4.1/clj-async-profiler-0.4.1.pom from clojars
Retrieving com/clojure-goes-fast/clj-async-profiler/0.4.1/clj-async-profiler-0.4.1.jar from clojars
nREPL server started on port 60660 on host 127.0.0.1 - nrepl://127.0.0.1:60660
REPL-y 0.4.4, nREPL 0.7.0
Clojure 1.10.0
OpenJDK 64-Bit Server VM 11.0.7+10
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e

clojure-rte.rte-core=> (require '[clj-async-profiler.core :as prof])
Execution error (FileNotFoundException) at clojure-rte.rte-core/eval13088 (form-init3039314401959532405.clj:1).
Could not locate clj_async_profiler/core__init.class, clj_async_profiler/core.clj or clj_async_profiler/core.cljc on classpath. Please check that namespaces with dashes use underscores in the Clojure file name.

Support for OpenJDK?

I'm attempting to use this with OpenJDK 8 and 16; in both cases, I get the following failure:

(prof/profile (test-benchmark :deep))
Execution error (ExceptionInfo) at clj-async-profiler.core/start (core.clj:264).
Could not find libjvm among loaded libraries. Unsupported JVM?

Are the underlying libraries dependent on Oracle JDK or should they work with OpenJDK and I'm just doing something wrong?

I'm on Mac OS X, and have installed OpenJDK using Homebrew.

Is it possible to generate a diffgraph from the UI and from different runs?

The documentation for diffgraph describes a means for generating a diffgraph using the repl and seemingly only between runs from the same process. Is it possible to generate them somehow from the UI and across different runs?

I'm assuming that it's NOT possible as code is currently written, otherwise you'd describe it. I think the question I'm really asking is whether there is something that fundamentally prevents such a diff, e.g., the data from two runs lacks sufficient context to properly diff them, or whether it's simply that nobody's done the plumbing to set it up yet.

Profiling doesn't work on Alpine docker images out of the box

Hello,
The profiler wasn't working for me from inside Alpine docker images (related to #12) and I managed to refine down the steps required to make it work. Some could be additions to the profiler itself, some are just requirements which have to be satisfied:

  • The musl compatible .so is missing. Adding it as a resource is the simplest part.
  • There's no detection if running in a musl environment or regular linux kernel. Besides resetting the .so path manually there's no comfortable solution.
  • Without jdk installed the virtual machine class is missing. Can be remedied by adding com.sun/tools as a dependency or specify it should be required externally by the project.
    There's also an issue with it not being in the regular maven repositories, each version is in another repository entirely, and some of them don't provide https. Has success with [com.sun/tools "1.7.0.13"] and :repositories [["nuition" "https://nexus.nuiton.org/nexus/content/groups/releases/"]]
  • alpine packages requirements: apk add libstdc++ perl

Then the profiler works from inside a docker image (phew)

Reflection Warnings

0.2.2 yields the following:

Reflection warning, clj_async_profiler/server.clj:17:4 - call to method sendResponseHeaders can't be resolved (target class is unknown).
Reflection warning, clj_async_profiler/server.clj:18:10 - reference to field getResponseBody can't be resolved.
Reflection warning, clj_async_profiler/server.clj:19:14 - reference to field getBytes can't be resolved.
Reflection warning, clj_async_profiler/server.clj:19:6 - call to method write can't be resolved (target class is unknown).
Reflection warning, clj_async_profiler/server.clj:20:6 - reference to field close can't be resolved.
Reflection warning, clj_async_profiler/server.clj:33:29 - call to method lastIndexOf can't be resolved (target class is unknown).
Reflection warning, clj_async_profiler/server.clj:33:3 - call to method substring can't be resolved (target class is unknown).
Reflection warning, clj_async_profiler/server.clj:36:28 - reference to field getName can't be resolved.
Reflection warning, clj_async_profiler/server.clj:37:27 - reference to field getRequestMethod can't be resolved.
Reflection warning, clj_async_profiler/server.clj:38:16 - reference to field length can't be resolved.
Reflection warning, clj_async_profiler/server.clj:39:11 - reference to field getResponseHeaders can't be resolved.
Reflection warning, clj_async_profiler/server.clj:40:7 - call to method add can't be resolved (target class is unknown).
Reflection warning, clj_async_profiler/server.clj:41:7 - call to method add can't be resolved (target class is unknown).
Reflection warning, clj_async_profiler/server.clj:43:5 - call to method sendResponseHeaders can't be resolved (target class is unknown).
Reflection warning, clj_async_profiler/server.clj:47:40 - reference to field getResponseBody can't be resolved.
Reflection warning, clj_async_profiler/server.clj:56:60 - reference to field getRequestURI can't be resolved.
Reflection warning, clj_async_profiler/server.clj:60:21 - reference to field getResponseHeaders can't be resolved.
Reflection warning, clj_async_profiler/server.clj:60:15 - call to method add can't be resolved (target class is unknown).
Reflection warning, clj_async_profiler/server.clj:74:25 - call to method stop on java.lang.Object can't be resolved (no such method).
Reflection warning, clj_async_profiler/core.clj:77:8 - call to method addURL on java.lang.Object can't be resolved (no such method).
Reflection warning, clj_async_profiler/core.clj:162:16 - call to method getDeclaredMethod on java.lang.Object can't be resolved (no such method).
Reflection warning, clj_async_profiler/core.clj:163:5 - call to method invoke can't be resolved (target class is unknown).
Reflection warning, clj_async_profiler/core.clj:183:10 - call to method loadAgentPath can't be resolved (target class is unknown).
Reflection warning, clj_async_profiler/core.clj:258:22 - call to method contains on java.lang.Object can't be resolved (no such method).

Possible to use as standalone application?

For some profiling where we cannot currently inject the profiler into the application we use the standard async-profiler by launching it from the command line with a process id specified, as described here: https://github.com/async-profiler/async-profiler/tree/v2.9#wall-clock-profiling

Can this be done using clj-async-profiler?
If yes, could you please point me to where it is documented, as I haven't succeeded in finding it.
If not, would it be in line with the goals of this project to have such an entry point made?

Running within a Docker container

I'm trying to use this from within a leiningen process within a Docker container, and calling prof/start! threw this error:

[WARN] perf_event_open for TID 311 failed: Operation not permitted
[ERROR] No access to perf events. Try --fdtransfer or --all-user option or 'sysctl kernel.perf_event_paranoid=1'

There's this page from the jvm async-profiler, but I couldn't figure out how to apply those settings through clj-async-profiler.

Have any ideas?

UI server is blocking graceful application shutdown

While developing my application that uses this library I noticed that the ui-server is blocking the shutdown of the application. It would be nice to have a function to stop the UI HTTP server in the core namespace so that the application can gracefully shutdown.

I'm happy to open a PR with the necessary changes.

Setup documentation is a bit lacking

I had some issue with setting the project on my machine:

  • The tools-jar-loaded function does not seem to work when running from lein, I had to use lein-jdk-tools plugin.

  • I had to enable non root perf support:

  $ echo 0 > /proc/sys/kernel/kptr_restrict
  $ echo 1 > /proc/sys/kernel/perf_event_paranoid

Error when using 0.2.0+

dev=> (require 'clj-async-profiler.core)
nil
dev=> (clj-async-profiler.core/profile {:return-file true}
 #_=>                                  true)
Execution error (ClassNotFoundException) at java.net.URLClassLoader/findClass (URLClassLoader.java:382).
com.sun.tools.attach.VirtualMachine
❯ java -version          
java version "1.8.0_202"
Java(TM) SE Runtime Environment (build 1.8.0_202-b08)
Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode)

OS: Linux x64

0.2.0+ gives me:

dev=> (clj-async-profiler.core/profile {:return-file true}
 #_=>                                  true)
Execution error (NullPointerException) at clj-async-profiler.core/mk-vm (core.clj:162).
null

(NumberFormatException) at java.lang.NumberFormatException/forInputString

Stacktrace pointed me to post-process-stacks:

NumberFormatException For input string: ""                                                                                                                                                                                                                  
        java.lang.NumberFormatException.forInputString (NumberFormatException.java:65)                                                                                                                                                                      
        java.lang.Long.parseLong (Long.java:601)                                                                                                                                                                                                            
        java.lang.Long.<init> (Long.java:965)                                                                                                                                                                                                               
        clj-async-profiler.post-processing/post-process-stacks/fn--89359 (NO_SOURCE_FILE:104)                                                                                                                                                               
        clj-async-profiler.post-processing/post-process-stacks (NO_SOURCE_FILE:98)                                                                                                                                                                          
        clj-async-profiler.post-processing/post-process-stacks (NO_SOURCE_FILE:92)                                                                                                                                                                          
        clj-async-profiler.core/generate-flamegraph (core.clj:265)                                                                                                                                                                                          
        clj-async-profiler.core/generate-flamegraph (core.clj:257)                                                                                                                                                                                          
        clj-async-profiler.core/stop (core.clj:321)                                                                                                                                                                                                         
        clj-async-profiler.core/stop (core.clj:290)                                                                                                                                                                                                          

The line was missing anything after the space?!

Unable to start profiler

First of all, thank you for the great tool!

Unfortunately, I am having issues starting the profiler using Docker images:

  • eclipse-temurin:17-jre-ubi9-minimal
  • eclipse-temurin:19-jre-ubi9-minimal
  • eclipse-temurin:21-jre-ubi9-minimal

First I got:

java.lang.reflect.InaccessibleObjectException: Unable to make protected void java.net.URLClassLoader.addURL(java.net.URL) accessible: module java.base does not "opens java.net" to unnamed module @6ab1d6ac
        at java.base/java.lang.reflect.AccessibleObject.throwInaccessibleObjectException(Unknown Source)
        at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(Unknown Source)
        at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(Unknown Source)
        at java.base/java.lang.reflect.Method.checkCanSetAccessible(Unknown Source)
        at java.base/java.lang.reflect.Method.setAccessible(Unknown Source)
        at clj_async_profiler.core$add_url_to_classloader_reflective.invokeStatic(core.clj:54)
        at clj_async_profiler.core$fn__15318.invokeStatic(core.clj:87)
        at clj_async_profiler.core$fn__15318.invoke(core.clj:82)
        at clojure.lang.Delay.deref(Delay.java:42)
        at clojure.core$deref.invokeStatic(core.clj:2337)
        at clj_async_profiler.core$get_virtualmachine_class.invokeStatic(core.clj:93)
        at clj_async_profiler.core$mk_vm.invokeStatic(core.clj:192)
        at clj_async_profiler.core$attach_agent.invokeStatic(core.clj:210)
        at clj_async_profiler.core$start.invokeStatic(core.clj:268)

When I add JVM arg: --add-opens=java.base/java.net=ALL-UNNAMED, then I receive the following:

java.lang.IllegalArgumentException: object is not an instance of declaring class
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.checkReceiver(Unknown Source)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source)
        at java.base/java.lang.reflect.Method.invoke(Unknown Source)
        at clj_async_profiler.core$add_url_to_classloader_reflective.invokeStatic(core.clj:55)
        at clj_async_profiler.core$fn__15318.invokeStatic(core.clj:87)
        at clj_async_profiler.core$fn__15318.invoke(core.clj:82)
        at clojure.lang.Delay.deref(Delay.java:42)
        at clojure.core$deref.invokeStatic(core.clj:2337)
        at clj_async_profiler.core$get_virtualmachine_class.invokeStatic(core.clj:93)
        at clj_async_profiler.core$mk_vm.invokeStatic(core.clj:192)
        at clj_async_profiler.core$attach_agent.invokeStatic(core.clj:210)
        at clj_async_profiler.core$start.invokeStatic(core.clj:268)

Is there any trick that I missed? :)

Empty output, + ERROR: No stack counts found

Hi. Thank you for bringing attention to async-profiler, and for creating this package.

I've tried running an example you've provided on the homepage and the introductory blog post, and, while the package seems to work, the resulting /tmp/clj-async-profiler/... txt files are empty. The SVG file that prof/stop returns does not exist on disk.

The only complaint from (clj-)async-profiler is an error message printed in the repl (probably to err by the native binary itself) that says "ERROR: No stack counts found".

My system is a recent Arch Linux, OpenJDK 8, clj-async-profiler 0.1.3.

Any hints?

clj-async-profiler on WSL in `:itimer` doesn't generate data

I'm trying to use clj-async-profiler on WSL.

WSL is not supported when :cpu profiling is set but async-profiler authors recommend using :itimer instead. But :itimer unfortunatelly doesn't generate any data (files are empty) with error:

Execution error (ExceptionInfo) at clj-async-profiler.core/run-flamegraph-script (core.clj:142).
ERROR: No stack counts found

:alloc profiling works.

I'm not sure if it's related to clj-async-profiler or maybe async-profiler itself (I don't know how to check it).

More details:

  • WSL 1.0, with Linux kernel 4.4 (Ubuntu 18.04.3)
  • OpenJDK 11.0.5
  • Clojure 1.10.1
  • Lein 2.9.1, run as lein repl (connection from Emacs/Cider)
  • tested on supported libasyncProfiler.so and locally compiled
  • tested with recommended JVM settings

Regression from 0.4.0 -> 0.4.1

When running the hello world from the home page, I get a ClassCastException that LinuxVirtualMachine cannot be cast to VirtualMachine.

With 0.4.0 everything works as expected.

Is there any new requirement introduced in the meantime?

My specs: Arch Linux (latest), Open JDK 1.8.0_242. Using leiningen.

hot spots

Imagine a flame graph like

|-X-|----Y----|---X---|--X--|-X-|
|-----A1------|---C1--|--D1-|-E1|
|-----A-------|---C---|--D--|-E-|

We see most of the time was spent in A and there in Y, however after a closer look one might see X is the method where most of the CPU time is being spent. With an arbitrarily complex call tree it gets extremely complex to find such culprits in the flame graph.

What I'm trying to say is that there's several ways to look at the results:

  • looking from bottom we can say A is taking longest to run, therefore we need to optimize it. Maybe Y can be optimized. Maybe calls to A can be partially cached. Maybe ...
  • looking from execution time we can say X took longest to run, therefore optimizing it will yield great overall benefits.

Is there a way to obtain the latter results? In the underlying async-profiler I see something similar being printed to the JVM's console output, maybe giving access to that would be a start?

Document dependencies / vague init error

I was having an issue trying to use the profiler:

> (prof/start {})
AgentLoadException Failed to load agent library  sun.tools.attach.LinuxVirtualMachine.execute (LinuxVirtualMachine.java:224)

1. Unhandled com.sun.tools.attach.AgentLoadException
   Failed to load agent library

  LinuxVirtualMachine.java:  224  sun.tools.attach.LinuxVirtualMachine/execute
HotSpotVirtualMachine.java:   58  sun.tools.attach.HotSpotVirtualMachine/loadAgentLibrary
HotSpotVirtualMachine.java:   88  sun.tools.attach.HotSpotVirtualMachine/loadAgentPath
NativeMethodAccessorImpl.java:   -2  sun.reflect.NativeMethodAccessorImpl/invoke0
NativeMethodAccessorImpl.java:   62  sun.reflect.NativeMethodAccessorImpl/invoke
DelegatingMethodAccessorImpl.java:   43  sun.reflect.DelegatingMethodAccessorImpl/invoke
               Method.java:  498  java.lang.reflect.Method/invoke
            Reflector.java:   93  clojure.lang.Reflector/invokeMatchingMethod
            Reflector.java:   28  clojure.lang.Reflector/invokeInstanceMethod
                  core.clj:  109  clj-async-profiler.core/attach-agent
                  core.clj:  103  clj-async-profiler.core/attach-agent
                  core.clj:  124  clj-async-profiler.core/start
                  core.clj:  116  clj-async-profiler.core/start
                  core.clj:  121  clj-async-profiler.core/start
                  core.clj:  116  clj-async-profiler.core/start
                      REPL:  485  my.ns/eval23126

So after some debugging it boiled down to:

> (System/load "/tmp/clj-async-profiler/libasyncProfiler-linux.so")
UnsatisfiedLinkError /tmp/clj-async-profiler/libasyncProfiler-linux.so: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by /tmp/clj-async-profiler/libasyncProfiler-linux.so)  java.lang.ClassLoader$NativeLibrary.load (ClassLoader.java:-2)

and

$ ldd /tmp/clj-async-profiler/libasyncProfiler-linux.so 
ldd: warning: you do not have execution permission for `/tmp/clj-async-profiler/libasyncProfiler-linux.so'
/tmp/clj-async-profiler/libasyncProfiler-linux.so: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by /tmp/clj-async-profiler/libasyncProfiler-linux.so)
	linux-vdso.so.1 =>  (0x00007ffdeb1ef000)
	libdl.so.2 => /lib64/libdl.so.2 (0x00007f7209974000)
	libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f7209757000)
	libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007f720944f000)
	libm.so.6 => /lib64/libm.so.6 (0x00007f72091cb000)
	libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f7208fb5000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f7208c20000)
	/lib64/ld-linux-x86-64.so.2 (0x0000562f0bec9000)

The system I run this on has a bit older version of libc.

It would be great to make this kind of errors more transparent, perhaps by having more than just "Failed to load agent library" message and/or documenting the required dependencies in the wiki.

Choose output dir

Instead of hardcoded /tmp, which doesn't really work on some machines (like on Fly.io).

Any possible support for metadata?

Hey, this is a great project thanks so much for making it =)...

I was just wondering if there's any way I could pass in a map of :metadata arguments to the profile which would then get written into the result? It would just make it much easier to pass in stuff like version numbers so when I'm looking back at historical profiles I can see for example what commit hash produced it, so when I'd doing comparisons I'm pretty sure what I'm looking at.

Does the underlying format have support for adding attributes like that? Or should I be looking to record this sort of stuff on my side? No problem if that's the case btw =)...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.