1*795d594fSAndroid Build Coastguard Worker /* 2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2011 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 dalvik.system.VMRuntime; 18*795d594fSAndroid Build Coastguard Worker 19*795d594fSAndroid Build Coastguard Worker import java.lang.reflect.*; 20*795d594fSAndroid Build Coastguard Worker import java.util.ArrayList; 21*795d594fSAndroid Build Coastguard Worker import java.util.Arrays; 22*795d594fSAndroid Build Coastguard Worker import java.util.Collections; 23*795d594fSAndroid Build Coastguard Worker import java.util.HashMap; 24*795d594fSAndroid Build Coastguard Worker import java.util.HashSet; 25*795d594fSAndroid Build Coastguard Worker import java.util.List; 26*795d594fSAndroid Build Coastguard Worker import java.util.Map; 27*795d594fSAndroid Build Coastguard Worker import java.util.Set; 28*795d594fSAndroid Build Coastguard Worker import java.util.concurrent.Semaphore; 29*795d594fSAndroid Build Coastguard Worker import java.util.concurrent.locks.LockSupport; 30*795d594fSAndroid Build Coastguard Worker 31*795d594fSAndroid Build Coastguard Worker // Run on host with: 32*795d594fSAndroid Build Coastguard Worker // javac ThreadTest.java && java ThreadStress && rm *.class 33*795d594fSAndroid Build Coastguard Worker // Through run-test: 34*795d594fSAndroid Build Coastguard Worker // test/run-test {run-test-args} 004-ThreadStress [Main {ThreadStress-args}] 35*795d594fSAndroid Build Coastguard Worker // (It is important to pass Main if you want to give parameters...) 36*795d594fSAndroid Build Coastguard Worker // 37*795d594fSAndroid Build Coastguard Worker // ThreadStress command line parameters: 38*795d594fSAndroid Build Coastguard Worker // -n X .............. number of threads 39*795d594fSAndroid Build Coastguard Worker // -d X .............. number of daemon threads 40*795d594fSAndroid Build Coastguard Worker // -o X .............. number of overall operations 41*795d594fSAndroid Build Coastguard Worker // -t X .............. number of operations per thread 42*795d594fSAndroid Build Coastguard Worker // -p X .............. number of permits granted by semaphore 43*795d594fSAndroid Build Coastguard Worker // --dumpmap ......... print the frequency map 44*795d594fSAndroid Build Coastguard Worker // --locks-only ...... select a pre-set frequency map with lock-related operations only 45*795d594fSAndroid Build Coastguard Worker // --allocs-only ..... select a pre-set frequency map with allocation-related operations only 46*795d594fSAndroid Build Coastguard Worker // -oom:X ............ frequency of OOM (double) 47*795d594fSAndroid Build Coastguard Worker // -sigquit:X ........ frequency of SigQuit (double) 48*795d594fSAndroid Build Coastguard Worker // -alloc:X .......... frequency of Alloc (double) 49*795d594fSAndroid Build Coastguard Worker // -largealloc:X ..... frequency of LargeAlloc (double) 50*795d594fSAndroid Build Coastguard Worker // -nonmovingalloc:X.. frequency of NonMovingAlloc (double) 51*795d594fSAndroid Build Coastguard Worker // -stacktrace:X ..... frequency of StackTrace (double) 52*795d594fSAndroid Build Coastguard Worker // -exit:X ........... frequency of Exit (double) 53*795d594fSAndroid Build Coastguard Worker // -sleep:X .......... frequency of Sleep (double) 54*795d594fSAndroid Build Coastguard Worker // -wait:X ........... frequency of Wait (double) 55*795d594fSAndroid Build Coastguard Worker // -timedwait:X ...... frequency of TimedWait (double) 56*795d594fSAndroid Build Coastguard Worker // -timedpark:X ...... frequency of TimedPark (double) 57*795d594fSAndroid Build Coastguard Worker // -syncandwork:X .... frequency of SyncAndWork (double) 58*795d594fSAndroid Build Coastguard Worker // -queuedwait:X ..... frequency of QueuedWait (double) 59*795d594fSAndroid Build Coastguard Worker 60*795d594fSAndroid Build Coastguard Worker public class Main implements Runnable { 61*795d594fSAndroid Build Coastguard Worker 62*795d594fSAndroid Build Coastguard Worker public static final boolean DEBUG = false; 63*795d594fSAndroid Build Coastguard Worker 64*795d594fSAndroid Build Coastguard Worker private static abstract class Operation { 65*795d594fSAndroid Build Coastguard Worker /** 66*795d594fSAndroid Build Coastguard Worker * Perform the action represented by this operation. Returns true if the thread should 67*795d594fSAndroid Build Coastguard Worker * continue when executed by a runner (non-daemon) thread. 68*795d594fSAndroid Build Coastguard Worker */ perform()69*795d594fSAndroid Build Coastguard Worker public abstract boolean perform(); 70*795d594fSAndroid Build Coastguard Worker } 71*795d594fSAndroid Build Coastguard Worker 72*795d594fSAndroid Build Coastguard Worker private final static class OOM extends Operation { 73*795d594fSAndroid Build Coastguard Worker private final static int ALLOC_SIZE = 1024; 74*795d594fSAndroid Build Coastguard Worker 75*795d594fSAndroid Build Coastguard Worker @Override perform()76*795d594fSAndroid Build Coastguard Worker public boolean perform() { 77*795d594fSAndroid Build Coastguard Worker try { 78*795d594fSAndroid Build Coastguard Worker List<byte[]> l = new ArrayList<byte[]>(); 79*795d594fSAndroid Build Coastguard Worker while (true) { 80*795d594fSAndroid Build Coastguard Worker l.add(new byte[ALLOC_SIZE]); 81*795d594fSAndroid Build Coastguard Worker } 82*795d594fSAndroid Build Coastguard Worker } catch (OutOfMemoryError e) { 83*795d594fSAndroid Build Coastguard Worker } 84*795d594fSAndroid Build Coastguard Worker return true; 85*795d594fSAndroid Build Coastguard Worker } 86*795d594fSAndroid Build Coastguard Worker } 87*795d594fSAndroid Build Coastguard Worker 88*795d594fSAndroid Build Coastguard Worker private final static class SigQuit extends Operation { 89*795d594fSAndroid Build Coastguard Worker private final static int sigquit; 90*795d594fSAndroid Build Coastguard Worker private final static Method kill; 91*795d594fSAndroid Build Coastguard Worker private final static int pid; 92*795d594fSAndroid Build Coastguard Worker 93*795d594fSAndroid Build Coastguard Worker static { 94*795d594fSAndroid Build Coastguard Worker int pidTemp = -1; 95*795d594fSAndroid Build Coastguard Worker int sigquitTemp = -1; 96*795d594fSAndroid Build Coastguard Worker Method killTemp = null; 97*795d594fSAndroid Build Coastguard Worker 98*795d594fSAndroid Build Coastguard Worker try { 99*795d594fSAndroid Build Coastguard Worker Class<?> osClass = Class.forName("android.system.Os"); 100*795d594fSAndroid Build Coastguard Worker Method getpid = osClass.getDeclaredMethod("getpid"); 101*795d594fSAndroid Build Coastguard Worker pidTemp = (Integer)getpid.invoke(null); 102*795d594fSAndroid Build Coastguard Worker 103*795d594fSAndroid Build Coastguard Worker Class<?> osConstants = Class.forName("android.system.OsConstants"); 104*795d594fSAndroid Build Coastguard Worker Field sigquitField = osConstants.getDeclaredField("SIGQUIT"); 105*795d594fSAndroid Build Coastguard Worker sigquitTemp = (Integer)sigquitField.get(null); 106*795d594fSAndroid Build Coastguard Worker 107*795d594fSAndroid Build Coastguard Worker killTemp = osClass.getDeclaredMethod("kill", int.class, int.class); 108*795d594fSAndroid Build Coastguard Worker } catch (Exception e) { 109*795d594fSAndroid Build Coastguard Worker Main.printThrowable(e); 110*795d594fSAndroid Build Coastguard Worker } 111*795d594fSAndroid Build Coastguard Worker 112*795d594fSAndroid Build Coastguard Worker pid = pidTemp; 113*795d594fSAndroid Build Coastguard Worker sigquit = sigquitTemp; 114*795d594fSAndroid Build Coastguard Worker kill = killTemp; 115*795d594fSAndroid Build Coastguard Worker } 116*795d594fSAndroid Build Coastguard Worker 117*795d594fSAndroid Build Coastguard Worker @Override perform()118*795d594fSAndroid Build Coastguard Worker public boolean perform() { 119*795d594fSAndroid Build Coastguard Worker try { 120*795d594fSAndroid Build Coastguard Worker kill.invoke(null, pid, sigquit); 121*795d594fSAndroid Build Coastguard Worker } catch (OutOfMemoryError e) { 122*795d594fSAndroid Build Coastguard Worker } catch (Exception e) { 123*795d594fSAndroid Build Coastguard Worker if (!e.getClass().getName().equals(Main.errnoExceptionName)) { 124*795d594fSAndroid Build Coastguard Worker Main.printThrowable(e); 125*795d594fSAndroid Build Coastguard Worker } 126*795d594fSAndroid Build Coastguard Worker } 127*795d594fSAndroid Build Coastguard Worker return true; 128*795d594fSAndroid Build Coastguard Worker } 129*795d594fSAndroid Build Coastguard Worker } 130*795d594fSAndroid Build Coastguard Worker 131*795d594fSAndroid Build Coastguard Worker private final static class Alloc extends Operation { 132*795d594fSAndroid Build Coastguard Worker private final static int ALLOC_SIZE = 1024; // Needs to be small enough to not be in LOS. 133*795d594fSAndroid Build Coastguard Worker private final static int ALLOC_COUNT = 1024; 134*795d594fSAndroid Build Coastguard Worker 135*795d594fSAndroid Build Coastguard Worker @Override perform()136*795d594fSAndroid Build Coastguard Worker public boolean perform() { 137*795d594fSAndroid Build Coastguard Worker try { 138*795d594fSAndroid Build Coastguard Worker List<byte[]> l = new ArrayList<byte[]>(); 139*795d594fSAndroid Build Coastguard Worker for (int i = 0; i < ALLOC_COUNT; i++) { 140*795d594fSAndroid Build Coastguard Worker l.add(new byte[ALLOC_SIZE]); 141*795d594fSAndroid Build Coastguard Worker } 142*795d594fSAndroid Build Coastguard Worker } catch (OutOfMemoryError e) { 143*795d594fSAndroid Build Coastguard Worker } 144*795d594fSAndroid Build Coastguard Worker return true; 145*795d594fSAndroid Build Coastguard Worker } 146*795d594fSAndroid Build Coastguard Worker } 147*795d594fSAndroid Build Coastguard Worker 148*795d594fSAndroid Build Coastguard Worker private final static class LargeAlloc extends Operation { 149*795d594fSAndroid Build Coastguard Worker private final static int PAGE_SIZE = 4096; 150*795d594fSAndroid Build Coastguard Worker private final static int PAGE_SIZE_MODIFIER = 10; // Needs to be large enough for LOS. 151*795d594fSAndroid Build Coastguard Worker private final static int ALLOC_COUNT = 100; 152*795d594fSAndroid Build Coastguard Worker 153*795d594fSAndroid Build Coastguard Worker @Override perform()154*795d594fSAndroid Build Coastguard Worker public boolean perform() { 155*795d594fSAndroid Build Coastguard Worker try { 156*795d594fSAndroid Build Coastguard Worker List<byte[]> l = new ArrayList<byte[]>(); 157*795d594fSAndroid Build Coastguard Worker for (int i = 0; i < ALLOC_COUNT; i++) { 158*795d594fSAndroid Build Coastguard Worker l.add(new byte[PAGE_SIZE_MODIFIER * PAGE_SIZE]); 159*795d594fSAndroid Build Coastguard Worker } 160*795d594fSAndroid Build Coastguard Worker } catch (OutOfMemoryError e) { 161*795d594fSAndroid Build Coastguard Worker } 162*795d594fSAndroid Build Coastguard Worker return true; 163*795d594fSAndroid Build Coastguard Worker } 164*795d594fSAndroid Build Coastguard Worker } 165*795d594fSAndroid Build Coastguard Worker 166*795d594fSAndroid Build Coastguard Worker private final static class NonMovingAlloc extends Operation { 167*795d594fSAndroid Build Coastguard Worker private final static int ALLOC_SIZE = 1024; // Needs to be small enough to not be in LOS. 168*795d594fSAndroid Build Coastguard Worker private final static int ALLOC_COUNT = 1024; 169*795d594fSAndroid Build Coastguard Worker private final static VMRuntime runtime = VMRuntime.getRuntime(); 170*795d594fSAndroid Build Coastguard Worker 171*795d594fSAndroid Build Coastguard Worker @Override perform()172*795d594fSAndroid Build Coastguard Worker public boolean perform() { 173*795d594fSAndroid Build Coastguard Worker try { 174*795d594fSAndroid Build Coastguard Worker List<byte[]> l = new ArrayList<byte[]>(); 175*795d594fSAndroid Build Coastguard Worker for (int i = 0; i < ALLOC_COUNT; i++) { 176*795d594fSAndroid Build Coastguard Worker l.add((byte[]) runtime.newNonMovableArray(byte.class, ALLOC_SIZE)); 177*795d594fSAndroid Build Coastguard Worker } 178*795d594fSAndroid Build Coastguard Worker } catch (OutOfMemoryError e) { 179*795d594fSAndroid Build Coastguard Worker } 180*795d594fSAndroid Build Coastguard Worker return true; 181*795d594fSAndroid Build Coastguard Worker } 182*795d594fSAndroid Build Coastguard Worker } 183*795d594fSAndroid Build Coastguard Worker 184*795d594fSAndroid Build Coastguard Worker 185*795d594fSAndroid Build Coastguard Worker private final static class StackTrace extends Operation { 186*795d594fSAndroid Build Coastguard Worker @Override perform()187*795d594fSAndroid Build Coastguard Worker public boolean perform() { 188*795d594fSAndroid Build Coastguard Worker try { 189*795d594fSAndroid Build Coastguard Worker Thread.currentThread().getStackTrace(); 190*795d594fSAndroid Build Coastguard Worker } catch (OutOfMemoryError e) { 191*795d594fSAndroid Build Coastguard Worker } 192*795d594fSAndroid Build Coastguard Worker return true; 193*795d594fSAndroid Build Coastguard Worker } 194*795d594fSAndroid Build Coastguard Worker } 195*795d594fSAndroid Build Coastguard Worker 196*795d594fSAndroid Build Coastguard Worker private final static class Exit extends Operation { 197*795d594fSAndroid Build Coastguard Worker @Override perform()198*795d594fSAndroid Build Coastguard Worker public boolean perform() { 199*795d594fSAndroid Build Coastguard Worker return false; 200*795d594fSAndroid Build Coastguard Worker } 201*795d594fSAndroid Build Coastguard Worker } 202*795d594fSAndroid Build Coastguard Worker 203*795d594fSAndroid Build Coastguard Worker private final static class Sleep extends Operation { 204*795d594fSAndroid Build Coastguard Worker private final static int SLEEP_TIME = 100; 205*795d594fSAndroid Build Coastguard Worker 206*795d594fSAndroid Build Coastguard Worker @Override perform()207*795d594fSAndroid Build Coastguard Worker public boolean perform() { 208*795d594fSAndroid Build Coastguard Worker try { 209*795d594fSAndroid Build Coastguard Worker Thread.sleep(SLEEP_TIME); 210*795d594fSAndroid Build Coastguard Worker } catch (InterruptedException ignored) { 211*795d594fSAndroid Build Coastguard Worker } 212*795d594fSAndroid Build Coastguard Worker return true; 213*795d594fSAndroid Build Coastguard Worker } 214*795d594fSAndroid Build Coastguard Worker } 215*795d594fSAndroid Build Coastguard Worker 216*795d594fSAndroid Build Coastguard Worker private final static class TimedWait extends Operation { 217*795d594fSAndroid Build Coastguard Worker private final static int SLEEP_TIME = 100; 218*795d594fSAndroid Build Coastguard Worker 219*795d594fSAndroid Build Coastguard Worker private final Object lock; 220*795d594fSAndroid Build Coastguard Worker TimedWait(Object lock)221*795d594fSAndroid Build Coastguard Worker public TimedWait(Object lock) { 222*795d594fSAndroid Build Coastguard Worker this.lock = lock; 223*795d594fSAndroid Build Coastguard Worker } 224*795d594fSAndroid Build Coastguard Worker 225*795d594fSAndroid Build Coastguard Worker @Override perform()226*795d594fSAndroid Build Coastguard Worker public boolean perform() { 227*795d594fSAndroid Build Coastguard Worker synchronized (lock) { 228*795d594fSAndroid Build Coastguard Worker try { 229*795d594fSAndroid Build Coastguard Worker lock.wait(SLEEP_TIME, 0); 230*795d594fSAndroid Build Coastguard Worker } catch (InterruptedException ignored) { 231*795d594fSAndroid Build Coastguard Worker } 232*795d594fSAndroid Build Coastguard Worker } 233*795d594fSAndroid Build Coastguard Worker return true; 234*795d594fSAndroid Build Coastguard Worker } 235*795d594fSAndroid Build Coastguard Worker } 236*795d594fSAndroid Build Coastguard Worker 237*795d594fSAndroid Build Coastguard Worker private final static class Wait extends Operation { 238*795d594fSAndroid Build Coastguard Worker private final Object lock; 239*795d594fSAndroid Build Coastguard Worker Wait(Object lock)240*795d594fSAndroid Build Coastguard Worker public Wait(Object lock) { 241*795d594fSAndroid Build Coastguard Worker this.lock = lock; 242*795d594fSAndroid Build Coastguard Worker } 243*795d594fSAndroid Build Coastguard Worker 244*795d594fSAndroid Build Coastguard Worker @Override perform()245*795d594fSAndroid Build Coastguard Worker public boolean perform() { 246*795d594fSAndroid Build Coastguard Worker synchronized (lock) { 247*795d594fSAndroid Build Coastguard Worker try { 248*795d594fSAndroid Build Coastguard Worker lock.wait(); 249*795d594fSAndroid Build Coastguard Worker } catch (InterruptedException ignored) { 250*795d594fSAndroid Build Coastguard Worker } 251*795d594fSAndroid Build Coastguard Worker } 252*795d594fSAndroid Build Coastguard Worker return true; 253*795d594fSAndroid Build Coastguard Worker } 254*795d594fSAndroid Build Coastguard Worker } 255*795d594fSAndroid Build Coastguard Worker 256*795d594fSAndroid Build Coastguard Worker private final static class TimedPark extends Operation { 257*795d594fSAndroid Build Coastguard Worker private final static int SLEEP_TIME = 100; 258*795d594fSAndroid Build Coastguard Worker TimedPark()259*795d594fSAndroid Build Coastguard Worker public TimedPark() {} 260*795d594fSAndroid Build Coastguard Worker 261*795d594fSAndroid Build Coastguard Worker @Override perform()262*795d594fSAndroid Build Coastguard Worker public boolean perform() { 263*795d594fSAndroid Build Coastguard Worker LockSupport.parkNanos(this, 100*1000000); 264*795d594fSAndroid Build Coastguard Worker return true; 265*795d594fSAndroid Build Coastguard Worker } 266*795d594fSAndroid Build Coastguard Worker } 267*795d594fSAndroid Build Coastguard Worker 268*795d594fSAndroid Build Coastguard Worker private final static class SyncAndWork extends Operation { 269*795d594fSAndroid Build Coastguard Worker private final Object lock; 270*795d594fSAndroid Build Coastguard Worker SyncAndWork(Object lock)271*795d594fSAndroid Build Coastguard Worker public SyncAndWork(Object lock) { 272*795d594fSAndroid Build Coastguard Worker this.lock = lock; 273*795d594fSAndroid Build Coastguard Worker } 274*795d594fSAndroid Build Coastguard Worker 275*795d594fSAndroid Build Coastguard Worker @Override perform()276*795d594fSAndroid Build Coastguard Worker public boolean perform() { 277*795d594fSAndroid Build Coastguard Worker synchronized (lock) { 278*795d594fSAndroid Build Coastguard Worker try { 279*795d594fSAndroid Build Coastguard Worker Thread.sleep((int)(Math.random() * 50 + 50)); 280*795d594fSAndroid Build Coastguard Worker } catch (InterruptedException ignored) { 281*795d594fSAndroid Build Coastguard Worker } 282*795d594fSAndroid Build Coastguard Worker } 283*795d594fSAndroid Build Coastguard Worker return true; 284*795d594fSAndroid Build Coastguard Worker } 285*795d594fSAndroid Build Coastguard Worker } 286*795d594fSAndroid Build Coastguard Worker 287*795d594fSAndroid Build Coastguard Worker // An operation requiring the acquisition of a permit from a semaphore 288*795d594fSAndroid Build Coastguard Worker // for its execution. This operation has been added to exercise 289*795d594fSAndroid Build Coastguard Worker // java.util.concurrent.locks.AbstractQueuedSynchronizer, used in the 290*795d594fSAndroid Build Coastguard Worker // implementation of java.util.concurrent.Semaphore. We use the latter, 291*795d594fSAndroid Build Coastguard Worker // as the former is not supposed to be used directly (see b/63822989). 292*795d594fSAndroid Build Coastguard Worker private final static class QueuedWait extends Operation { 293*795d594fSAndroid Build Coastguard Worker private final static int SLEEP_TIME = 100; 294*795d594fSAndroid Build Coastguard Worker 295*795d594fSAndroid Build Coastguard Worker private final Semaphore semaphore; 296*795d594fSAndroid Build Coastguard Worker QueuedWait(Semaphore semaphore)297*795d594fSAndroid Build Coastguard Worker public QueuedWait(Semaphore semaphore) { 298*795d594fSAndroid Build Coastguard Worker this.semaphore = semaphore; 299*795d594fSAndroid Build Coastguard Worker } 300*795d594fSAndroid Build Coastguard Worker 301*795d594fSAndroid Build Coastguard Worker @Override perform()302*795d594fSAndroid Build Coastguard Worker public boolean perform() { 303*795d594fSAndroid Build Coastguard Worker boolean permitAcquired = false; 304*795d594fSAndroid Build Coastguard Worker try { 305*795d594fSAndroid Build Coastguard Worker semaphore.acquire(); 306*795d594fSAndroid Build Coastguard Worker permitAcquired = true; 307*795d594fSAndroid Build Coastguard Worker Thread.sleep(SLEEP_TIME); 308*795d594fSAndroid Build Coastguard Worker } catch (OutOfMemoryError ignored) { 309*795d594fSAndroid Build Coastguard Worker // The call to semaphore.acquire() above may trigger an OOME, 310*795d594fSAndroid Build Coastguard Worker // despite the care taken doing some warm-up by forcing 311*795d594fSAndroid Build Coastguard Worker // ahead-of-time initialization of classes used by the Semaphore 312*795d594fSAndroid Build Coastguard Worker // class (see forceTransitiveClassInitialization below). 313*795d594fSAndroid Build Coastguard Worker // For instance, one of the code paths executes 314*795d594fSAndroid Build Coastguard Worker // AbstractQueuedSynchronizer.addWaiter, which allocates an 315*795d594fSAndroid Build Coastguard Worker // AbstractQueuedSynchronizer$Node (see b/67730573). 316*795d594fSAndroid Build Coastguard Worker // In that case, just ignore the OOME and continue. 317*795d594fSAndroid Build Coastguard Worker } catch (InterruptedException ignored) { 318*795d594fSAndroid Build Coastguard Worker } finally { 319*795d594fSAndroid Build Coastguard Worker if (permitAcquired) { 320*795d594fSAndroid Build Coastguard Worker semaphore.release(); 321*795d594fSAndroid Build Coastguard Worker } 322*795d594fSAndroid Build Coastguard Worker } 323*795d594fSAndroid Build Coastguard Worker return true; 324*795d594fSAndroid Build Coastguard Worker } 325*795d594fSAndroid Build Coastguard Worker } 326*795d594fSAndroid Build Coastguard Worker createDefaultFrequencyMap(Object lock, Semaphore semaphore)327*795d594fSAndroid Build Coastguard Worker private final static Map<Operation, Double> createDefaultFrequencyMap(Object lock, 328*795d594fSAndroid Build Coastguard Worker Semaphore semaphore) { 329*795d594fSAndroid Build Coastguard Worker Map<Operation, Double> frequencyMap = new HashMap<Operation, Double>(); 330*795d594fSAndroid Build Coastguard Worker frequencyMap.put(new OOM(), 0.005); // 1/200 331*795d594fSAndroid Build Coastguard Worker frequencyMap.put(new SigQuit(), 0.095); // 19/200 332*795d594fSAndroid Build Coastguard Worker frequencyMap.put(new Alloc(), 0.2); // 40/200 333*795d594fSAndroid Build Coastguard Worker frequencyMap.put(new LargeAlloc(), 0.05); // 10/200 334*795d594fSAndroid Build Coastguard Worker frequencyMap.put(new NonMovingAlloc(), 0.025); // 5/200 335*795d594fSAndroid Build Coastguard Worker frequencyMap.put(new StackTrace(), 0.1); // 20/200 336*795d594fSAndroid Build Coastguard Worker frequencyMap.put(new Exit(), 0.225); // 45/200 337*795d594fSAndroid Build Coastguard Worker frequencyMap.put(new Sleep(), 0.075); // 15/200 338*795d594fSAndroid Build Coastguard Worker frequencyMap.put(new TimedPark(), 0.05); // 10/200 339*795d594fSAndroid Build Coastguard Worker frequencyMap.put(new TimedWait(lock), 0.05); // 10/200 340*795d594fSAndroid Build Coastguard Worker frequencyMap.put(new Wait(lock), 0.075); // 15/200 341*795d594fSAndroid Build Coastguard Worker frequencyMap.put(new QueuedWait(semaphore), 0.05); // 10/200 342*795d594fSAndroid Build Coastguard Worker 343*795d594fSAndroid Build Coastguard Worker return frequencyMap; 344*795d594fSAndroid Build Coastguard Worker } 345*795d594fSAndroid Build Coastguard Worker createAllocFrequencyMap()346*795d594fSAndroid Build Coastguard Worker private final static Map<Operation, Double> createAllocFrequencyMap() { 347*795d594fSAndroid Build Coastguard Worker Map<Operation, Double> frequencyMap = new HashMap<Operation, Double>(); 348*795d594fSAndroid Build Coastguard Worker frequencyMap.put(new Sleep(), 0.2); // 40/200 349*795d594fSAndroid Build Coastguard Worker frequencyMap.put(new Alloc(), 0.575); // 115/200 350*795d594fSAndroid Build Coastguard Worker frequencyMap.put(new LargeAlloc(), 0.15); // 30/200 351*795d594fSAndroid Build Coastguard Worker frequencyMap.put(new NonMovingAlloc(), 0.075); // 15/200 352*795d594fSAndroid Build Coastguard Worker 353*795d594fSAndroid Build Coastguard Worker return frequencyMap; 354*795d594fSAndroid Build Coastguard Worker } 355*795d594fSAndroid Build Coastguard Worker createLockFrequencyMap(Object lock)356*795d594fSAndroid Build Coastguard Worker private final static Map<Operation, Double> createLockFrequencyMap(Object lock) { 357*795d594fSAndroid Build Coastguard Worker Map<Operation, Double> frequencyMap = new HashMap<Operation, Double>(); 358*795d594fSAndroid Build Coastguard Worker frequencyMap.put(new Sleep(), 0.2); // 40/200 359*795d594fSAndroid Build Coastguard Worker frequencyMap.put(new TimedWait(lock), 0.1); // 20/200 360*795d594fSAndroid Build Coastguard Worker frequencyMap.put(new Wait(lock), 0.2); // 40/200 361*795d594fSAndroid Build Coastguard Worker frequencyMap.put(new SyncAndWork(lock), 0.4); // 80/200 362*795d594fSAndroid Build Coastguard Worker frequencyMap.put(new TimedPark(), 0.1); // 20/200 363*795d594fSAndroid Build Coastguard Worker 364*795d594fSAndroid Build Coastguard Worker return frequencyMap; 365*795d594fSAndroid Build Coastguard Worker } 366*795d594fSAndroid Build Coastguard Worker main(String[] args)367*795d594fSAndroid Build Coastguard Worker public static void main(String[] args) throws Exception { 368*795d594fSAndroid Build Coastguard Worker System.loadLibrary(args[0]); 369*795d594fSAndroid Build Coastguard Worker parseAndRun(args); 370*795d594fSAndroid Build Coastguard Worker } 371*795d594fSAndroid Build Coastguard Worker updateFrequencyMap(Map<Operation, Double> in, Object lock, Semaphore semaphore, String arg)372*795d594fSAndroid Build Coastguard Worker private static Map<Operation, Double> updateFrequencyMap(Map<Operation, Double> in, 373*795d594fSAndroid Build Coastguard Worker Object lock, Semaphore semaphore, String arg) { 374*795d594fSAndroid Build Coastguard Worker String split[] = arg.split(":"); 375*795d594fSAndroid Build Coastguard Worker if (split.length != 2) { 376*795d594fSAndroid Build Coastguard Worker throw new IllegalArgumentException("Can't split argument " + arg); 377*795d594fSAndroid Build Coastguard Worker } 378*795d594fSAndroid Build Coastguard Worker double d; 379*795d594fSAndroid Build Coastguard Worker try { 380*795d594fSAndroid Build Coastguard Worker d = Double.parseDouble(split[1]); 381*795d594fSAndroid Build Coastguard Worker } catch (Exception e) { 382*795d594fSAndroid Build Coastguard Worker throw new IllegalArgumentException(e); 383*795d594fSAndroid Build Coastguard Worker } 384*795d594fSAndroid Build Coastguard Worker if (d < 0) { 385*795d594fSAndroid Build Coastguard Worker throw new IllegalArgumentException(arg + ": value must be >= 0."); 386*795d594fSAndroid Build Coastguard Worker } 387*795d594fSAndroid Build Coastguard Worker Operation op = null; 388*795d594fSAndroid Build Coastguard Worker if (split[0].equals("-oom")) { 389*795d594fSAndroid Build Coastguard Worker op = new OOM(); 390*795d594fSAndroid Build Coastguard Worker } else if (split[0].equals("-sigquit")) { 391*795d594fSAndroid Build Coastguard Worker op = new SigQuit(); 392*795d594fSAndroid Build Coastguard Worker } else if (split[0].equals("-alloc")) { 393*795d594fSAndroid Build Coastguard Worker op = new Alloc(); 394*795d594fSAndroid Build Coastguard Worker } else if (split[0].equals("-largealloc")) { 395*795d594fSAndroid Build Coastguard Worker op = new LargeAlloc(); 396*795d594fSAndroid Build Coastguard Worker } else if (split[0].equals("-nonmovingalloc")) { 397*795d594fSAndroid Build Coastguard Worker op = new NonMovingAlloc(); 398*795d594fSAndroid Build Coastguard Worker } else if (split[0].equals("-stacktrace")) { 399*795d594fSAndroid Build Coastguard Worker op = new StackTrace(); 400*795d594fSAndroid Build Coastguard Worker } else if (split[0].equals("-exit")) { 401*795d594fSAndroid Build Coastguard Worker op = new Exit(); 402*795d594fSAndroid Build Coastguard Worker } else if (split[0].equals("-sleep")) { 403*795d594fSAndroid Build Coastguard Worker op = new Sleep(); 404*795d594fSAndroid Build Coastguard Worker } else if (split[0].equals("-wait")) { 405*795d594fSAndroid Build Coastguard Worker op = new Wait(lock); 406*795d594fSAndroid Build Coastguard Worker } else if (split[0].equals("-timedwait")) { 407*795d594fSAndroid Build Coastguard Worker op = new TimedWait(lock); 408*795d594fSAndroid Build Coastguard Worker } else if (split[0].equals("-timedpark")) { 409*795d594fSAndroid Build Coastguard Worker op = new TimedPark(); 410*795d594fSAndroid Build Coastguard Worker } else if (split[0].equals("-syncandwork")) { 411*795d594fSAndroid Build Coastguard Worker op = new SyncAndWork(lock); 412*795d594fSAndroid Build Coastguard Worker } else if (split[0].equals("-queuedwait")) { 413*795d594fSAndroid Build Coastguard Worker op = new QueuedWait(semaphore); 414*795d594fSAndroid Build Coastguard Worker } else { 415*795d594fSAndroid Build Coastguard Worker throw new IllegalArgumentException("Unknown arg " + arg); 416*795d594fSAndroid Build Coastguard Worker } 417*795d594fSAndroid Build Coastguard Worker 418*795d594fSAndroid Build Coastguard Worker if (in == null) { 419*795d594fSAndroid Build Coastguard Worker in = new HashMap<Operation, Double>(); 420*795d594fSAndroid Build Coastguard Worker } 421*795d594fSAndroid Build Coastguard Worker in.put(op, d); 422*795d594fSAndroid Build Coastguard Worker 423*795d594fSAndroid Build Coastguard Worker return in; 424*795d594fSAndroid Build Coastguard Worker } 425*795d594fSAndroid Build Coastguard Worker normalize(Map<Operation, Double> map)426*795d594fSAndroid Build Coastguard Worker private static void normalize(Map<Operation, Double> map) { 427*795d594fSAndroid Build Coastguard Worker double sum = 0; 428*795d594fSAndroid Build Coastguard Worker for (Double d : map.values()) { 429*795d594fSAndroid Build Coastguard Worker sum += d; 430*795d594fSAndroid Build Coastguard Worker } 431*795d594fSAndroid Build Coastguard Worker if (sum == 0) { 432*795d594fSAndroid Build Coastguard Worker throw new RuntimeException("No elements!"); 433*795d594fSAndroid Build Coastguard Worker } 434*795d594fSAndroid Build Coastguard Worker if (sum != 1.0) { 435*795d594fSAndroid Build Coastguard Worker // Avoid ConcurrentModificationException. 436*795d594fSAndroid Build Coastguard Worker Set<Operation> tmp = new HashSet<>(map.keySet()); 437*795d594fSAndroid Build Coastguard Worker for (Operation op : tmp) { 438*795d594fSAndroid Build Coastguard Worker map.put(op, map.get(op) / sum); 439*795d594fSAndroid Build Coastguard Worker } 440*795d594fSAndroid Build Coastguard Worker } 441*795d594fSAndroid Build Coastguard Worker } 442*795d594fSAndroid Build Coastguard Worker parseAndRun(String[] args)443*795d594fSAndroid Build Coastguard Worker public static void parseAndRun(String[] args) throws Exception { 444*795d594fSAndroid Build Coastguard Worker int numberOfThreads = -1; 445*795d594fSAndroid Build Coastguard Worker int numberOfDaemons = -1; 446*795d594fSAndroid Build Coastguard Worker int totalOperations = -1; 447*795d594fSAndroid Build Coastguard Worker int operationsPerThread = -1; 448*795d594fSAndroid Build Coastguard Worker int permits = -1; 449*795d594fSAndroid Build Coastguard Worker Object lock = new Object(); 450*795d594fSAndroid Build Coastguard Worker Map<Operation, Double> frequencyMap = null; 451*795d594fSAndroid Build Coastguard Worker boolean dumpMap = false; 452*795d594fSAndroid Build Coastguard Worker 453*795d594fSAndroid Build Coastguard Worker if (args != null) { 454*795d594fSAndroid Build Coastguard Worker // args[0] is libarttest 455*795d594fSAndroid Build Coastguard Worker for (int i = 1; i < args.length; i++) { 456*795d594fSAndroid Build Coastguard Worker if (args[i].equals("-n")) { 457*795d594fSAndroid Build Coastguard Worker i++; 458*795d594fSAndroid Build Coastguard Worker numberOfThreads = Integer.parseInt(args[i]); 459*795d594fSAndroid Build Coastguard Worker } else if (args[i].equals("-d")) { 460*795d594fSAndroid Build Coastguard Worker i++; 461*795d594fSAndroid Build Coastguard Worker numberOfDaemons = Integer.parseInt(args[i]); 462*795d594fSAndroid Build Coastguard Worker } else if (args[i].equals("-o")) { 463*795d594fSAndroid Build Coastguard Worker i++; 464*795d594fSAndroid Build Coastguard Worker totalOperations = Integer.parseInt(args[i]); 465*795d594fSAndroid Build Coastguard Worker } else if (args[i].equals("-t")) { 466*795d594fSAndroid Build Coastguard Worker i++; 467*795d594fSAndroid Build Coastguard Worker operationsPerThread = Integer.parseInt(args[i]); 468*795d594fSAndroid Build Coastguard Worker } else if (args[i].equals("-p")) { 469*795d594fSAndroid Build Coastguard Worker i++; 470*795d594fSAndroid Build Coastguard Worker permits = Integer.parseInt(args[i]); 471*795d594fSAndroid Build Coastguard Worker } else if (args[i].equals("--locks-only")) { 472*795d594fSAndroid Build Coastguard Worker frequencyMap = createLockFrequencyMap(lock); 473*795d594fSAndroid Build Coastguard Worker } else if (args[i].equals("--allocs-only")) { 474*795d594fSAndroid Build Coastguard Worker frequencyMap = createAllocFrequencyMap(); 475*795d594fSAndroid Build Coastguard Worker } else if (args[i].equals("--dumpmap")) { 476*795d594fSAndroid Build Coastguard Worker dumpMap = true; 477*795d594fSAndroid Build Coastguard Worker } else { 478*795d594fSAndroid Build Coastguard Worker // Processing an argument of the form "-<operation>:X" 479*795d594fSAndroid Build Coastguard Worker // (where X is a double value). 480*795d594fSAndroid Build Coastguard Worker Semaphore semaphore = getSemaphore(permits); 481*795d594fSAndroid Build Coastguard Worker frequencyMap = updateFrequencyMap(frequencyMap, lock, semaphore, args[i]); 482*795d594fSAndroid Build Coastguard Worker } 483*795d594fSAndroid Build Coastguard Worker } 484*795d594fSAndroid Build Coastguard Worker } 485*795d594fSAndroid Build Coastguard Worker 486*795d594fSAndroid Build Coastguard Worker if (totalOperations != -1 && operationsPerThread != -1) { 487*795d594fSAndroid Build Coastguard Worker throw new IllegalArgumentException( 488*795d594fSAndroid Build Coastguard Worker "Specified both totalOperations and operationsPerThread"); 489*795d594fSAndroid Build Coastguard Worker } 490*795d594fSAndroid Build Coastguard Worker 491*795d594fSAndroid Build Coastguard Worker if (numberOfThreads == -1) { 492*795d594fSAndroid Build Coastguard Worker numberOfThreads = 5; 493*795d594fSAndroid Build Coastguard Worker } 494*795d594fSAndroid Build Coastguard Worker 495*795d594fSAndroid Build Coastguard Worker if (numberOfDaemons == -1) { 496*795d594fSAndroid Build Coastguard Worker numberOfDaemons = 3; 497*795d594fSAndroid Build Coastguard Worker } 498*795d594fSAndroid Build Coastguard Worker 499*795d594fSAndroid Build Coastguard Worker if (totalOperations == -1) { 500*795d594fSAndroid Build Coastguard Worker totalOperations = 1000; 501*795d594fSAndroid Build Coastguard Worker } 502*795d594fSAndroid Build Coastguard Worker 503*795d594fSAndroid Build Coastguard Worker if (operationsPerThread == -1) { 504*795d594fSAndroid Build Coastguard Worker operationsPerThread = totalOperations/numberOfThreads; 505*795d594fSAndroid Build Coastguard Worker } 506*795d594fSAndroid Build Coastguard Worker 507*795d594fSAndroid Build Coastguard Worker if (frequencyMap == null) { 508*795d594fSAndroid Build Coastguard Worker Semaphore semaphore = getSemaphore(permits); 509*795d594fSAndroid Build Coastguard Worker frequencyMap = createDefaultFrequencyMap(lock, semaphore); 510*795d594fSAndroid Build Coastguard Worker } 511*795d594fSAndroid Build Coastguard Worker normalize(frequencyMap); 512*795d594fSAndroid Build Coastguard Worker 513*795d594fSAndroid Build Coastguard Worker if (dumpMap) { 514*795d594fSAndroid Build Coastguard Worker System.out.println(frequencyMap); 515*795d594fSAndroid Build Coastguard Worker } 516*795d594fSAndroid Build Coastguard Worker 517*795d594fSAndroid Build Coastguard Worker try { 518*795d594fSAndroid Build Coastguard Worker runTest(numberOfThreads, numberOfDaemons, operationsPerThread, lock, frequencyMap); 519*795d594fSAndroid Build Coastguard Worker } catch (Throwable t) { 520*795d594fSAndroid Build Coastguard Worker // In this case, the output should not contain all the required 521*795d594fSAndroid Build Coastguard Worker // "Finishing worker" lines. 522*795d594fSAndroid Build Coastguard Worker Main.printThrowable(t); 523*795d594fSAndroid Build Coastguard Worker } 524*795d594fSAndroid Build Coastguard Worker } 525*795d594fSAndroid Build Coastguard Worker getSemaphore(int permits)526*795d594fSAndroid Build Coastguard Worker private static Semaphore getSemaphore(int permits) { 527*795d594fSAndroid Build Coastguard Worker if (permits == -1) { 528*795d594fSAndroid Build Coastguard Worker // Default number of permits. 529*795d594fSAndroid Build Coastguard Worker permits = 3; 530*795d594fSAndroid Build Coastguard Worker } 531*795d594fSAndroid Build Coastguard Worker 532*795d594fSAndroid Build Coastguard Worker Semaphore semaphore = new Semaphore(permits, /* fair */ true); 533*795d594fSAndroid Build Coastguard Worker forceTransitiveClassInitialization(semaphore, permits); 534*795d594fSAndroid Build Coastguard Worker return semaphore; 535*795d594fSAndroid Build Coastguard Worker } 536*795d594fSAndroid Build Coastguard Worker 537*795d594fSAndroid Build Coastguard Worker // Force ahead-of-time initialization of classes used by Semaphore 538*795d594fSAndroid Build Coastguard Worker // code. Try to exercise all code paths likely to be taken during 539*795d594fSAndroid Build Coastguard Worker // the actual test later (including having a thread blocking on 540*795d594fSAndroid Build Coastguard Worker // the semaphore trying to acquire a permit), so that we increase 541*795d594fSAndroid Build Coastguard Worker // the chances to initialize all classes indirectly used by 542*795d594fSAndroid Build Coastguard Worker // QueuedWait (e.g. AbstractQueuedSynchronizer$Node). forceTransitiveClassInitialization(Semaphore semaphore, final int permits)543*795d594fSAndroid Build Coastguard Worker private static void forceTransitiveClassInitialization(Semaphore semaphore, final int permits) { 544*795d594fSAndroid Build Coastguard Worker // Ensure `semaphore` has the expected number of permits 545*795d594fSAndroid Build Coastguard Worker // before we start. 546*795d594fSAndroid Build Coastguard Worker assert semaphore.availablePermits() == permits; 547*795d594fSAndroid Build Coastguard Worker 548*795d594fSAndroid Build Coastguard Worker // Let the main (current) thread acquire all permits from 549*795d594fSAndroid Build Coastguard Worker // `semaphore`. Then create an auxiliary thread acquiring a 550*795d594fSAndroid Build Coastguard Worker // permit from `semaphore`, blocking because none is 551*795d594fSAndroid Build Coastguard Worker // available. Have the main thread release one permit, thus 552*795d594fSAndroid Build Coastguard Worker // unblocking the second thread. 553*795d594fSAndroid Build Coastguard Worker 554*795d594fSAndroid Build Coastguard Worker // Auxiliary thread. 555*795d594fSAndroid Build Coastguard Worker Thread auxThread = new Thread("Aux") { 556*795d594fSAndroid Build Coastguard Worker public void run() { 557*795d594fSAndroid Build Coastguard Worker try { 558*795d594fSAndroid Build Coastguard Worker // Try to acquire one permit, and block until 559*795d594fSAndroid Build Coastguard Worker // that permit is released by the main thread. 560*795d594fSAndroid Build Coastguard Worker semaphore.acquire(); 561*795d594fSAndroid Build Coastguard Worker // When unblocked, release the acquired permit 562*795d594fSAndroid Build Coastguard Worker // immediately. 563*795d594fSAndroid Build Coastguard Worker semaphore.release(); 564*795d594fSAndroid Build Coastguard Worker } catch (InterruptedException ignored) { 565*795d594fSAndroid Build Coastguard Worker throw new RuntimeException("Test set up failed in auxiliary thread"); 566*795d594fSAndroid Build Coastguard Worker } 567*795d594fSAndroid Build Coastguard Worker } 568*795d594fSAndroid Build Coastguard Worker }; 569*795d594fSAndroid Build Coastguard Worker 570*795d594fSAndroid Build Coastguard Worker // Main thread. 571*795d594fSAndroid Build Coastguard Worker try { 572*795d594fSAndroid Build Coastguard Worker // Acquire all permits. 573*795d594fSAndroid Build Coastguard Worker semaphore.acquire(permits); 574*795d594fSAndroid Build Coastguard Worker // Start the auxiliary thread and have it try to acquire a 575*795d594fSAndroid Build Coastguard Worker // permit. 576*795d594fSAndroid Build Coastguard Worker auxThread.start(); 577*795d594fSAndroid Build Coastguard Worker // Synchronization: Wait until the auxiliary thread is 578*795d594fSAndroid Build Coastguard Worker // blocked trying to acquire a permit from `semaphore`. 579*795d594fSAndroid Build Coastguard Worker while (!semaphore.hasQueuedThreads()) { 580*795d594fSAndroid Build Coastguard Worker Thread.sleep(100); 581*795d594fSAndroid Build Coastguard Worker } 582*795d594fSAndroid Build Coastguard Worker // Release one permit, thus unblocking `auxThread` and let 583*795d594fSAndroid Build Coastguard Worker // it acquire a permit. 584*795d594fSAndroid Build Coastguard Worker semaphore.release(); 585*795d594fSAndroid Build Coastguard Worker // Synchronization: Wait for the auxiliary thread to die. 586*795d594fSAndroid Build Coastguard Worker auxThread.join(); 587*795d594fSAndroid Build Coastguard Worker // Release remaining permits. 588*795d594fSAndroid Build Coastguard Worker semaphore.release(permits - 1); 589*795d594fSAndroid Build Coastguard Worker 590*795d594fSAndroid Build Coastguard Worker // Verify that all permits have been released. 591*795d594fSAndroid Build Coastguard Worker assert semaphore.availablePermits() == permits; 592*795d594fSAndroid Build Coastguard Worker } catch (InterruptedException ignored) { 593*795d594fSAndroid Build Coastguard Worker throw new RuntimeException("Test set up failed in main thread"); 594*795d594fSAndroid Build Coastguard Worker } 595*795d594fSAndroid Build Coastguard Worker } 596*795d594fSAndroid Build Coastguard Worker runTest(final int numberOfThreads, final int numberOfDaemons, final int operationsPerThread, final Object lock, Map<Operation, Double> frequencyMap)597*795d594fSAndroid Build Coastguard Worker public static void runTest(final int numberOfThreads, final int numberOfDaemons, 598*795d594fSAndroid Build Coastguard Worker final int operationsPerThread, final Object lock, 599*795d594fSAndroid Build Coastguard Worker Map<Operation, Double> frequencyMap) throws Exception { 600*795d594fSAndroid Build Coastguard Worker final Thread mainThread = Thread.currentThread(); 601*795d594fSAndroid Build Coastguard Worker final Barrier startBarrier = new Barrier(numberOfThreads + numberOfDaemons + 1); 602*795d594fSAndroid Build Coastguard Worker 603*795d594fSAndroid Build Coastguard Worker // Each normal thread is going to do operationsPerThread 604*795d594fSAndroid Build Coastguard Worker // operations. Each daemon thread will loop over all 605*795d594fSAndroid Build Coastguard Worker // the operations and will not stop. 606*795d594fSAndroid Build Coastguard Worker // The distribution of operations is determined by 607*795d594fSAndroid Build Coastguard Worker // the frequencyMap values. We fill out an Operation[] 608*795d594fSAndroid Build Coastguard Worker // for each thread with the operations it is to perform. The 609*795d594fSAndroid Build Coastguard Worker // Operation[] is shuffled so that there is more random 610*795d594fSAndroid Build Coastguard Worker // interactions between the threads. 611*795d594fSAndroid Build Coastguard Worker 612*795d594fSAndroid Build Coastguard Worker // Fill in the Operation[] array for each thread by laying 613*795d594fSAndroid Build Coastguard Worker // down references to operation according to their desired 614*795d594fSAndroid Build Coastguard Worker // frequency. 615*795d594fSAndroid Build Coastguard Worker // The first numberOfThreads elements are normal threads, the last 616*795d594fSAndroid Build Coastguard Worker // numberOfDaemons elements are daemon threads. 617*795d594fSAndroid Build Coastguard Worker final Main[] threadStresses = new Main[numberOfThreads + numberOfDaemons]; 618*795d594fSAndroid Build Coastguard Worker for (int t = 0; t < threadStresses.length; t++) { 619*795d594fSAndroid Build Coastguard Worker Operation[] operations = new Operation[operationsPerThread]; 620*795d594fSAndroid Build Coastguard Worker int o = 0; 621*795d594fSAndroid Build Coastguard Worker LOOP: 622*795d594fSAndroid Build Coastguard Worker while (true) { 623*795d594fSAndroid Build Coastguard Worker for (Operation op : frequencyMap.keySet()) { 624*795d594fSAndroid Build Coastguard Worker int freq = (int)(frequencyMap.get(op) * operationsPerThread); 625*795d594fSAndroid Build Coastguard Worker for (int f = 0; f < freq; f++) { 626*795d594fSAndroid Build Coastguard Worker if (o == operations.length) { 627*795d594fSAndroid Build Coastguard Worker break LOOP; 628*795d594fSAndroid Build Coastguard Worker } 629*795d594fSAndroid Build Coastguard Worker operations[o] = op; 630*795d594fSAndroid Build Coastguard Worker o++; 631*795d594fSAndroid Build Coastguard Worker } 632*795d594fSAndroid Build Coastguard Worker } 633*795d594fSAndroid Build Coastguard Worker } 634*795d594fSAndroid Build Coastguard Worker // Randomize the operation order 635*795d594fSAndroid Build Coastguard Worker Collections.shuffle(Arrays.asList(operations)); 636*795d594fSAndroid Build Coastguard Worker threadStresses[t] = (t < numberOfThreads) 637*795d594fSAndroid Build Coastguard Worker ? new Main(lock, t, operations) 638*795d594fSAndroid Build Coastguard Worker : new Daemon(lock, t, operations, mainThread, startBarrier); 639*795d594fSAndroid Build Coastguard Worker } 640*795d594fSAndroid Build Coastguard Worker 641*795d594fSAndroid Build Coastguard Worker // Enable to dump operation counts per thread to see that it is 642*795d594fSAndroid Build Coastguard Worker // commensurate with the frequencyMap. 643*795d594fSAndroid Build Coastguard Worker if (DEBUG) { 644*795d594fSAndroid Build Coastguard Worker for (int t = 0; t < threadStresses.length; t++) { 645*795d594fSAndroid Build Coastguard Worker Operation[] operations = threadStresses[t].operations; 646*795d594fSAndroid Build Coastguard Worker Map<Operation, Integer> distribution = new HashMap<Operation, Integer>(); 647*795d594fSAndroid Build Coastguard Worker for (Operation operation : operations) { 648*795d594fSAndroid Build Coastguard Worker Integer ops = distribution.get(operation); 649*795d594fSAndroid Build Coastguard Worker if (ops == null) { 650*795d594fSAndroid Build Coastguard Worker ops = 1; 651*795d594fSAndroid Build Coastguard Worker } else { 652*795d594fSAndroid Build Coastguard Worker ops++; 653*795d594fSAndroid Build Coastguard Worker } 654*795d594fSAndroid Build Coastguard Worker distribution.put(operation, ops); 655*795d594fSAndroid Build Coastguard Worker } 656*795d594fSAndroid Build Coastguard Worker System.out.println("Distribution for " + t); 657*795d594fSAndroid Build Coastguard Worker for (Operation op : frequencyMap.keySet()) { 658*795d594fSAndroid Build Coastguard Worker System.out.println(op + " = " + distribution.get(op)); 659*795d594fSAndroid Build Coastguard Worker } 660*795d594fSAndroid Build Coastguard Worker } 661*795d594fSAndroid Build Coastguard Worker } 662*795d594fSAndroid Build Coastguard Worker 663*795d594fSAndroid Build Coastguard Worker // Create the runners for each thread. The runner Thread 664*795d594fSAndroid Build Coastguard Worker // ensures that thread that exit due to operation Exit will be 665*795d594fSAndroid Build Coastguard Worker // restarted until they reach their desired 666*795d594fSAndroid Build Coastguard Worker // operationsPerThread. 667*795d594fSAndroid Build Coastguard Worker Thread[] runners = new Thread[numberOfThreads]; 668*795d594fSAndroid Build Coastguard Worker for (int r = 0; r < runners.length; r++) { 669*795d594fSAndroid Build Coastguard Worker final Main ts = threadStresses[r]; 670*795d594fSAndroid Build Coastguard Worker runners[r] = new Thread("Runner thread " + r) { 671*795d594fSAndroid Build Coastguard Worker final Main threadStress = ts; 672*795d594fSAndroid Build Coastguard Worker public void run() { 673*795d594fSAndroid Build Coastguard Worker try { 674*795d594fSAndroid Build Coastguard Worker int id = threadStress.id; 675*795d594fSAndroid Build Coastguard Worker // No memory hungry task are running yet, so println() should succeed. 676*795d594fSAndroid Build Coastguard Worker System.out.println("Starting worker for " + id); 677*795d594fSAndroid Build Coastguard Worker // Wait until all runners and daemons reach the starting point. 678*795d594fSAndroid Build Coastguard Worker startBarrier.await(); 679*795d594fSAndroid Build Coastguard Worker // Run the stress tasks. 680*795d594fSAndroid Build Coastguard Worker while (threadStress.nextOperation < operationsPerThread) { 681*795d594fSAndroid Build Coastguard Worker try { 682*795d594fSAndroid Build Coastguard Worker Thread thread = new Thread(ts, "Worker thread " + id); 683*795d594fSAndroid Build Coastguard Worker thread.start(); 684*795d594fSAndroid Build Coastguard Worker thread.join(); 685*795d594fSAndroid Build Coastguard Worker 686*795d594fSAndroid Build Coastguard Worker if (DEBUG) { 687*795d594fSAndroid Build Coastguard Worker System.out.println( 688*795d594fSAndroid Build Coastguard Worker "Thread exited for " + id + " with " + 689*795d594fSAndroid Build Coastguard Worker (operationsPerThread - threadStress.nextOperation) + 690*795d594fSAndroid Build Coastguard Worker " operations remaining."); 691*795d594fSAndroid Build Coastguard Worker } 692*795d594fSAndroid Build Coastguard Worker } catch (OutOfMemoryError e) { 693*795d594fSAndroid Build Coastguard Worker // Ignore OOME since we need to print "Finishing worker" 694*795d594fSAndroid Build Coastguard Worker // for the test to pass. This OOM can come from creating 695*795d594fSAndroid Build Coastguard Worker // the Thread or from the DEBUG output. 696*795d594fSAndroid Build Coastguard Worker // Note that the Thread creation may fail repeatedly, 697*795d594fSAndroid Build Coastguard Worker // preventing the runner from making any progress, 698*795d594fSAndroid Build Coastguard Worker // especially if the number of daemons is too high. 699*795d594fSAndroid Build Coastguard Worker } 700*795d594fSAndroid Build Coastguard Worker } 701*795d594fSAndroid Build Coastguard Worker // Print "Finishing worker" through JNI to avoid OOME. 702*795d594fSAndroid Build Coastguard Worker Main.printString(Main.finishingWorkerMessage); 703*795d594fSAndroid Build Coastguard Worker } catch (Throwable t) { 704*795d594fSAndroid Build Coastguard Worker Main.printThrowable(t); 705*795d594fSAndroid Build Coastguard Worker // Interrupt the main thread, so that it can orderly shut down 706*795d594fSAndroid Build Coastguard Worker // instead of waiting indefinitely for some Barrier. 707*795d594fSAndroid Build Coastguard Worker mainThread.interrupt(); 708*795d594fSAndroid Build Coastguard Worker } 709*795d594fSAndroid Build Coastguard Worker } 710*795d594fSAndroid Build Coastguard Worker }; 711*795d594fSAndroid Build Coastguard Worker } 712*795d594fSAndroid Build Coastguard Worker 713*795d594fSAndroid Build Coastguard Worker // The notifier thread is a daemon just loops forever to wake 714*795d594fSAndroid Build Coastguard Worker // up threads in operations Wait and Park. 715*795d594fSAndroid Build Coastguard Worker if (lock != null) { 716*795d594fSAndroid Build Coastguard Worker Thread notifier = new Thread("Notifier") { 717*795d594fSAndroid Build Coastguard Worker public void run() { 718*795d594fSAndroid Build Coastguard Worker while (true) { 719*795d594fSAndroid Build Coastguard Worker synchronized (lock) { 720*795d594fSAndroid Build Coastguard Worker lock.notifyAll(); 721*795d594fSAndroid Build Coastguard Worker } 722*795d594fSAndroid Build Coastguard Worker for (Thread runner : runners) { 723*795d594fSAndroid Build Coastguard Worker if (runner != null) { 724*795d594fSAndroid Build Coastguard Worker LockSupport.unpark(runner); 725*795d594fSAndroid Build Coastguard Worker } 726*795d594fSAndroid Build Coastguard Worker } 727*795d594fSAndroid Build Coastguard Worker } 728*795d594fSAndroid Build Coastguard Worker } 729*795d594fSAndroid Build Coastguard Worker }; 730*795d594fSAndroid Build Coastguard Worker notifier.setDaemon(true); 731*795d594fSAndroid Build Coastguard Worker notifier.start(); 732*795d594fSAndroid Build Coastguard Worker } 733*795d594fSAndroid Build Coastguard Worker 734*795d594fSAndroid Build Coastguard Worker // Create and start the daemon threads. 735*795d594fSAndroid Build Coastguard Worker for (int r = 0; r < numberOfDaemons; r++) { 736*795d594fSAndroid Build Coastguard Worker Main daemon = threadStresses[numberOfThreads + r]; 737*795d594fSAndroid Build Coastguard Worker Thread t = new Thread(daemon, "Daemon thread " + daemon.id); 738*795d594fSAndroid Build Coastguard Worker t.setDaemon(true); 739*795d594fSAndroid Build Coastguard Worker t.start(); 740*795d594fSAndroid Build Coastguard Worker } 741*795d594fSAndroid Build Coastguard Worker 742*795d594fSAndroid Build Coastguard Worker for (int r = 0; r < runners.length; r++) { 743*795d594fSAndroid Build Coastguard Worker runners[r].start(); 744*795d594fSAndroid Build Coastguard Worker } 745*795d594fSAndroid Build Coastguard Worker // Wait for all threads to reach the starting point. 746*795d594fSAndroid Build Coastguard Worker startBarrier.await(); 747*795d594fSAndroid Build Coastguard Worker // Wait for runners to finish. 748*795d594fSAndroid Build Coastguard Worker for (int r = 0; r < runners.length; r++) { 749*795d594fSAndroid Build Coastguard Worker runners[r].join(); 750*795d594fSAndroid Build Coastguard Worker } 751*795d594fSAndroid Build Coastguard Worker } 752*795d594fSAndroid Build Coastguard Worker 753*795d594fSAndroid Build Coastguard Worker protected final Operation[] operations; 754*795d594fSAndroid Build Coastguard Worker private final Object lock; 755*795d594fSAndroid Build Coastguard Worker protected final int id; 756*795d594fSAndroid Build Coastguard Worker 757*795d594fSAndroid Build Coastguard Worker private int nextOperation; 758*795d594fSAndroid Build Coastguard Worker Main(Object lock, int id, Operation[] operations)759*795d594fSAndroid Build Coastguard Worker private Main(Object lock, int id, Operation[] operations) { 760*795d594fSAndroid Build Coastguard Worker this.lock = lock; 761*795d594fSAndroid Build Coastguard Worker this.id = id; 762*795d594fSAndroid Build Coastguard Worker this.operations = operations; 763*795d594fSAndroid Build Coastguard Worker } 764*795d594fSAndroid Build Coastguard Worker run()765*795d594fSAndroid Build Coastguard Worker public void run() { 766*795d594fSAndroid Build Coastguard Worker try { 767*795d594fSAndroid Build Coastguard Worker if (DEBUG) { 768*795d594fSAndroid Build Coastguard Worker System.out.println("Starting ThreadStress " + id); 769*795d594fSAndroid Build Coastguard Worker } 770*795d594fSAndroid Build Coastguard Worker while (nextOperation < operations.length) { 771*795d594fSAndroid Build Coastguard Worker Operation operation = operations[nextOperation]; 772*795d594fSAndroid Build Coastguard Worker if (DEBUG) { 773*795d594fSAndroid Build Coastguard Worker System.out.println("ThreadStress " + id 774*795d594fSAndroid Build Coastguard Worker + " operation " + nextOperation 775*795d594fSAndroid Build Coastguard Worker + " is " + operation); 776*795d594fSAndroid Build Coastguard Worker } 777*795d594fSAndroid Build Coastguard Worker nextOperation++; 778*795d594fSAndroid Build Coastguard Worker if (!operation.perform()) { 779*795d594fSAndroid Build Coastguard Worker return; 780*795d594fSAndroid Build Coastguard Worker } 781*795d594fSAndroid Build Coastguard Worker } 782*795d594fSAndroid Build Coastguard Worker } finally { 783*795d594fSAndroid Build Coastguard Worker if (DEBUG) { 784*795d594fSAndroid Build Coastguard Worker System.out.println("Finishing ThreadStress for " + id); 785*795d594fSAndroid Build Coastguard Worker } 786*795d594fSAndroid Build Coastguard Worker } 787*795d594fSAndroid Build Coastguard Worker } 788*795d594fSAndroid Build Coastguard Worker 789*795d594fSAndroid Build Coastguard Worker private static class Daemon extends Main { Daemon(Object lock, int id, Operation[] operations, Thread mainThread, Barrier startBarrier)790*795d594fSAndroid Build Coastguard Worker private Daemon(Object lock, 791*795d594fSAndroid Build Coastguard Worker int id, 792*795d594fSAndroid Build Coastguard Worker Operation[] operations, 793*795d594fSAndroid Build Coastguard Worker Thread mainThread, 794*795d594fSAndroid Build Coastguard Worker Barrier startBarrier) { 795*795d594fSAndroid Build Coastguard Worker super(lock, id, operations); 796*795d594fSAndroid Build Coastguard Worker this.mainThread = mainThread; 797*795d594fSAndroid Build Coastguard Worker this.startBarrier = startBarrier; 798*795d594fSAndroid Build Coastguard Worker } 799*795d594fSAndroid Build Coastguard Worker run()800*795d594fSAndroid Build Coastguard Worker public void run() { 801*795d594fSAndroid Build Coastguard Worker try { 802*795d594fSAndroid Build Coastguard Worker if (DEBUG) { 803*795d594fSAndroid Build Coastguard Worker System.out.println("Starting ThreadStress Daemon " + id); 804*795d594fSAndroid Build Coastguard Worker } 805*795d594fSAndroid Build Coastguard Worker startBarrier.await(); 806*795d594fSAndroid Build Coastguard Worker try { 807*795d594fSAndroid Build Coastguard Worker int i = 0; 808*795d594fSAndroid Build Coastguard Worker while (true) { 809*795d594fSAndroid Build Coastguard Worker Operation operation = operations[i]; 810*795d594fSAndroid Build Coastguard Worker if (DEBUG) { 811*795d594fSAndroid Build Coastguard Worker System.out.println("ThreadStress Daemon " + id 812*795d594fSAndroid Build Coastguard Worker + " operation " + i 813*795d594fSAndroid Build Coastguard Worker + " is " + operation); 814*795d594fSAndroid Build Coastguard Worker } 815*795d594fSAndroid Build Coastguard Worker // Ignore the result of the performed operation, making 816*795d594fSAndroid Build Coastguard Worker // Exit.perform() essentially a no-op for daemon threads. 817*795d594fSAndroid Build Coastguard Worker operation.perform(); 818*795d594fSAndroid Build Coastguard Worker i = (i + 1) % operations.length; 819*795d594fSAndroid Build Coastguard Worker } 820*795d594fSAndroid Build Coastguard Worker } catch (OutOfMemoryError e) { 821*795d594fSAndroid Build Coastguard Worker // Catch OutOfMemoryErrors since these can cause the test to fail it they print 822*795d594fSAndroid Build Coastguard Worker // the stack trace after "Finishing worker". Note that operations should catch 823*795d594fSAndroid Build Coastguard Worker // their own OOME, this guards only agains OOME in the DEBUG output. 824*795d594fSAndroid Build Coastguard Worker } 825*795d594fSAndroid Build Coastguard Worker if (DEBUG) { 826*795d594fSAndroid Build Coastguard Worker System.out.println("Finishing ThreadStress Daemon for " + id); 827*795d594fSAndroid Build Coastguard Worker } 828*795d594fSAndroid Build Coastguard Worker } catch (Throwable t) { 829*795d594fSAndroid Build Coastguard Worker Main.printThrowable(t); 830*795d594fSAndroid Build Coastguard Worker // Interrupt the main thread, so that it can orderly shut down 831*795d594fSAndroid Build Coastguard Worker // instead of waiting indefinitely for some Barrier. 832*795d594fSAndroid Build Coastguard Worker mainThread.interrupt(); 833*795d594fSAndroid Build Coastguard Worker } 834*795d594fSAndroid Build Coastguard Worker } 835*795d594fSAndroid Build Coastguard Worker 836*795d594fSAndroid Build Coastguard Worker final Thread mainThread; 837*795d594fSAndroid Build Coastguard Worker final Barrier startBarrier; 838*795d594fSAndroid Build Coastguard Worker } 839*795d594fSAndroid Build Coastguard Worker 840*795d594fSAndroid Build Coastguard Worker // Note: java.util.concurrent.CyclicBarrier.await() allocates memory and may throw OOM. 841*795d594fSAndroid Build Coastguard Worker // That is highly undesirable in this test, so we use our own simple barrier class. 842*795d594fSAndroid Build Coastguard Worker // The only memory allocation that can happen here is the lock inflation which uses 843*795d594fSAndroid Build Coastguard Worker // a native allocation. As such, it should succeed even if the Java heap is full. 844*795d594fSAndroid Build Coastguard Worker // If the native allocation surprisingly fails, the program shall abort(). 845*795d594fSAndroid Build Coastguard Worker private static class Barrier { Barrier(int initialCount)846*795d594fSAndroid Build Coastguard Worker public Barrier(int initialCount) { 847*795d594fSAndroid Build Coastguard Worker count = initialCount; 848*795d594fSAndroid Build Coastguard Worker } 849*795d594fSAndroid Build Coastguard Worker await()850*795d594fSAndroid Build Coastguard Worker public synchronized void await() throws InterruptedException { 851*795d594fSAndroid Build Coastguard Worker --count; 852*795d594fSAndroid Build Coastguard Worker if (count != 0) { 853*795d594fSAndroid Build Coastguard Worker do { 854*795d594fSAndroid Build Coastguard Worker wait(); 855*795d594fSAndroid Build Coastguard Worker } while (count != 0); // Check for spurious wakeup. 856*795d594fSAndroid Build Coastguard Worker } else { 857*795d594fSAndroid Build Coastguard Worker notifyAll(); 858*795d594fSAndroid Build Coastguard Worker } 859*795d594fSAndroid Build Coastguard Worker } 860*795d594fSAndroid Build Coastguard Worker 861*795d594fSAndroid Build Coastguard Worker private int count; 862*795d594fSAndroid Build Coastguard Worker } 863*795d594fSAndroid Build Coastguard Worker 864*795d594fSAndroid Build Coastguard Worker // Printing a String/Throwable through JNI requires only native memory and space 865*795d594fSAndroid Build Coastguard Worker // in the local reference table, so it should succeed even if the Java heap is full. printString(String s)866*795d594fSAndroid Build Coastguard Worker private static native void printString(String s); printThrowable(Throwable t)867*795d594fSAndroid Build Coastguard Worker private static native void printThrowable(Throwable t); 868*795d594fSAndroid Build Coastguard Worker 869*795d594fSAndroid Build Coastguard Worker static final String finishingWorkerMessage; 870*795d594fSAndroid Build Coastguard Worker static final String errnoExceptionName; 871*795d594fSAndroid Build Coastguard Worker static { 872*795d594fSAndroid Build Coastguard Worker // We pre-allocate the strings in class initializer to avoid const-string 873*795d594fSAndroid Build Coastguard Worker // instructions in code using these strings later as they may throw OOME. 874*795d594fSAndroid Build Coastguard Worker finishingWorkerMessage = "Finishing worker\n"; 875*795d594fSAndroid Build Coastguard Worker errnoExceptionName = "ErrnoException"; 876*795d594fSAndroid Build Coastguard Worker } 877*795d594fSAndroid Build Coastguard Worker } 878