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( 44 /* streaming=*/true, /* flags= */ 0, STREAMING_DUAL_CLOCK_VERSION); 45 46 System.out.println("***** streaming test - wall clock *******"); 47 testTracing( 48 /* streaming=*/true, /* flags= */ WALL_CLOCK_FLAG, STREAMING_WALL_CLOCK_VERSION); 49 } 50 testTracing(boolean streaming, int flags, int expected_version)51 public static void testTracing(boolean streaming, int flags, int expected_version) 52 throws Exception { 53 Main m = new Main(); 54 Thread t = new Thread(() -> { 55 try { 56 file = createTempFile(); 57 FileOutputStream out_file = new FileOutputStream(file); 58 VMDebug.startMethodTracingV2( 59 file.getPath(), out_file.getFD(), 0, flags, false, 0, streaming); 60 Main m1 = new Main(); 61 m1.$noinline$doSomeWork(); 62 // Call JITed code multiple times to flush out any issues with timestamps. 63 for (int i = 0; i < 20; i++) { 64 m.$noinline$doSomeWorkJIT(); 65 } 66 VMDebug.$noinline$stopMethodTracing(); 67 out_file.close(); 68 dumpTrace(file.getAbsolutePath(), "TestThread2246"); 69 file.delete(); 70 } catch (Exception e) { 71 System.out.println("Exception in thread " + e); 72 e.printStackTrace(); 73 } finally { 74 file.delete(); 75 } 76 }, "TestThread2246"); 77 try { 78 if (VMDebug.getMethodTracingMode() != 0) { 79 VMDebug.$noinline$stopMethodTracing(); 80 } 81 82 t.start(); 83 t.join(); 84 85 file = createTempFile(); 86 FileOutputStream main_out_file = new FileOutputStream(file); 87 VMDebug.startMethodTracingV2( 88 file.getPath(), main_out_file.getFD(), 0, flags, false, 0, streaming); 89 m.$noinline$doSomeWork(); 90 // Call JITed code multiple times to flush out any issues with timestamps. 91 for (int i = 0; i < 20; i++) { 92 m.$noinline$doSomeWorkJIT(); 93 } 94 m.doSomeWorkThrow(); 95 VMDebug.$noinline$stopMethodTracing(); 96 main_out_file.close(); 97 dumpTrace(file.getAbsolutePath(), "main"); 98 file.delete(); 99 } finally { 100 file.delete(); 101 } 102 } 103 createTempFile()104 private static File createTempFile() throws Exception { 105 try { 106 return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX); 107 } catch (IOException e) { 108 System.setProperty("java.io.tmpdir", "/data/local/tmp"); 109 try { 110 return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX); 111 } catch (IOException e2) { 112 System.setProperty("java.io.tmpdir", "/sdcard"); 113 return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX); 114 } 115 } 116 } 117 callOuterFunction()118 public void callOuterFunction() { 119 callLeafFunction(); 120 } 121 callLeafFunction()122 public void callLeafFunction() {} 123 $noinline$doSomeWork()124 public void $noinline$doSomeWork() { 125 callOuterFunction(); 126 callLeafFunction(); 127 } 128 $noinline$doSomeWorkJIT()129 public void $noinline$doSomeWorkJIT() { 130 callOuterFunction(); 131 callLeafFunction(); 132 } 133 callThrowFunction()134 public void callThrowFunction() throws Exception { 135 throw new Exception("test"); 136 } 137 doSomeWorkThrow()138 public void doSomeWorkThrow() { 139 try { 140 callThrowFunction(); 141 } catch (Exception e) { 142 } 143 } 144 145 private static class VMDebug { 146 private static final Method startMethodTracingMethod; 147 private static final Method stopMethodTracingMethod; 148 private static final Method getMethodTracingModeMethod; 149 static { 150 try { 151 Class<?> c = Class.forName("dalvik.system.VMDebug"); 152 startMethodTracingMethod = c.getDeclaredMethod("startMethodTracing", String.class, 153 FileDescriptor.class, Integer.TYPE, Integer.TYPE, Boolean.TYPE, 154 Integer.TYPE, Boolean.TYPE); 155 stopMethodTracingMethod = c.getDeclaredMethod("stopMethodTracing"); 156 getMethodTracingModeMethod = c.getDeclaredMethod("getMethodTracingMode"); 157 } catch (Exception e) { 158 throw new RuntimeException(e); 159 } 160 } 161 startMethodTracingV2(String filename, FileDescriptor fd, int bufferSize, int flags, boolean samplingEnabled, int intervalUs, boolean streaming)162 public static void startMethodTracingV2(String filename, FileDescriptor fd, int bufferSize, 163 int flags, boolean samplingEnabled, int intervalUs, boolean streaming) 164 throws Exception { 165 startMethodTracingMethod.invoke(null, filename, fd, bufferSize, 166 flags | TRACE_OUTPUT_V2_FLAG, samplingEnabled, intervalUs, streaming); 167 } $noinline$stopMethodTracing()168 public static void $noinline$stopMethodTracing() throws Exception { 169 stopMethodTracingMethod.invoke(null); 170 } getMethodTracingMode()171 public static int getMethodTracingMode() throws Exception { 172 return (int) getMethodTracingModeMethod.invoke(null); 173 } 174 } 175 ensureJitCompiled(Class<?> cls, String methodName)176 private static native void ensureJitCompiled(Class<?> cls, String methodName); dumpTrace(String fileName, String threadName)177 private static native void dumpTrace(String fileName, String threadName); 178 } 179