diff options
Diffstat (limited to 'spark-common/src/main/java')
-rw-r--r-- | spark-common/src/main/java/me/lucko/spark/common/sampler/async/AsyncProfilerAccess.java | 54 | ||||
-rw-r--r-- | spark-common/src/main/java/me/lucko/spark/common/sampler/async/AsyncSampler.java | 2 |
2 files changed, 48 insertions, 8 deletions
diff --git a/spark-common/src/main/java/me/lucko/spark/common/sampler/async/AsyncProfilerAccess.java b/spark-common/src/main/java/me/lucko/spark/common/sampler/async/AsyncProfilerAccess.java index 06db795..3dfbbbf 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/sampler/async/AsyncProfilerAccess.java +++ b/spark-common/src/main/java/me/lucko/spark/common/sampler/async/AsyncProfilerAccess.java @@ -45,22 +45,31 @@ public enum AsyncProfilerAccess { /** An instance of the async-profiler Java API. */ private final AsyncProfiler profiler; + /** The event to use for profiling */ + private final ProfilingEvent profilingEvent; + /** If profiler is null, contains the reason why setup failed */ private final Exception setupException; AsyncProfilerAccess() { AsyncProfiler profiler; + ProfilingEvent profilingEvent = null; Exception setupException = null; try { profiler = load(); - ensureCpuEventSupported(profiler); + if (isEventSupported(profiler, ProfilingEvent.CPU, false)) { + profilingEvent = ProfilingEvent.CPU; + } else if (isEventSupported(profiler, ProfilingEvent.ITIMER, true)) { + profilingEvent = ProfilingEvent.ITIMER; + } } catch (Exception e) { profiler = null; setupException = e; } this.profiler = profiler; + this.profilingEvent = profilingEvent; this.setupException = setupException; } @@ -71,11 +80,18 @@ public enum AsyncProfilerAccess { return this.profiler; } + public ProfilingEvent getProfilingEvent() { + return this.profilingEvent; + } + public boolean checkSupported(SparkPlatform platform) { if (this.setupException != null) { if (this.setupException instanceof UnsupportedSystemException) { platform.getPlugin().log(Level.INFO, "The async-profiler engine is not supported for your os/arch (" + this.setupException.getMessage() + "), so the built-in Java engine will be used instead."); + } else if (this.setupException instanceof NativeLoadingException && this.setupException.getCause().getMessage().contains("libstdc++")) { + platform.getPlugin().log(Level.WARNING, "Unable to initialise the async-profiler engine because libstdc++ is not installed."); + platform.getPlugin().log(Level.WARNING, "Please see here for more information: https://spark.lucko.me/docs/misc/Using-async-profiler#install-libstdc"); } else { platform.getPlugin().log(Level.WARNING, "Unable to initialise the async-profiler engine: " + this.setupException.getMessage()); platform.getPlugin().log(Level.WARNING, "Please see here for more information: https://spark.lucko.me/docs/misc/Using-async-profiler"); @@ -118,7 +134,7 @@ public enum AsyncProfilerAccess { try { return AsyncProfiler.getInstance(extractPath.toAbsolutePath().toString()); } catch (UnsatisfiedLinkError e) { - throw new RuntimeException("A runtime error occurred whilst loading the native library", e); + throw new NativeLoadingException(e); } } @@ -126,12 +142,30 @@ public enum AsyncProfilerAccess { * Checks the {@code profiler} to ensure the CPU event is supported. * * @param profiler the profiler instance - * @throws Exception if the event is not supported + * @return if the event is supported */ - private static void ensureCpuEventSupported(AsyncProfiler profiler) throws Exception { - String resp = profiler.execute("check,event=cpu").trim(); - if (!resp.equalsIgnoreCase("ok")) { - throw new UnsupportedOperationException("CPU event is not supported"); + private static boolean isEventSupported(AsyncProfiler profiler, ProfilingEvent event, boolean throwException) { + try { + String resp = profiler.execute("check,event=" + event).trim(); + if (resp.equalsIgnoreCase("ok")) { + return true; + } else if (throwException) { + throw new IllegalArgumentException(resp); + } + } catch (Exception e) { + if (throwException) { + throw new RuntimeException("Event " + event + " is not supported", e); + } + } + return false; + } + + enum ProfilingEvent { + CPU, ITIMER; + + @Override + public String toString() { + return name().toLowerCase(Locale.ROOT); } } @@ -140,4 +174,10 @@ public enum AsyncProfilerAccess { super(os + '/' + arch); } } + + private static final class NativeLoadingException extends RuntimeException { + public NativeLoadingException(Throwable cause) { + super("A runtime error occurred whilst loading the native library", cause); + } + } } diff --git a/spark-common/src/main/java/me/lucko/spark/common/sampler/async/AsyncSampler.java b/spark-common/src/main/java/me/lucko/spark/common/sampler/async/AsyncSampler.java index 62325ae..5d587a0 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/sampler/async/AsyncSampler.java +++ b/spark-common/src/main/java/me/lucko/spark/common/sampler/async/AsyncSampler.java @@ -99,7 +99,7 @@ public class AsyncSampler extends AbstractSampler { throw new RuntimeException("Unable to create temporary output file", e); } - String command = "start,event=cpu,interval=" + this.interval + "us,threads,jfr,file=" + this.outputFile.toString(); + String command = "start,event=" + AsyncProfilerAccess.INSTANCE.getProfilingEvent() + ",interval=" + this.interval + "us,threads,jfr,file=" + this.outputFile.toString(); if (this.threadDumper instanceof ThreadDumper.Specific) { command += ",filter"; } |