diff --git a/src/com/android/loganalysis/item/GfxInfoItem.java b/src/com/android/loganalysis/item/GfxInfoItem.java index 482cea3d1e094b3d411b8bd72a1a9d8362d0e0f3..21ff245e65c41f2971f172e3434301935edbfe59 100644 --- a/src/com/android/loganalysis/item/GfxInfoItem.java +++ b/src/com/android/loganalysis/item/GfxInfoItem.java @@ -38,6 +38,12 @@ public class GfxInfoItem implements IItem { 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 class GfxInfoItem implements IItem { public String name; public long totalFrames; public long jankyFrames; + public int percentile90; + public int percentile95; + public int percentile99; } /** @@ -76,7 +85,9 @@ public class GfxInfoItem implements IItem { 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 @@ public class GfxInfoItem implements IItem { * @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 class GfxInfoItem implements IItem { 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 ef549d73a86608eb6f4924ede1f84c4b4b15f440..8f0dce7f89eaf17f4095abda29aaa74b09cb7a2b 100644 --- a/src/com/android/loganalysis/parser/GfxInfoParser.java +++ b/src/com/android/loganalysis/parser/GfxInfoParser.java @@ -38,6 +38,18 @@ public class GfxInfoParser implements IParser { 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 @@ public class GfxInfoParser implements IParser { 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 @@ public class GfxInfoParser implements IParser { totalFrames = null; jankyFrames = null; + percentile90 = null; + percentile95 = null; + percentile99 = null; } m = TOTAL_FRAMES_PREFIX.matcher(line); @@ -76,14 +94,45 @@ public class GfxInfoParser implements IParser { 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 b424472657a9f3e2dd53abb6050d57c443c8a848..fcd053b9c8f60625b10cbb4227729e8c08f61d12 100644 --- a/tests/src/com/android/loganalysis/parser/GfxInfoParserTest.java +++ b/tests/src/com/android/loganalysis/parser/GfxInfoParserTest.java @@ -93,6 +93,9 @@ public class GfxInfoParserTest extends TestCase { 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 @@ public class GfxInfoParserTest extends TestCase { 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)); } /**