diff --git a/common/src/java/org/apache/hive/http/ProfileServlet.java b/common/src/java/org/apache/hive/http/ProfileServlet.java index c2ff2712938f..c1260e4a3fda 100644 --- a/common/src/java/org/apache/hive/http/ProfileServlet.java +++ b/common/src/java/org/apache/hive/http/ProfileServlet.java @@ -17,6 +17,9 @@ import java.io.File; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; @@ -45,19 +48,19 @@ * // -m method fully qualified method name: 'ClassName.methodName' * // -t profile different threads separately * // -s simple class names instead of FQN - * // -o fmt[,fmt...] output format: summary|traces|flat|collapsed|svg|tree|jfr + * // -o fmt[,fmt...] output format: summary|traces|flat|collapsed|svg|tree|jfr|html * // --width px SVG width pixels (integer) * // --height px SVG frame height pixels (integer) * // --minwidth px skip frames smaller than px (double) * // --reverse generate stack-reversed FlameGraph / Call tree * Example: - * - To collect 30 second CPU profile of current process (returns FlameGraph svg) + * - To collect 10 second CPU profile of current process (returns FlameGraph html) * curl "http://localhost:10002/prof" * - To collect 1 minute CPU profile of current process and output in tree format (html) * curl "http://localhost:10002/prof?output=tree&duration=60" - * - To collect 30 second heap allocation profile of current process (returns FlameGraph svg) + * - To collect 10 second heap allocation profile of current process (returns FlameGraph html) * curl "http://localhost:10002/prof?event=alloc" - * - To collect lock contention profile of current process (returns FlameGraph svg) + * - To collect lock contention profile of current process (returns FlameGraph html) * curl "http://localhost:10002/prof?event=lock" * Following event types are supported (default is 'cpu') (NOTE: not all OS'es support all events) * // Perf events: @@ -89,7 +92,6 @@ public class ProfileServlet extends HttpServlet { private static final String CONTENT_TYPE_TEXT = "text/plain; charset=utf-8"; private static final String ASYNC_PROFILER_HOME_ENV = "ASYNC_PROFILER_HOME"; private static final String ASYNC_PROFILER_HOME_SYSTEM_PROPERTY = "async.profiler.home"; - private static final String PROFILER_SCRIPT = "/profiler.sh"; private static final int DEFAULT_DURATION_SECONDS = 10; private static final AtomicInteger ID_GEN = new AtomicInteger(0); static final String OUTPUT_DIR = System.getProperty("java.io.tmpdir") + "/prof-output"; @@ -141,7 +143,8 @@ enum Output { COLLAPSED, SVG, TREE, - JFR + JFR, + HTML } private Lock profilerLock = new ReentrantLock(); @@ -213,7 +216,7 @@ protected void doGet(final HttpServletRequest req, final HttpServletResponse res (method == null ? event.name().toLowerCase() : method) + "-" + ID_GEN.incrementAndGet() + "." + output.name().toLowerCase()); List cmd = new ArrayList<>(); - cmd.add(asyncProfilerHome + PROFILER_SCRIPT); + cmd.add(getProfilerScriptPath()); cmd.add("-e"); cmd.add(method == null ? event.getInternalName() : method); cmd.add("-d"); @@ -293,6 +296,16 @@ protected void doGet(final HttpServletRequest req, final HttpServletResponse res } } + /** + * Get the path of the profiler script to be executed. + * Before async-profiler 3.0, the script was named profiler.sh, and after 3.0 it's bin/asprof + * @return + */ + private String getProfilerScriptPath() { + Path defaultPath = Paths.get(asyncProfilerHome + "/bin/asprof"); + return Files.exists(defaultPath)? defaultPath.toString() : asyncProfilerHome + "/profiler.sh"; + } + private Integer getInteger(final HttpServletRequest req, final String param, final Integer defaultValue) { final String value = req.getParameter(param); if (value != null) { @@ -340,14 +353,16 @@ private Event getEvent(final HttpServletRequest req) { private Output getOutput(final HttpServletRequest req) { final String outputArg = req.getParameter("output"); + String outputFormat = outputArg.trim().toUpperCase(); if (req.getParameter("output") != null) { try { - return Output.valueOf(outputArg.trim().toUpperCase()); + return Output.valueOf(outputFormat); } catch (IllegalArgumentException e) { - return Output.SVG; + LOG.warn("Output format value '{}' is invalid, returning with default HTML", outputFormat); + return Output.HTML; } } - return Output.SVG; + return Output.HTML; } private void setResponseHeader(final HttpServletResponse response) {