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