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