Generalize KvmHypTracer

Currently KvmHypTracer is only used by testNoLonghypSections and was
only able to trace "hyp_enter" and "hyp_exit" events. In preparation to
re-use this class for other tests, make it more generic with an event
list as a parameter.

Bug: 340244758
Test: atest AVFHostTestCase#testNoLongHypSections
Change-Id: I45ab976c198dede2b37a2b056d763c2a994fd8e9
diff --git a/tests/benchmark_hostside/java/android/avf/test/AVFHostTestCase.java b/tests/benchmark_hostside/java/android/avf/test/AVFHostTestCase.java
index 0280652..99a8df8 100644
--- a/tests/benchmark_hostside/java/android/avf/test/AVFHostTestCase.java
+++ b/tests/benchmark_hostside/java/android/avf/test/AVFHostTestCase.java
@@ -121,9 +121,14 @@
 
     @Test
     public void testNoLongHypSections() throws Exception {
-        assumeTrue("Skip without hypervisor tracing", KvmHypTracer.isSupported(getDevice()));
+        String[] hypEvents = {
+            "hyp_enter", "hyp_exit"
+        };
 
-        KvmHypTracer tracer = new KvmHypTracer(getDevice());
+        assumeTrue("Skip without hypervisor tracing",
+            KvmHypTracer.isSupported(getDevice(), hypEvents));
+
+        KvmHypTracer tracer = new KvmHypTracer(getDevice(), hypEvents);
         String result = tracer.run(COMPOSD_CMD_BIN + " test-compile");
         assertWithMessage("Failed to test compilation VM.")
                 .that(result).ignoringCase().contains("all ok");
diff --git a/tests/hostside/helper/java/com/android/microdroid/test/host/KvmHypTracer.java b/tests/hostside/helper/java/com/android/microdroid/test/host/KvmHypTracer.java
index 0d8ee96..a91049d 100644
--- a/tests/hostside/helper/java/com/android/microdroid/test/host/KvmHypTracer.java
+++ b/tests/hostside/helper/java/com/android/microdroid/test/host/KvmHypTracer.java
@@ -38,16 +38,15 @@
 public final class KvmHypTracer {
 
     private static final String HYP_TRACING_ROOT = "/sys/kernel/tracing/hyp/";
-    private static final String HYP_EVENTS[] = { "hyp_enter", "hyp_exit" };
     private static final int DEFAULT_BUF_SIZE_KB = 4 * 1024;
     private static final Pattern LOST_EVENT_PATTERN = Pattern.compile(
             "^CPU:[0-9]* \\[LOST ([0-9]*) EVENTS\\]");
-    private static final Pattern EVENT_PATTERN = Pattern.compile(
-            "^\\[([0-9]*)\\][ \t]*([0-9]*\\.[0-9]*): (" + String.join("|", HYP_EVENTS) + ") (.*)");
 
     private final CommandRunner mRunner;
     private final ITestDevice mDevice;
     private final int mNrCpus;
+    private final String mHypEvents[];
+    private final Pattern mHypEventPattern;
 
     private final ArrayList<File> mTraces;
 
@@ -59,22 +58,25 @@
         return "events/hyp/" + event + "/";
     }
 
-    public static boolean isSupported(ITestDevice device) throws Exception {
-        for (String event: HYP_EVENTS) {
+    public static boolean isSupported(ITestDevice device, String[] events) throws Exception {
+        for (String event: events) {
             if (!device.doesFileExist(HYP_TRACING_ROOT + eventDir(event) + "/enable"))
                 return false;
         }
         return true;
     }
 
-    public KvmHypTracer(@Nonnull ITestDevice device) throws Exception {
-        assertWithMessage("Hypervisor tracing not supported")
-                .that(isSupported(device)).isTrue();
+    public KvmHypTracer(@Nonnull ITestDevice device, String[] events) throws Exception {
+        assertWithMessage("Hypervisor events " + String.join(",", events) + " not supported")
+            .that(isSupported(device, events)).isTrue();
 
         mDevice = device;
         mRunner = new CommandRunner(mDevice);
         mTraces = new ArrayList<File>();
         mNrCpus = Integer.parseInt(mRunner.run("nproc"));
+        mHypEvents = events;
+        mHypEventPattern = Pattern.compile(
+            "^\\[([0-9]*)\\][ \t]*([0-9]*\\.[0-9]*): (" + String.join("|", mHypEvents) + ") (.*)");
     }
 
     public String run(String payload_cmd) throws Exception {
@@ -83,7 +85,7 @@
         setNode("tracing_on", 0);
         mRunner.run("echo 0 | tee " + HYP_TRACING_ROOT + "events/*/*/enable");
         setNode("buffer_size_kb", DEFAULT_BUF_SIZE_KB);
-        for (String event: HYP_EVENTS)
+        for (String event: mHypEvents)
             setNode(eventDir(event) + "/enable", 1);
         setNode("trace", 0);
 
@@ -128,9 +130,23 @@
         return res;
     }
 
+    private boolean hasEvents(String[] events) {
+        for (String event : events) {
+            if (!Arrays.asList(mHypEvents).contains(event)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
     public SimpleStats getDurationStats() throws Exception {
+        String[] reqEvents = {"hyp_enter", "hyp_exit"};
         SimpleStats stats = new SimpleStats();
 
+        assertWithMessage("KvmHypTracer() is missing events " + String.join(",", reqEvents))
+            .that(hasEvents(reqEvents)).isTrue();
+
         for (File trace: mTraces) {
             BufferedReader br = new BufferedReader(new FileReader(trace));
             double last = 0.0, hyp_enter = 0.0;
@@ -140,7 +156,7 @@
                 if (matcher.find())
                     throw new OutOfMemoryError("Lost " + matcher.group(1) + " events");
 
-                matcher = EVENT_PATTERN.matcher(l);
+                matcher = mHypEventPattern.matcher(l);
                 if (!matcher.find()) {
                     CLog.w("Failed to parse hyp event: " + l);
                     continue;