xref: /aosp_15_r20/art/test/114-ParallelGC/src/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 java.util.ArrayList;
18*795d594fSAndroid Build Coastguard Worker import java.util.List;
19*795d594fSAndroid Build Coastguard Worker import java.util.concurrent.atomic.AtomicInteger;
20*795d594fSAndroid Build Coastguard Worker import java.util.concurrent.CyclicBarrier;
21*795d594fSAndroid Build Coastguard Worker 
22*795d594fSAndroid Build Coastguard Worker public class Main implements Runnable {
23*795d594fSAndroid Build Coastguard Worker 
24*795d594fSAndroid Build Coastguard Worker     // Timeout in minutes. Make it larger than the run-test timeout to get a native thread dump by
25*795d594fSAndroid Build Coastguard Worker     // ART on timeout when running on the host.
26*795d594fSAndroid Build Coastguard Worker     private final static long TIMEOUT_VALUE = 7;
27*795d594fSAndroid Build Coastguard Worker 
28*795d594fSAndroid Build Coastguard Worker     private final static long MAX_SIZE = 1000;  // Maximum size of array-list to allocate.
29*795d594fSAndroid Build Coastguard Worker 
30*795d594fSAndroid Build Coastguard Worker     private final static int THREAD_COUNT = 16;
31*795d594fSAndroid Build Coastguard Worker 
32*795d594fSAndroid Build Coastguard Worker     // Use a couple of different forms of synchronizing to test some of these...
33*795d594fSAndroid Build Coastguard Worker     private final static AtomicInteger counter = new AtomicInteger(-1);
34*795d594fSAndroid Build Coastguard Worker     private final static Object gate = new Object();
35*795d594fSAndroid Build Coastguard Worker     private volatile static int waitCount = 0;
36*795d594fSAndroid Build Coastguard Worker 
37*795d594fSAndroid Build Coastguard Worker     static {
38*795d594fSAndroid Build Coastguard Worker         // If we're using the interpreter for the boot class path, the VarHandle implementation of
39*795d594fSAndroid Build Coastguard Worker         // AtomicInteger.incrementAndGet() needs to resolve a MethodType which is then cached for
40*795d594fSAndroid Build Coastguard Worker         // subsequent uses. Make sure the MethodType is resolved early, otherwise the
41*795d594fSAndroid Build Coastguard Worker         // counter.incrementAndGet() call in work(), after we have tried to allocate all memory,
42*795d594fSAndroid Build Coastguard Worker         // could throw OOME.
counter.incrementAndGet()43*795d594fSAndroid Build Coastguard Worker         counter.incrementAndGet();
44*795d594fSAndroid Build Coastguard Worker     }
45*795d594fSAndroid Build Coastguard Worker 
main(String[] args)46*795d594fSAndroid Build Coastguard Worker     public static void main(String[] args) throws Exception {
47*795d594fSAndroid Build Coastguard Worker         Thread[] threads = new Thread[THREAD_COUNT];
48*795d594fSAndroid Build Coastguard Worker 
49*795d594fSAndroid Build Coastguard Worker         // This barrier is used to synchronize the threads starting to allocate.
50*795d594fSAndroid Build Coastguard Worker         // Note: Even though a barrier is not allocation-free, this one is fine, as it will be used
51*795d594fSAndroid Build Coastguard Worker         //       before filling the heap.
52*795d594fSAndroid Build Coastguard Worker         CyclicBarrier startBarrier = new CyclicBarrier(threads.length);
53*795d594fSAndroid Build Coastguard Worker 
54*795d594fSAndroid Build Coastguard Worker         for (int i = 0; i < threads.length; i++) {
55*795d594fSAndroid Build Coastguard Worker             threads[i] = new Thread(new Main(startBarrier));
56*795d594fSAndroid Build Coastguard Worker             threads[i].start();
57*795d594fSAndroid Build Coastguard Worker         }
58*795d594fSAndroid Build Coastguard Worker 
59*795d594fSAndroid Build Coastguard Worker         // Wait for the threads to finish.
60*795d594fSAndroid Build Coastguard Worker         for (Thread thread : threads) {
61*795d594fSAndroid Build Coastguard Worker             thread.join();
62*795d594fSAndroid Build Coastguard Worker         }
63*795d594fSAndroid Build Coastguard Worker 
64*795d594fSAndroid Build Coastguard Worker         // Allocate objects to definitely run GC before quitting.
65*795d594fSAndroid Build Coastguard Worker         allocateObjectsToRunGc();
66*795d594fSAndroid Build Coastguard Worker 
67*795d594fSAndroid Build Coastguard Worker         new ArrayList<Object>(50);
68*795d594fSAndroid Build Coastguard Worker     }
69*795d594fSAndroid Build Coastguard Worker 
allocateObjectsToRunGc()70*795d594fSAndroid Build Coastguard Worker     private static void allocateObjectsToRunGc() {
71*795d594fSAndroid Build Coastguard Worker       ArrayList<Object> l = new ArrayList<Object>();
72*795d594fSAndroid Build Coastguard Worker       try {
73*795d594fSAndroid Build Coastguard Worker           for (int i = 0; i < 100000; i++) {
74*795d594fSAndroid Build Coastguard Worker               l.add(new ArrayList<Object>(i));
75*795d594fSAndroid Build Coastguard Worker           }
76*795d594fSAndroid Build Coastguard Worker       } catch (OutOfMemoryError oom) {
77*795d594fSAndroid Build Coastguard Worker       }
78*795d594fSAndroid Build Coastguard Worker     }
79*795d594fSAndroid Build Coastguard Worker 
Main(CyclicBarrier startBarrier)80*795d594fSAndroid Build Coastguard Worker     private Main(CyclicBarrier startBarrier) {
81*795d594fSAndroid Build Coastguard Worker         this.startBarrier = startBarrier;
82*795d594fSAndroid Build Coastguard Worker     }
83*795d594fSAndroid Build Coastguard Worker 
84*795d594fSAndroid Build Coastguard Worker     private ArrayList<Object> store;
85*795d594fSAndroid Build Coastguard Worker     private CyclicBarrier startBarrier;
86*795d594fSAndroid Build Coastguard Worker 
run()87*795d594fSAndroid Build Coastguard Worker     public void run() {
88*795d594fSAndroid Build Coastguard Worker         try {
89*795d594fSAndroid Build Coastguard Worker             work();
90*795d594fSAndroid Build Coastguard Worker         } catch (Throwable t) {
91*795d594fSAndroid Build Coastguard Worker             // Any exception or error getting here is bad.
92*795d594fSAndroid Build Coastguard Worker             try {
93*795d594fSAndroid Build Coastguard Worker                 // May need allocations...
94*795d594fSAndroid Build Coastguard Worker                 t.printStackTrace(System.out);
95*795d594fSAndroid Build Coastguard Worker             } catch (Throwable tInner) {
96*795d594fSAndroid Build Coastguard Worker             }
97*795d594fSAndroid Build Coastguard Worker             System.exit(1);
98*795d594fSAndroid Build Coastguard Worker         }
99*795d594fSAndroid Build Coastguard Worker     }
100*795d594fSAndroid Build Coastguard Worker 
work()101*795d594fSAndroid Build Coastguard Worker     private void work() throws Exception {
102*795d594fSAndroid Build Coastguard Worker         // Any exceptions except an OOME in the allocation loop are bad and handed off to the
103*795d594fSAndroid Build Coastguard Worker         // caller which should abort the whole runtime.
104*795d594fSAndroid Build Coastguard Worker 
105*795d594fSAndroid Build Coastguard Worker         ArrayList<Object> l = new ArrayList<Object>();
106*795d594fSAndroid Build Coastguard Worker         store = l;  // Keep it alive.
107*795d594fSAndroid Build Coastguard Worker 
108*795d594fSAndroid Build Coastguard Worker         // Wait for the start signal.
109*795d594fSAndroid Build Coastguard Worker         startBarrier.await(TIMEOUT_VALUE, java.util.concurrent.TimeUnit.MINUTES);
110*795d594fSAndroid Build Coastguard Worker 
111*795d594fSAndroid Build Coastguard Worker         // Allocate.
112*795d594fSAndroid Build Coastguard Worker         try {
113*795d594fSAndroid Build Coastguard Worker             for (int i = 0; i < MAX_SIZE; i++) {
114*795d594fSAndroid Build Coastguard Worker                 l.add(new ArrayList<Object>(i));
115*795d594fSAndroid Build Coastguard Worker             }
116*795d594fSAndroid Build Coastguard Worker         } catch (OutOfMemoryError oome) {
117*795d594fSAndroid Build Coastguard Worker             // Fine, we're done.
118*795d594fSAndroid Build Coastguard Worker         }
119*795d594fSAndroid Build Coastguard Worker 
120*795d594fSAndroid Build Coastguard Worker         // Atomically increment the counter and check whether we were last.
121*795d594fSAndroid Build Coastguard Worker         int number = counter.incrementAndGet();
122*795d594fSAndroid Build Coastguard Worker 
123*795d594fSAndroid Build Coastguard Worker         if (number < THREAD_COUNT) {
124*795d594fSAndroid Build Coastguard Worker             // Not last.
125*795d594fSAndroid Build Coastguard Worker             synchronized (gate) {
126*795d594fSAndroid Build Coastguard Worker                 // Increment the wait counter.
127*795d594fSAndroid Build Coastguard Worker                 waitCount++;
128*795d594fSAndroid Build Coastguard Worker                 gate.wait(TIMEOUT_VALUE * 1000 * 60);
129*795d594fSAndroid Build Coastguard Worker             }
130*795d594fSAndroid Build Coastguard Worker         } else {
131*795d594fSAndroid Build Coastguard Worker             // Last. Wait until waitCount == THREAD_COUNT - 1.
132*795d594fSAndroid Build Coastguard Worker             for (int loops = 0; ; loops++) {
133*795d594fSAndroid Build Coastguard Worker                 synchronized (gate) {
134*795d594fSAndroid Build Coastguard Worker                     if (waitCount == THREAD_COUNT - 1) {
135*795d594fSAndroid Build Coastguard Worker                         // OK, everyone's waiting. Notify and break out.
136*795d594fSAndroid Build Coastguard Worker                         gate.notifyAll();
137*795d594fSAndroid Build Coastguard Worker                         break;
138*795d594fSAndroid Build Coastguard Worker                     } else if (loops > 40) {
139*795d594fSAndroid Build Coastguard Worker                         // 1s wait, too many tries.
140*795d594fSAndroid Build Coastguard Worker                         System.out.println("Waited too long for the last thread.");
141*795d594fSAndroid Build Coastguard Worker                         System.exit(1);
142*795d594fSAndroid Build Coastguard Worker                     }
143*795d594fSAndroid Build Coastguard Worker                 }
144*795d594fSAndroid Build Coastguard Worker                 // Wait a bit.
145*795d594fSAndroid Build Coastguard Worker                 Thread.sleep(25);
146*795d594fSAndroid Build Coastguard Worker             }
147*795d594fSAndroid Build Coastguard Worker         }
148*795d594fSAndroid Build Coastguard Worker 
149*795d594fSAndroid Build Coastguard Worker         store = null;  // Allow GC to reclaim it.
150*795d594fSAndroid Build Coastguard Worker     }
151*795d594fSAndroid Build Coastguard Worker }
152