Add percentile fields to GfxInfoParser

Test: tools/tradefederation/core/tests/run_tradefed_tests.sh --class com.android.loganalysis.parser.GfxInfoParserTest
Bug: None
Change-Id: Id2c36af1daa3cb330aa783756a6c412e2f7f820c
diff --git a/src/com/android/loganalysis/item/GfxInfoItem.java b/src/com/android/loganalysis/item/GfxInfoItem.java
index 482cea3..21ff245 100644
--- a/src/com/android/loganalysis/item/GfxInfoItem.java
+++ b/src/com/android/loganalysis/item/GfxInfoItem.java
@@ -38,6 +38,12 @@
     public static final String TOTAL_FRAMES_KEY = "total_frames";
     /** Constant for JSON output */
     public static final String JANKY_FRAMES_KEY = "janky_frames";
+    /** Constant for JSON output */
+    public static final String PERCENTILE_90_KEY = "percentile_90";
+    /** Constant for JSON output */
+    public static final String PERCENTILE_95_KEY = "percentile_95";
+    /** Constant for JSON output */
+    public static final String PERCENTILE_99_KEY = "percentile_99";
 
     private Map<Integer, Row> mRows = new HashMap<Integer, Row>();
 
@@ -45,6 +51,9 @@
         public String name;
         public long totalFrames;
         public long jankyFrames;
+        public int percentile90;
+        public int percentile95;
+        public int percentile99;
     }
 
     /**
@@ -76,7 +85,9 @@
                 proc.put(PID_KEY, pid);
                 proc.put(NAME_KEY, getName(pid));
                 proc.put(TOTAL_FRAMES_KEY, getTotalFrames(pid));
-                proc.put(JANKY_FRAMES_KEY, getJankyFrames(pid));
+                proc.put(PERCENTILE_90_KEY, getPrecentile90(pid));
+                proc.put(PERCENTILE_95_KEY, getPrecentile95(pid));
+                proc.put(PERCENTILE_99_KEY, getPrecentile99(pid));
                 processes.put(proc);
             } catch (JSONException e) {
                 // ignore
@@ -106,11 +117,21 @@
      * @param totalFrames The number of total frames rendered by the process
      * @param jankyFrames The number of janky frames rendered by the process
      */
-    public void addRow(int pid, String name, long totalFrames, long jankyFrames) {
+    public void addRow(
+            int pid,
+            String name,
+            long totalFrames,
+            long jankyFrames,
+            int percentile90,
+            int percentile95,
+            int percentile99) {
         Row row = new Row();
         row.name = name;
         row.totalFrames = totalFrames;
         row.jankyFrames = jankyFrames;
+        row.percentile90 = percentile90;
+        row.percentile95 = percentile95;
+        row.percentile99 = percentile99;
         mRows.put(pid, row);
     }
 
@@ -134,4 +155,19 @@
     public long getJankyFrames(int pid) {
         return mRows.get(pid).jankyFrames;
     }
+
+    /** Get the 90th percentile value of frame times (ms) */
+    public int getPrecentile90(int pid) {
+        return mRows.get(pid).percentile90;
+    }
+
+    /** Get the 95th percentile value of frame times (ms) */
+    public int getPrecentile95(int pid) {
+        return mRows.get(pid).percentile95;
+    }
+
+    /** Get the 99th percentile value of frame times (ms) */
+    public int getPrecentile99(int pid) {
+        return mRows.get(pid).percentile99;
+    }
 }
diff --git a/src/com/android/loganalysis/parser/GfxInfoParser.java b/src/com/android/loganalysis/parser/GfxInfoParser.java
index ef549d7..8f0dce7 100644
--- a/src/com/android/loganalysis/parser/GfxInfoParser.java
+++ b/src/com/android/loganalysis/parser/GfxInfoParser.java
@@ -38,6 +38,18 @@
     private static final Pattern JANKY_FRAMES_PREFIX = Pattern.compile(
             "Janky frames: (\\d+) \\(.+\\%\\)");
 
+    // Example: "90th percentile: 9ms"
+    private static final Pattern PERCENTILE_90_PREFIX =
+            Pattern.compile("90th percentile: (\\d+)ms");
+
+    // Example: "90th percentile: 14ms"
+    private static final Pattern PERCENTILE_95_PREFIX =
+            Pattern.compile("95th percentile: (\\d+)ms");
+
+    // Example: "90th percentile: 32ms"
+    private static final Pattern PERCENTILE_99_PREFIX =
+            Pattern.compile("99th percentile: (\\d+)ms");
+
     /**
      * Parses the log of "dumpsys gfxinfo".
      * Currently it only parses total frame number and total jank number per process.
@@ -51,6 +63,9 @@
         Integer pid = null;
         Long totalFrames = null;
         Long jankyFrames = null;
+        Integer percentile90 = null;
+        Integer percentile95 = null;
+        Integer percentile99 = null;
 
         // gfxinfo also offers stats for specific views, but this parser
         // only records per process data. See example in GfxInfoParserTest.java.
@@ -64,6 +79,9 @@
 
                 totalFrames = null;
                 jankyFrames = null;
+                percentile90 = null;
+                percentile95 = null;
+                percentile99 = null;
             }
 
             m = TOTAL_FRAMES_PREFIX.matcher(line);
@@ -76,14 +94,45 @@
                 jankyFrames = Long.parseLong(m.group(1));
             }
 
-            if (name != null && pid != null && totalFrames != null && jankyFrames != null) {
+            m = PERCENTILE_90_PREFIX.matcher(line);
+            if (percentile90 == null && m.matches()) {
+                percentile90 = Integer.parseInt(m.group(1));
+            }
+
+            m = PERCENTILE_95_PREFIX.matcher(line);
+            if (percentile95 == null && m.matches()) {
+                percentile95 = Integer.parseInt(m.group(1));
+            }
+
+            m = PERCENTILE_99_PREFIX.matcher(line);
+            if (percentile99 == null && m.matches()) {
+                percentile99 = Integer.parseInt(m.group(1));
+            }
+
+            if (name != null
+                    && pid != null
+                    && totalFrames != null
+                    && jankyFrames != null
+                    && percentile90 != null
+                    && percentile95 != null
+                    && percentile99 != null) {
                 // All the data for the process is recorded, add as a row.
-                item.addRow(pid, name, totalFrames, jankyFrames);
+                item.addRow(
+                        pid,
+                        name,
+                        totalFrames,
+                        jankyFrames,
+                        percentile90,
+                        percentile95,
+                        percentile99);
 
                 name = null;
                 pid = null;
                 totalFrames = null;
                 jankyFrames = null;
+                percentile90 = null;
+                percentile95 = null;
+                percentile99 = null;
             }
         }
 
diff --git a/tests/src/com/android/loganalysis/parser/GfxInfoParserTest.java b/tests/src/com/android/loganalysis/parser/GfxInfoParserTest.java
index b424472..fcd053b 100644
--- a/tests/src/com/android/loganalysis/parser/GfxInfoParserTest.java
+++ b/tests/src/com/android/loganalysis/parser/GfxInfoParserTest.java
@@ -93,6 +93,9 @@
         assertEquals("com.google.android.leanbacklauncher", item.getName(853));
         assertEquals(20391, item.getTotalFrames(853));
         assertEquals(785, item.getJankyFrames(853));
+        assertEquals(9, item.getPrecentile90(853));
+        assertEquals(14, item.getPrecentile95(853));
+        assertEquals(32, item.getPrecentile99(853));
     }
 
     /**
@@ -285,12 +288,21 @@
         assertEquals("com.google.android.leanbacklauncher", item.getName(844));
         assertEquals(1690, item.getTotalFrames(844));
         assertEquals(125, item.getJankyFrames(844));
+        assertEquals(13, item.getPrecentile90(844));
+        assertEquals(19, item.getPrecentile95(844));
+        assertEquals(48, item.getPrecentile99(844));
         assertEquals("com.android.vending", item.getName(1881));
         assertEquals(693, item.getTotalFrames(1881));
         assertEquals(62, item.getJankyFrames(1881));
+        assertEquals(16, item.getPrecentile90(1881));
+        assertEquals(26, item.getPrecentile95(1881));
+        assertEquals(81, item.getPrecentile99(1881));
         assertEquals("com.google.android.videos", item.getName(2931));
         assertEquals(107, item.getTotalFrames(2931));
         assertEquals(42, item.getJankyFrames(2931));
+        assertEquals(48, item.getPrecentile90(2931));
+        assertEquals(65, item.getPrecentile95(2931));
+        assertEquals(113, item.getPrecentile99(2931));
     }
 
     /**