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