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