1556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom/*
2556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom * Copyright (C) 2011 The Android Open Source Project
3556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom *
4556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom * Licensed under the Apache License, Version 2.0 (the "License");
5556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom * you may not use this file except in compliance with the License.
6556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom * You may obtain a copy of the License at
7556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom *
8556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom *      http://www.apache.org/licenses/LICENSE-2.0
9556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom *
10556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom * Unless required by applicable law or agreed to in writing, software
11556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom * distributed under the License is distributed on an "AS IS" BASIS,
12556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom * See the License for the specific language governing permissions and
14556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom * limitations under the License.
15556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom */
16556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom
17556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstromimport java.util.ArrayList;
18556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstromimport java.util.List;
196c957c521929ea66d098736995e27aae18be9e68Andreas Gampeimport java.util.concurrent.atomic.AtomicInteger;
2093f3da1578bf25d3bc8cf1d121477bf29b4d760aAndreas Gampeimport java.util.concurrent.CyclicBarrier;
21556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom
221c83cbc4a817acbd7f9abb5b29a2d418a958e6a1Andreas Gampepublic class Main implements Runnable {
2393f3da1578bf25d3bc8cf1d121477bf29b4d760aAndreas Gampe
24ee576fa06302dca086a69d777d1f4a914bbd921dAndreas Gampe    // Timeout in minutes. Make it larger than the run-test timeout to get a native thread dump by
25ee576fa06302dca086a69d777d1f4a914bbd921dAndreas Gampe    // ART on timeout when running on the host.
266c957c521929ea66d098736995e27aae18be9e68Andreas Gampe    private final static long TIMEOUT_VALUE = 7;
27ee576fa06302dca086a69d777d1f4a914bbd921dAndreas Gampe
286c957c521929ea66d098736995e27aae18be9e68Andreas Gampe    private final static long MAX_SIZE = 1000;  // Maximum size of array-list to allocate.
296c957c521929ea66d098736995e27aae18be9e68Andreas Gampe
306c957c521929ea66d098736995e27aae18be9e68Andreas Gampe    private final static int THREAD_COUNT = 16;
316c957c521929ea66d098736995e27aae18be9e68Andreas Gampe
326c957c521929ea66d098736995e27aae18be9e68Andreas Gampe    // Use a couple of different forms of synchronizing to test some of these...
336c957c521929ea66d098736995e27aae18be9e68Andreas Gampe    private final static AtomicInteger counter = new AtomicInteger();
346c957c521929ea66d098736995e27aae18be9e68Andreas Gampe    private final static Object gate = new Object();
356c957c521929ea66d098736995e27aae18be9e68Andreas Gampe    private volatile static int waitCount = 0;
3693f3da1578bf25d3bc8cf1d121477bf29b4d760aAndreas Gampe
37556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom    public static void main(String[] args) throws Exception {
386c957c521929ea66d098736995e27aae18be9e68Andreas Gampe        Thread[] threads = new Thread[THREAD_COUNT];
396c957c521929ea66d098736995e27aae18be9e68Andreas Gampe
406c957c521929ea66d098736995e27aae18be9e68Andreas Gampe        // This barrier is used to synchronize the threads starting to allocate.
416c957c521929ea66d098736995e27aae18be9e68Andreas Gampe        // Note: Even though a barrier is not allocation-free, this one is fine, as it will be used
426c957c521929ea66d098736995e27aae18be9e68Andreas Gampe        //       before filling the heap.
436c957c521929ea66d098736995e27aae18be9e68Andreas Gampe        CyclicBarrier startBarrier = new CyclicBarrier(threads.length);
4493f3da1578bf25d3bc8cf1d121477bf29b4d760aAndreas Gampe
45556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom        for (int i = 0; i < threads.length; i++) {
466c957c521929ea66d098736995e27aae18be9e68Andreas Gampe            threads[i] = new Thread(new Main(startBarrier));
476c957c521929ea66d098736995e27aae18be9e68Andreas Gampe            threads[i].start();
48556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom        }
4993f3da1578bf25d3bc8cf1d121477bf29b4d760aAndreas Gampe
5093f3da1578bf25d3bc8cf1d121477bf29b4d760aAndreas Gampe        // Wait for the threads to finish.
51556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom        for (Thread thread : threads) {
52556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom            thread.join();
53556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom        }
5493f3da1578bf25d3bc8cf1d121477bf29b4d760aAndreas Gampe
5593f3da1578bf25d3bc8cf1d121477bf29b4d760aAndreas Gampe        // Allocate objects to definitely run GC before quitting.
5619ac0276208f0afef6ba8a4ab34b74a59b8d11d7Sebastien Hertz        allocateObjectsToRunGc();
5719ac0276208f0afef6ba8a4ab34b74a59b8d11d7Sebastien Hertz
586c957c521929ea66d098736995e27aae18be9e68Andreas Gampe        new ArrayList<Object>(50);
5993f3da1578bf25d3bc8cf1d121477bf29b4d760aAndreas Gampe    }
6093f3da1578bf25d3bc8cf1d121477bf29b4d760aAndreas Gampe
6119ac0276208f0afef6ba8a4ab34b74a59b8d11d7Sebastien Hertz    private static void allocateObjectsToRunGc() {
6219ac0276208f0afef6ba8a4ab34b74a59b8d11d7Sebastien Hertz      ArrayList<Object> l = new ArrayList<Object>();
6319ac0276208f0afef6ba8a4ab34b74a59b8d11d7Sebastien Hertz      try {
6419ac0276208f0afef6ba8a4ab34b74a59b8d11d7Sebastien Hertz          for (int i = 0; i < 100000; i++) {
6519ac0276208f0afef6ba8a4ab34b74a59b8d11d7Sebastien Hertz              l.add(new ArrayList<Object>(i));
6619ac0276208f0afef6ba8a4ab34b74a59b8d11d7Sebastien Hertz          }
6719ac0276208f0afef6ba8a4ab34b74a59b8d11d7Sebastien Hertz      } catch (OutOfMemoryError oom) {
6819ac0276208f0afef6ba8a4ab34b74a59b8d11d7Sebastien Hertz      }
6919ac0276208f0afef6ba8a4ab34b74a59b8d11d7Sebastien Hertz    }
7019ac0276208f0afef6ba8a4ab34b74a59b8d11d7Sebastien Hertz
716c957c521929ea66d098736995e27aae18be9e68Andreas Gampe    private Main(CyclicBarrier startBarrier) {
726c957c521929ea66d098736995e27aae18be9e68Andreas Gampe        this.startBarrier = startBarrier;
73556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom    }
74556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom
756c957c521929ea66d098736995e27aae18be9e68Andreas Gampe    private ArrayList<Object> store;
766c957c521929ea66d098736995e27aae18be9e68Andreas Gampe    private CyclicBarrier startBarrier;
77556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom
78556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom    public void run() {
7993f3da1578bf25d3bc8cf1d121477bf29b4d760aAndreas Gampe        try {
8093f3da1578bf25d3bc8cf1d121477bf29b4d760aAndreas Gampe            work();
816c957c521929ea66d098736995e27aae18be9e68Andreas Gampe        } catch (Throwable t) {
826c957c521929ea66d098736995e27aae18be9e68Andreas Gampe            // Any exception or error getting here is bad.
836c957c521929ea66d098736995e27aae18be9e68Andreas Gampe            try {
846c957c521929ea66d098736995e27aae18be9e68Andreas Gampe                // May need allocations...
856c957c521929ea66d098736995e27aae18be9e68Andreas Gampe                t.printStackTrace(System.err);
866c957c521929ea66d098736995e27aae18be9e68Andreas Gampe            } catch (Throwable tInner) {
876c957c521929ea66d098736995e27aae18be9e68Andreas Gampe            }
8893f3da1578bf25d3bc8cf1d121477bf29b4d760aAndreas Gampe            System.exit(1);
89556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom        }
90556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom    }
9121b4bf89b4454d2af88762200e5d8b42e0d36cf4Andreas Gampe
926c957c521929ea66d098736995e27aae18be9e68Andreas Gampe    private void work() throws Exception {
936c957c521929ea66d098736995e27aae18be9e68Andreas Gampe        // Any exceptions except an OOME in the allocation loop are bad and handed off to the
946c957c521929ea66d098736995e27aae18be9e68Andreas Gampe        // caller which should abort the whole runtime.
956c957c521929ea66d098736995e27aae18be9e68Andreas Gampe
9693f3da1578bf25d3bc8cf1d121477bf29b4d760aAndreas Gampe        ArrayList<Object> l = new ArrayList<Object>();
976c957c521929ea66d098736995e27aae18be9e68Andreas Gampe        store = l;  // Keep it alive.
9893f3da1578bf25d3bc8cf1d121477bf29b4d760aAndreas Gampe
996c957c521929ea66d098736995e27aae18be9e68Andreas Gampe        // Wait for the start signal.
1006c957c521929ea66d098736995e27aae18be9e68Andreas Gampe        startBarrier.await(TIMEOUT_VALUE, java.util.concurrent.TimeUnit.MINUTES);
10193f3da1578bf25d3bc8cf1d121477bf29b4d760aAndreas Gampe
1026c957c521929ea66d098736995e27aae18be9e68Andreas Gampe        // Allocate.
1036c957c521929ea66d098736995e27aae18be9e68Andreas Gampe        try {
1046c957c521929ea66d098736995e27aae18be9e68Andreas Gampe            for (int i = 0; i < MAX_SIZE; i++) {
1056c957c521929ea66d098736995e27aae18be9e68Andreas Gampe                l.add(new ArrayList<Object>(i));
1066c957c521929ea66d098736995e27aae18be9e68Andreas Gampe            }
1076c957c521929ea66d098736995e27aae18be9e68Andreas Gampe        } catch (OutOfMemoryError oome) {
1086c957c521929ea66d098736995e27aae18be9e68Andreas Gampe            // Fine, we're done.
10993f3da1578bf25d3bc8cf1d121477bf29b4d760aAndreas Gampe        }
11093f3da1578bf25d3bc8cf1d121477bf29b4d760aAndreas Gampe
1116c957c521929ea66d098736995e27aae18be9e68Andreas Gampe        // Atomically increment the counter and check whether we were last.
1126c957c521929ea66d098736995e27aae18be9e68Andreas Gampe        int number = counter.incrementAndGet();
1136c957c521929ea66d098736995e27aae18be9e68Andreas Gampe
1146c957c521929ea66d098736995e27aae18be9e68Andreas Gampe        if (number < THREAD_COUNT) {
1156c957c521929ea66d098736995e27aae18be9e68Andreas Gampe            // Not last.
1166c957c521929ea66d098736995e27aae18be9e68Andreas Gampe            synchronized (gate) {
1176c957c521929ea66d098736995e27aae18be9e68Andreas Gampe                // Increment the wait counter.
1186c957c521929ea66d098736995e27aae18be9e68Andreas Gampe                waitCount++;
1196c957c521929ea66d098736995e27aae18be9e68Andreas Gampe                gate.wait(TIMEOUT_VALUE * 1000 * 60);
1206c957c521929ea66d098736995e27aae18be9e68Andreas Gampe            }
1216c957c521929ea66d098736995e27aae18be9e68Andreas Gampe        } else {
1226c957c521929ea66d098736995e27aae18be9e68Andreas Gampe            // Last. Wait until waitCount == THREAD_COUNT - 1.
1236c957c521929ea66d098736995e27aae18be9e68Andreas Gampe            for (int loops = 0; ; loops++) {
1246c957c521929ea66d098736995e27aae18be9e68Andreas Gampe                synchronized (gate) {
1256c957c521929ea66d098736995e27aae18be9e68Andreas Gampe                    if (waitCount == THREAD_COUNT - 1) {
1266c957c521929ea66d098736995e27aae18be9e68Andreas Gampe                        // OK, everyone's waiting. Notify and break out.
1276c957c521929ea66d098736995e27aae18be9e68Andreas Gampe                        gate.notifyAll();
1286c957c521929ea66d098736995e27aae18be9e68Andreas Gampe                        break;
1296c957c521929ea66d098736995e27aae18be9e68Andreas Gampe                    } else if (loops > 40) {
1306c957c521929ea66d098736995e27aae18be9e68Andreas Gampe                        // 1s wait, too many tries.
1316c957c521929ea66d098736995e27aae18be9e68Andreas Gampe                        System.out.println("Waited too long for the last thread.");
1326c957c521929ea66d098736995e27aae18be9e68Andreas Gampe                        System.exit(1);
1336c957c521929ea66d098736995e27aae18be9e68Andreas Gampe                    }
1346c957c521929ea66d098736995e27aae18be9e68Andreas Gampe                }
1356c957c521929ea66d098736995e27aae18be9e68Andreas Gampe                // Wait a bit.
1366c957c521929ea66d098736995e27aae18be9e68Andreas Gampe                Thread.sleep(25);
1376c957c521929ea66d098736995e27aae18be9e68Andreas Gampe            }
1386c957c521929ea66d098736995e27aae18be9e68Andreas Gampe        }
13993f3da1578bf25d3bc8cf1d121477bf29b4d760aAndreas Gampe
1406c957c521929ea66d098736995e27aae18be9e68Andreas Gampe        store = null;  // Allow GC to reclaim it.
14193f3da1578bf25d3bc8cf1d121477bf29b4d760aAndreas Gampe    }
142556217477768af1b2abf6768f007c09f226bbe7eBrian Carlstrom}
143