1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import java.io.File; 18 import java.io.FileDescriptor; 19 import java.io.FileOutputStream; 20 import java.io.IOException; 21 import java.lang.reflect.Method; 22 23 public class Main { 24 private static final String TEMP_FILE_NAME_PREFIX = "test"; 25 private static final String TEMP_FILE_NAME_SUFFIX = ".trace"; 26 private static final int WALL_CLOCK_FLAG = 0x010; 27 private static final int TRACE_OUTPUT_V2_FLAG = 0b010; 28 private static final int STREAMING_DUAL_CLOCK_VERSION = 1; 29 private static final int STREAMING_WALL_CLOCK_VERSION = 1; 30 private static File file; 31 main(String[] args)32 public static void main(String[] args) throws Exception { 33 System.loadLibrary(args[0]); 34 String name = System.getProperty("java.vm.name"); 35 if (!"Dalvik".equals(name)) { 36 System.out.println("This test is not supported on " + name); 37 return; 38 } 39 40 ensureJitCompiled(Main.class, "$noinline$doSomeWorkJIT"); 41 42 System.out.println("***** streaming test - dual clock *******"); 43 testTracing(/* streaming=*/true, /* flags= */ 0); 44 45 System.out.println("***** streaming test - wall clock *******"); 46 testTracing(/* streaming=*/true, /* flags= */ WALL_CLOCK_FLAG); 47 48 System.out.println("***** non-streaming test - dual clock *******"); 49 testTracing(/* streaming=*/false, /* flags= */ 0); 50 51 System.out.println("***** non-streaming test - wall clock *******"); 52 testTracing(/* streaming=*/false, /* flags= */ WALL_CLOCK_FLAG); 53 } 54 testTracing(boolean streaming, int flags)55 public static void testTracing(boolean streaming, int flags) throws Exception { 56 Main m = new Main(); 57 Thread t = new Thread(() -> { 58 try { 59 file = createTempFile(); 60 FileOutputStream out_file = new FileOutputStream(file); 61 VMDebug.startMethodTracingV2( 62 file.getPath(), out_file.getFD(), 0, flags, false, 0, streaming); 63 Main m1 = new Main(); 64 m1.$noinline$doSomeWork(); 65 // Call JITed code multiple times to flush out any issues with timestamps. 66 for (int i = 0; i < 20; i++) { 67 m.$noinline$doSomeWorkJIT(); 68 } 69 VMDebug.$noinline$stopMethodTracing(); 70 out_file.close(); 71 dumpTrace(file.getAbsolutePath(), "TestThread2246"); 72 file.delete(); 73 } catch (Exception e) { 74 System.out.println("Exception in thread " + e); 75 e.printStackTrace(); 76 } finally { 77 file.delete(); 78 } 79 }, "TestThread2246"); 80 try { 81 if (VMDebug.getMethodTracingMode() != 0) { 82 VMDebug.$noinline$stopMethodTracing(); 83 } 84 85 t.start(); 86 t.join(); 87 88 file = createTempFile(); 89 FileOutputStream main_out_file = new FileOutputStream(file); 90 VMDebug.startMethodTracingV2( 91 file.getPath(), main_out_file.getFD(), 0, flags, false, 0, streaming); 92 m.$noinline$doSomeWork(); 93 // Call JITed code multiple times to flush out any issues with timestamps. 94 for (int i = 0; i < 20; i++) { 95 m.$noinline$doSomeWorkJIT(); 96 } 97 m.doSomeWorkThrow(); 98 VMDebug.$noinline$stopMethodTracing(); 99 main_out_file.close(); 100 dumpTrace(file.getAbsolutePath(), "main"); 101 file.delete(); 102 } finally { 103 file.delete(); 104 } 105 } 106 createTempFile()107 private static File createTempFile() throws Exception { 108 try { 109 return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX); 110 } catch (IOException e) { 111 System.setProperty("java.io.tmpdir", "/data/local/tmp"); 112 try { 113 return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX); 114 } catch (IOException e2) { 115 System.setProperty("java.io.tmpdir", "/sdcard"); 116 return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX); 117 } 118 } 119 } 120 callOuterFunction()121 public void callOuterFunction() { 122 callLeafFunction(); 123 } 124 callLeafFunction()125 public void callLeafFunction() {} 126 $noinline$doSomeWork()127 public void $noinline$doSomeWork() { 128 callOuterFunction(); 129 callLeafFunction(); 130 } 131 $noinline$doSomeWorkJIT()132 public void $noinline$doSomeWorkJIT() { 133 callOuterFunction(); 134 callLeafFunction(); 135 } 136 callThrowFunction()137 public void callThrowFunction() throws Exception { 138 throw new Exception("test"); 139 } 140 doSomeWorkThrow()141 public void doSomeWorkThrow() { 142 try { 143 callThrowFunction(); 144 } catch (Exception e) { 145 } 146 } 147 148 private static class VMDebug { 149 private static final Method startMethodTracingMethod; 150 private static final Method stopMethodTracingMethod; 151 private static final Method getMethodTracingModeMethod; 152 static { 153 try { 154 Class<?> c = Class.forName("dalvik.system.VMDebug"); 155 startMethodTracingMethod = c.getDeclaredMethod("startMethodTracing", String.class, 156 FileDescriptor.class, Integer.TYPE, Integer.TYPE, Boolean.TYPE, 157 Integer.TYPE, Boolean.TYPE); 158 stopMethodTracingMethod = c.getDeclaredMethod("stopMethodTracing"); 159 getMethodTracingModeMethod = c.getDeclaredMethod("getMethodTracingMode"); 160 } catch (Exception e) { 161 throw new RuntimeException(e); 162 } 163 } 164 startMethodTracingV2(String filename, FileDescriptor fd, int bufferSize, int flags, boolean samplingEnabled, int intervalUs, boolean streaming)165 public static void startMethodTracingV2(String filename, FileDescriptor fd, int bufferSize, 166 int flags, boolean samplingEnabled, int intervalUs, boolean streaming) 167 throws Exception { 168 startMethodTracingMethod.invoke(null, filename, fd, bufferSize, 169 flags | TRACE_OUTPUT_V2_FLAG, samplingEnabled, intervalUs, streaming); 170 } $noinline$stopMethodTracing()171 public static void $noinline$stopMethodTracing() throws Exception { 172 stopMethodTracingMethod.invoke(null); 173 } getMethodTracingMode()174 public static int getMethodTracingMode() throws Exception { 175 return (int) getMethodTracingModeMethod.invoke(null); 176 } 177 } 178 ensureJitCompiled(Class<?> cls, String methodName)179 private static native void ensureJitCompiled(Class<?> cls, String methodName); dumpTrace(String fileName, String threadName)180 private static native void dumpTrace(String fileName, String threadName); 181 } 182