xref: /aosp_15_r20/art/test/708-jit-cache-churn/src/JitCacheChurnTest.java (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2017 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.lang.reflect.Method;
18*795d594fSAndroid Build Coastguard Worker import java.util.ArrayList;
19*795d594fSAndroid Build Coastguard Worker import java.util.List;
20*795d594fSAndroid Build Coastguard Worker import java.util.Random;
21*795d594fSAndroid Build Coastguard Worker import java.util.concurrent.atomic.AtomicInteger;
22*795d594fSAndroid Build Coastguard Worker import java.util.concurrent.Callable;
23*795d594fSAndroid Build Coastguard Worker import java.util.concurrent.CyclicBarrier;
24*795d594fSAndroid Build Coastguard Worker import java.util.concurrent.ExecutionException;
25*795d594fSAndroid Build Coastguard Worker import java.util.concurrent.ExecutorService;
26*795d594fSAndroid Build Coastguard Worker import java.util.concurrent.Future;
27*795d594fSAndroid Build Coastguard Worker import java.util.concurrent.LinkedBlockingQueue;
28*795d594fSAndroid Build Coastguard Worker import java.util.concurrent.ThreadPoolExecutor;
29*795d594fSAndroid Build Coastguard Worker import java.util.concurrent.TimeUnit;
30*795d594fSAndroid Build Coastguard Worker 
31*795d594fSAndroid Build Coastguard Worker /**
32*795d594fSAndroid Build Coastguard Worker  * A test driver for JIT compiling methods and looking for JIT
33*795d594fSAndroid Build Coastguard Worker  * cache issues.
34*795d594fSAndroid Build Coastguard Worker  */
35*795d594fSAndroid Build Coastguard Worker public class JitCacheChurnTest {
36*795d594fSAndroid Build Coastguard Worker   /* The name of methods to JIT */
37*795d594fSAndroid Build Coastguard Worker   private static final String JITTED_METHOD = "$noinline$Call";
38*795d594fSAndroid Build Coastguard Worker 
39*795d594fSAndroid Build Coastguard Worker   /* The number of cores to oversubscribe load by. */
40*795d594fSAndroid Build Coastguard Worker   private static final int OVERSUBSCRIBED_CORES = 1;
41*795d594fSAndroid Build Coastguard Worker 
42*795d594fSAndroid Build Coastguard Worker   /* The number of concurrent executions of methods to be JIT compiled. */
43*795d594fSAndroid Build Coastguard Worker   private static final int CONCURRENCY =
44*795d594fSAndroid Build Coastguard Worker       Runtime.getRuntime().availableProcessors() + OVERSUBSCRIBED_CORES;
45*795d594fSAndroid Build Coastguard Worker 
46*795d594fSAndroid Build Coastguard Worker   /* The number of times the methods to be JIT compiled should be executed per thread. */
47*795d594fSAndroid Build Coastguard Worker   private static final int METHOD_ITERATIONS = 10;
48*795d594fSAndroid Build Coastguard Worker 
49*795d594fSAndroid Build Coastguard Worker   /* Number of test iterations JIT methods and removing methods from JIT cache. */
50*795d594fSAndroid Build Coastguard Worker   private static final int TEST_ITERATIONS = 512;
51*795d594fSAndroid Build Coastguard Worker 
52*795d594fSAndroid Build Coastguard Worker   /* Tasks to run and generate compiled code of various sizes */
53*795d594fSAndroid Build Coastguard Worker   private static final BaseTask [] TASKS = {
54*795d594fSAndroid Build Coastguard Worker     new TaskOne(), new TaskTwo(), new TaskThree(), new TaskFour(), new TaskFive(), new TaskSix(),
55*795d594fSAndroid Build Coastguard Worker     new TaskSeven(), new TaskEight(), new TaskNine(), new TaskTen()
56*795d594fSAndroid Build Coastguard Worker   };
57*795d594fSAndroid Build Coastguard Worker   private static final int TASK_BITMASK = (1 << TASKS.length) - 1;
58*795d594fSAndroid Build Coastguard Worker 
59*795d594fSAndroid Build Coastguard Worker   private final ExecutorService executorService;
60*795d594fSAndroid Build Coastguard Worker   private int runMask = 0;
61*795d594fSAndroid Build Coastguard Worker 
JitCacheChurnTest()62*795d594fSAndroid Build Coastguard Worker   private JitCacheChurnTest() {
63*795d594fSAndroid Build Coastguard Worker     this.executorService = new ThreadPoolExecutor(CONCURRENCY, CONCURRENCY, 5000,
64*795d594fSAndroid Build Coastguard Worker         TimeUnit.MILLISECONDS,new LinkedBlockingQueue<>());
65*795d594fSAndroid Build Coastguard Worker   }
66*795d594fSAndroid Build Coastguard Worker 
shutdown()67*795d594fSAndroid Build Coastguard Worker   private void shutdown() {
68*795d594fSAndroid Build Coastguard Worker     this.executorService.shutdown();
69*795d594fSAndroid Build Coastguard Worker   }
70*795d594fSAndroid Build Coastguard Worker 
runTasks(Callable<Integer> task)71*795d594fSAndroid Build Coastguard Worker   private void runTasks(Callable<Integer> task) {
72*795d594fSAndroid Build Coastguard Worker     // Force JIT compilation of tasks method.
73*795d594fSAndroid Build Coastguard Worker     ensureJitCompiled(task.getClass(), JITTED_METHOD);
74*795d594fSAndroid Build Coastguard Worker 
75*795d594fSAndroid Build Coastguard Worker     // Launch worker threads to run JIT compiled method.
76*795d594fSAndroid Build Coastguard Worker     try {
77*795d594fSAndroid Build Coastguard Worker       ArrayList<Callable<Integer>> tasks = new ArrayList<>(CONCURRENCY);
78*795d594fSAndroid Build Coastguard Worker       for (int i = 0; i < CONCURRENCY; ++i) {
79*795d594fSAndroid Build Coastguard Worker         tasks.add(i, task);
80*795d594fSAndroid Build Coastguard Worker       }
81*795d594fSAndroid Build Coastguard Worker 
82*795d594fSAndroid Build Coastguard Worker       List<Future<Integer>> results = executorService.invokeAll(tasks);
83*795d594fSAndroid Build Coastguard Worker       for (Future<?> result : results) {
84*795d594fSAndroid Build Coastguard Worker         result.get();
85*795d594fSAndroid Build Coastguard Worker       }
86*795d594fSAndroid Build Coastguard Worker     } catch (InterruptedException | ExecutionException e) {
87*795d594fSAndroid Build Coastguard Worker       System.err.println(e);
88*795d594fSAndroid Build Coastguard Worker       System.exit(-1);
89*795d594fSAndroid Build Coastguard Worker     }
90*795d594fSAndroid Build Coastguard Worker   }
91*795d594fSAndroid Build Coastguard Worker 
92*795d594fSAndroid Build Coastguard Worker   private static abstract class BaseTask implements Callable<Integer> {
93*795d594fSAndroid Build Coastguard Worker     private static CyclicBarrier barrier = new CyclicBarrier(CONCURRENCY);
94*795d594fSAndroid Build Coastguard Worker 
call()95*795d594fSAndroid Build Coastguard Worker     public Integer call() throws Exception {
96*795d594fSAndroid Build Coastguard Worker       barrier.await();
97*795d594fSAndroid Build Coastguard Worker       int iterations = METHOD_ITERATIONS + 1;
98*795d594fSAndroid Build Coastguard Worker       for (int i = 0; i < iterations; ++i) {
99*795d594fSAndroid Build Coastguard Worker         $noinline$Call();
100*795d594fSAndroid Build Coastguard Worker       }
101*795d594fSAndroid Build Coastguard Worker       return $noinline$Call();
102*795d594fSAndroid Build Coastguard Worker     }
103*795d594fSAndroid Build Coastguard Worker 
$noinline$Call()104*795d594fSAndroid Build Coastguard Worker     protected abstract Integer $noinline$Call();
105*795d594fSAndroid Build Coastguard Worker   }
106*795d594fSAndroid Build Coastguard Worker 
107*795d594fSAndroid Build Coastguard Worker   private static class TaskOne extends BaseTask {
108*795d594fSAndroid Build Coastguard Worker     @Override
$noinline$Call()109*795d594fSAndroid Build Coastguard Worker     protected Integer $noinline$Call() {
110*795d594fSAndroid Build Coastguard Worker       return null;
111*795d594fSAndroid Build Coastguard Worker     }
112*795d594fSAndroid Build Coastguard Worker   }
113*795d594fSAndroid Build Coastguard Worker 
114*795d594fSAndroid Build Coastguard Worker   private static class TaskTwo extends BaseTask {
115*795d594fSAndroid Build Coastguard Worker     @Override
$noinline$Call()116*795d594fSAndroid Build Coastguard Worker     protected Integer $noinline$Call() {
117*795d594fSAndroid Build Coastguard Worker       return 0;
118*795d594fSAndroid Build Coastguard Worker     }
119*795d594fSAndroid Build Coastguard Worker   }
120*795d594fSAndroid Build Coastguard Worker 
121*795d594fSAndroid Build Coastguard Worker   private static class TaskThree extends BaseTask {
122*795d594fSAndroid Build Coastguard Worker     @Override
$noinline$Call()123*795d594fSAndroid Build Coastguard Worker     protected Integer $noinline$Call() {
124*795d594fSAndroid Build Coastguard Worker       int sum = 0;
125*795d594fSAndroid Build Coastguard Worker       for (int i = 0; i < 3; ++i) {
126*795d594fSAndroid Build Coastguard Worker         sum = i * (i + 1);
127*795d594fSAndroid Build Coastguard Worker       }
128*795d594fSAndroid Build Coastguard Worker       return sum;
129*795d594fSAndroid Build Coastguard Worker     }
130*795d594fSAndroid Build Coastguard Worker   }
131*795d594fSAndroid Build Coastguard Worker 
132*795d594fSAndroid Build Coastguard Worker   private static class TaskFour extends BaseTask {
133*795d594fSAndroid Build Coastguard Worker     @Override
$noinline$Call()134*795d594fSAndroid Build Coastguard Worker     protected Integer $noinline$Call() {
135*795d594fSAndroid Build Coastguard Worker       int sum = 0;
136*795d594fSAndroid Build Coastguard Worker       for (int i = 0; i < 10; ++i) {
137*795d594fSAndroid Build Coastguard Worker         int bits = i;
138*795d594fSAndroid Build Coastguard Worker         bits = ((bits >>> 1) & 0x55555555) | ((bits << 1) & 0x55555555);
139*795d594fSAndroid Build Coastguard Worker         bits = ((bits >>> 2) & 0x33333333) | ((bits << 2) & 0x33333333);
140*795d594fSAndroid Build Coastguard Worker         bits = ((bits >>> 4) & 0x0f0f0f0f) | ((bits << 4) & 0x0f0f0f0f);
141*795d594fSAndroid Build Coastguard Worker         bits = ((bits >>> 8) & 0x00ff00ff) | ((bits << 8) & 0x00ff00ff);
142*795d594fSAndroid Build Coastguard Worker         bits = (bits >>> 16) | (bits << 16);
143*795d594fSAndroid Build Coastguard Worker         sum += bits;
144*795d594fSAndroid Build Coastguard Worker       }
145*795d594fSAndroid Build Coastguard Worker       return sum;
146*795d594fSAndroid Build Coastguard Worker     }
147*795d594fSAndroid Build Coastguard Worker   }
148*795d594fSAndroid Build Coastguard Worker 
149*795d594fSAndroid Build Coastguard Worker   private static class TaskFive extends BaseTask {
150*795d594fSAndroid Build Coastguard Worker     static final AtomicInteger instances = new AtomicInteger(0);
151*795d594fSAndroid Build Coastguard Worker     int instance;
TaskFive()152*795d594fSAndroid Build Coastguard Worker     TaskFive() {
153*795d594fSAndroid Build Coastguard Worker       instance = instances.getAndIncrement();
154*795d594fSAndroid Build Coastguard Worker     }
$noinline$Call()155*795d594fSAndroid Build Coastguard Worker     protected Integer $noinline$Call() {
156*795d594fSAndroid Build Coastguard Worker       return instance;
157*795d594fSAndroid Build Coastguard Worker     }
158*795d594fSAndroid Build Coastguard Worker   }
159*795d594fSAndroid Build Coastguard Worker 
160*795d594fSAndroid Build Coastguard Worker   private static class TaskSix extends TaskFive {
$noinline$Call()161*795d594fSAndroid Build Coastguard Worker     protected Integer $noinline$Call() {
162*795d594fSAndroid Build Coastguard Worker       return instance + 1;
163*795d594fSAndroid Build Coastguard Worker     }
164*795d594fSAndroid Build Coastguard Worker   }
165*795d594fSAndroid Build Coastguard Worker 
166*795d594fSAndroid Build Coastguard Worker   private static class TaskSeven extends TaskFive {
$noinline$Call()167*795d594fSAndroid Build Coastguard Worker     protected Integer $noinline$Call() {
168*795d594fSAndroid Build Coastguard Worker       return 2 * instance + 1;
169*795d594fSAndroid Build Coastguard Worker     }
170*795d594fSAndroid Build Coastguard Worker   }
171*795d594fSAndroid Build Coastguard Worker 
172*795d594fSAndroid Build Coastguard Worker   private static class TaskEight extends TaskFive {
$noinline$Call()173*795d594fSAndroid Build Coastguard Worker     protected Integer $noinline$Call() {
174*795d594fSAndroid Build Coastguard Worker       double a = Math.cosh(2.22 * instance);
175*795d594fSAndroid Build Coastguard Worker       double b = a / 2;
176*795d594fSAndroid Build Coastguard Worker       double c = b * 3;
177*795d594fSAndroid Build Coastguard Worker       double d = a + b + c;
178*795d594fSAndroid Build Coastguard Worker       if (d > 42) {
179*795d594fSAndroid Build Coastguard Worker         d *= Math.max(Math.sin(d), Math.sinh(d));
180*795d594fSAndroid Build Coastguard Worker         d *= Math.max(1.33, 0.17 * Math.sinh(d));
181*795d594fSAndroid Build Coastguard Worker         d *= Math.max(1.34, 0.21 * Math.sinh(d));
182*795d594fSAndroid Build Coastguard Worker         d *= Math.max(1.35, 0.32 * Math.sinh(d));
183*795d594fSAndroid Build Coastguard Worker         d *= Math.max(1.36, 0.41 * Math.sinh(d));
184*795d594fSAndroid Build Coastguard Worker         d *= Math.max(1.37, 0.57 * Math.sinh(d));
185*795d594fSAndroid Build Coastguard Worker         d *= Math.max(1.38, 0.61 * Math.sinh(d));
186*795d594fSAndroid Build Coastguard Worker         d *= Math.max(1.39, 0.79 * Math.sinh(d));
187*795d594fSAndroid Build Coastguard Worker         d += Double.parseDouble("3.711e23");
188*795d594fSAndroid Build Coastguard Worker       }
189*795d594fSAndroid Build Coastguard Worker 
190*795d594fSAndroid Build Coastguard Worker       if (d > 3) {
191*795d594fSAndroid Build Coastguard Worker         return (int) a;
192*795d594fSAndroid Build Coastguard Worker       } else {
193*795d594fSAndroid Build Coastguard Worker         return (int) b;
194*795d594fSAndroid Build Coastguard Worker       }
195*795d594fSAndroid Build Coastguard Worker     }
196*795d594fSAndroid Build Coastguard Worker   }
197*795d594fSAndroid Build Coastguard Worker 
198*795d594fSAndroid Build Coastguard Worker   private static class TaskNine extends TaskFive {
199*795d594fSAndroid Build Coastguard Worker     private final String [] numbers = { "One", "Two", "Three", "Four", "Five", "Six" };
200*795d594fSAndroid Build Coastguard Worker 
$noinline$Call()201*795d594fSAndroid Build Coastguard Worker     protected Integer $noinline$Call() {
202*795d594fSAndroid Build Coastguard Worker       String number = numbers[instance % numbers.length];
203*795d594fSAndroid Build Coastguard Worker       return number.length();
204*795d594fSAndroid Build Coastguard Worker     }
205*795d594fSAndroid Build Coastguard Worker   }
206*795d594fSAndroid Build Coastguard Worker 
207*795d594fSAndroid Build Coastguard Worker   private static class TaskTen extends TaskFive {
208*795d594fSAndroid Build Coastguard Worker     private final String [] numbers = { "12345", "23451", "34512", "78901", "89012" };
209*795d594fSAndroid Build Coastguard Worker 
$noinline$Call()210*795d594fSAndroid Build Coastguard Worker     protected Integer $noinline$Call() {
211*795d594fSAndroid Build Coastguard Worker       int odd = 0;
212*795d594fSAndroid Build Coastguard Worker       String number = numbers[instance % numbers.length];
213*795d594fSAndroid Build Coastguard Worker       for (int i = 0; i < number.length(); i += 2) {
214*795d594fSAndroid Build Coastguard Worker         odd += Integer.parseInt(numbers[i]);
215*795d594fSAndroid Build Coastguard Worker       }
216*795d594fSAndroid Build Coastguard Worker       odd *= 3;
217*795d594fSAndroid Build Coastguard Worker 
218*795d594fSAndroid Build Coastguard Worker       int even = 0;
219*795d594fSAndroid Build Coastguard Worker       for (int i = 1; i < number.length(); i += 2) {
220*795d594fSAndroid Build Coastguard Worker         even += Integer.parseInt(numbers[i]);
221*795d594fSAndroid Build Coastguard Worker       }
222*795d594fSAndroid Build Coastguard Worker       return (odd + even) % 10;
223*795d594fSAndroid Build Coastguard Worker     }
224*795d594fSAndroid Build Coastguard Worker   }
225*795d594fSAndroid Build Coastguard Worker 
runAndJitMethods(int mask)226*795d594fSAndroid Build Coastguard Worker   private void runAndJitMethods(int mask) {
227*795d594fSAndroid Build Coastguard Worker     runMask |= mask;
228*795d594fSAndroid Build Coastguard Worker     for (int index = 0; mask != 0; mask >>= 1, index++) {
229*795d594fSAndroid Build Coastguard Worker       if ((mask & 1) == 1) {
230*795d594fSAndroid Build Coastguard Worker         runTasks(TASKS[index]);
231*795d594fSAndroid Build Coastguard Worker       }
232*795d594fSAndroid Build Coastguard Worker     }
233*795d594fSAndroid Build Coastguard Worker   }
234*795d594fSAndroid Build Coastguard Worker 
ensureJitCompiled(Class<?> klass, String name)235*795d594fSAndroid Build Coastguard Worker   private static void ensureJitCompiled(Class<?> klass, String name) {
236*795d594fSAndroid Build Coastguard Worker     Main.ensureJitCompiled(klass, name);
237*795d594fSAndroid Build Coastguard Worker   }
238*795d594fSAndroid Build Coastguard Worker 
removeJittedMethod(Class<?> klass, String name)239*795d594fSAndroid Build Coastguard Worker   private void removeJittedMethod(Class<?> klass, String name) {
240*795d594fSAndroid Build Coastguard Worker     Method method = null;
241*795d594fSAndroid Build Coastguard Worker     try {
242*795d594fSAndroid Build Coastguard Worker       method = klass.getDeclaredMethod(name);
243*795d594fSAndroid Build Coastguard Worker     } catch (NoSuchMethodException e) {
244*795d594fSAndroid Build Coastguard Worker       System.err.println(e);
245*795d594fSAndroid Build Coastguard Worker       System.exit(-1);
246*795d594fSAndroid Build Coastguard Worker     }
247*795d594fSAndroid Build Coastguard Worker     Main.removeJitCompiledMethod(method, false);
248*795d594fSAndroid Build Coastguard Worker   }
249*795d594fSAndroid Build Coastguard Worker 
removeJittedMethods(int mask)250*795d594fSAndroid Build Coastguard Worker   private void removeJittedMethods(int mask) {
251*795d594fSAndroid Build Coastguard Worker     mask = mask & runMask;
252*795d594fSAndroid Build Coastguard Worker     runMask ^= mask;
253*795d594fSAndroid Build Coastguard Worker     for (int index = 0; mask != 0; mask >>= 1, index++) {
254*795d594fSAndroid Build Coastguard Worker       if ((mask & 1) == 1) {
255*795d594fSAndroid Build Coastguard Worker         removeJittedMethod(TASKS[index].getClass(), JITTED_METHOD);
256*795d594fSAndroid Build Coastguard Worker       }
257*795d594fSAndroid Build Coastguard Worker     }
258*795d594fSAndroid Build Coastguard Worker   }
259*795d594fSAndroid Build Coastguard Worker 
getMethodsAsMask(Random rng)260*795d594fSAndroid Build Coastguard Worker   private static int getMethodsAsMask(Random rng) {
261*795d594fSAndroid Build Coastguard Worker     return rng.nextInt(TASK_BITMASK) + 1;
262*795d594fSAndroid Build Coastguard Worker   }
263*795d594fSAndroid Build Coastguard Worker 
run()264*795d594fSAndroid Build Coastguard Worker   public static void run() {
265*795d594fSAndroid Build Coastguard Worker     JitCacheChurnTest concurrentExecution = new JitCacheChurnTest();
266*795d594fSAndroid Build Coastguard Worker     Random invokeMethodGenerator = new Random(5);
267*795d594fSAndroid Build Coastguard Worker     Random removeMethodGenerator = new Random(7);
268*795d594fSAndroid Build Coastguard Worker     try {
269*795d594fSAndroid Build Coastguard Worker       for (int i = 0; i < TEST_ITERATIONS; ++i) {
270*795d594fSAndroid Build Coastguard Worker         concurrentExecution.runAndJitMethods(getMethodsAsMask(invokeMethodGenerator));
271*795d594fSAndroid Build Coastguard Worker         concurrentExecution.removeJittedMethods(getMethodsAsMask(removeMethodGenerator));
272*795d594fSAndroid Build Coastguard Worker       }
273*795d594fSAndroid Build Coastguard Worker     } finally {
274*795d594fSAndroid Build Coastguard Worker       concurrentExecution.shutdown();
275*795d594fSAndroid Build Coastguard Worker     }
276*795d594fSAndroid Build Coastguard Worker   }
277*795d594fSAndroid Build Coastguard Worker }
278