HDDS-4984. Support async profiler 2.0 (#2048)

diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/http/ProfileServlet.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/http/ProfileServlet.java
index 02e00fd..56c4f78 100644
--- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/http/ProfileServlet.java
+++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/http/ProfileServlet.java
@@ -46,20 +46,33 @@
  * Source: https://github.com/apache/hive/blob/master/common/src/java/org
  * /apache/hive/http/ProfileServlet.java
  * <p>
- * Following options from async-profiler can be specified as query paramater.
+ * Following options from async-profiler can be specified as query parameter.
  * //  -e event          profiling event: cpu|alloc|lock|cache-misses etc.
- * //  -d duration       run profiling for <duration> seconds (integer)
- * //  -i interval       sampling interval in nanoseconds (long)
- * //  -j jstackdepth    maximum Java stack depth (integer)
- * //  -b bufsize        frame buffer size (long)
+ * //  -d duration       run profiling for <duration> seconds
+ * //  -f filename       dump output to <filename>
+ * //  -i interval       sampling interval in nanoseconds
+ * //  -j jstackdepth    maximum Java stack depth
  * //  -t                profile different threads separately
  * //  -s                simple class names instead of FQN
- * //  -o fmt[,fmt...]   output format:
- * summary|traces|flat|collapsed|svg|tree|jfr
- * //  --width px        SVG width pixels (integer)
- * //  --height px       SVG frame height pixels (integer)
- * //  --minwidth px     skip frames smaller than px (double)
+ * //  -g                print method signatures
+ * //  -a                annotate Java method names
+ * //  -o fmt            output format:
+ * flat|traces|collapsed|flamegraph|tree|jfr
+ * //  -I include        output only stack traces
+ * containing the specified pattern
+ * //  -X exclude        exclude stack traces with the specified pattern
+ * //  -v, --version     display version string
+ * //  --title string    FlameGraph title
+ * //  --minwidth pct    skip frames smaller than pct%
  * //  --reverse         generate stack-reversed FlameGraph / Call tree
+ * //  --alloc bytes     allocation profiling interval in bytes
+ * //  --lock duration   lock profiling threshold in nanoseconds
+ * //  --total           accumulate the total value (time, bytes, etc.)
+ * //  --all-user        only include user-mode events
+ * //  --cstack mode     how to traverse C stack: fp|lbr|no
+ * //  --begin function  begin profiling when function is executed
+ * //  --end function    end profiling when function is executed
+ * //  --ttsp            time-to-safepoint profiling
  * Example:
  * - To collect 30 second CPU profile of current process (returns FlameGraph
  * svg)
@@ -174,10 +187,13 @@
   @VisibleForTesting
   protected static String generateFileName(Integer pid, Output output,
       Event event) {
+    String outputFormat = output.name().toLowerCase();
+    if(output == Output.FLAMEGRAPH) {
+      outputFormat = "html";
+    }
     return FILE_PREFIX + pid + "-" +
         event.name().toLowerCase() + "-" + ID_GEN.incrementAndGet()
-        + "." +
-        output.name().toLowerCase();
+        + "." + outputFormat;
   }
 
   @VisibleForTesting
@@ -365,7 +381,9 @@
           "This page will auto-refresh every 2 second until output file is "
               + "ready..");
     } else {
-      if (safeFileName.endsWith(".svg")) {
+      if (safeFileName.endsWith(".html")) {
+        resp.setContentType("text/html");
+      } else if (safeFileName.endsWith(".svg")) {
         resp.setContentType("image/svg+xml");
       } else if (safeFileName.endsWith(".tree")) {
         resp.setContentType("text/html");
@@ -500,7 +518,8 @@
     COLLAPSED,
     SVG,
     TREE,
-    JFR
+    JFR,
+    FLAMEGRAPH
   }
 
 }
diff --git a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/http/TestProfileServlet.java b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/http/TestProfileServlet.java
index 8890c1c..a7fcba4 100644
--- a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/http/TestProfileServlet.java
+++ b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/http/TestProfileServlet.java
@@ -32,8 +32,9 @@
   @Test
   public void testNameValidation() throws IOException {
     ProfileServlet.validateFileName(
+        ProfileServlet.generateFileName(1, Output.FLAMEGRAPH, Event.ALLOC));
+    ProfileServlet.validateFileName(
         ProfileServlet.generateFileName(1, Output.SVG, Event.ALLOC));
-
     ProfileServlet.validateFileName(
         ProfileServlet.generateFileName(23, Output.COLLAPSED,
             Event.L1_DCACHE_LOAD_MISSES));
@@ -42,12 +43,18 @@
   @Test(expected = IllegalArgumentException.class)
   public void testNameValidationWithNewLine() throws IOException {
     ProfileServlet.validateFileName(
+        "test\n" + ProfileServlet.generateFileName(1, Output.FLAMEGRAPH,
+            Event.ALLOC));
+    ProfileServlet.validateFileName(
         "test\n" + ProfileServlet.generateFileName(1, Output.SVG, Event.ALLOC));
   }
 
   @Test(expected = IllegalArgumentException.class)
   public void testNameValidationWithSlash() throws IOException {
     ProfileServlet.validateFileName(
+        "../" + ProfileServlet.generateFileName(1, Output.FLAMEGRAPH,
+            Event.ALLOC));
+    ProfileServlet.validateFileName(
         "../" + ProfileServlet.generateFileName(1, Output.SVG, Event.ALLOC));
   }