aboutsummaryrefslogtreecommitdiff
path: root/spark-common/src
diff options
context:
space:
mode:
Diffstat (limited to 'spark-common/src')
-rw-r--r--spark-common/src/main/java/me/lucko/spark/common/sampler/async/AsyncProfilerAccess.java54
-rw-r--r--spark-common/src/main/java/me/lucko/spark/common/sampler/async/AsyncSampler.java2
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";
}