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