xref: /aosp_15_r20/art/test/004-ThreadStress/src-art/Main.java (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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