Brian Carlstrom | 5562174 | 2011-10-17 00:41:56 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2011 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | import java.util.ArrayList; |
| 18 | import java.util.List; |
Andreas Gampe | 93f3da1 | 2014-07-26 01:13:13 -0700 | [diff] [blame] | 19 | import java.util.concurrent.BrokenBarrierException; |
| 20 | import java.util.concurrent.CyclicBarrier; |
| 21 | import java.util.concurrent.SynchronousQueue; |
| 22 | import java.util.concurrent.TimeUnit; |
| 23 | import java.util.concurrent.TimeoutException; |
Brian Carlstrom | 5562174 | 2011-10-17 00:41:56 -0700 | [diff] [blame] | 24 | |
Andreas Gampe | 1c83cbc | 2014-07-22 18:52:29 -0700 | [diff] [blame] | 25 | public class Main implements Runnable { |
Andreas Gampe | 93f3da1 | 2014-07-26 01:13:13 -0700 | [diff] [blame] | 26 | |
Andreas Gampe | ee576fa | 2015-01-15 08:02:22 -0800 | [diff] [blame] | 27 | // Timeout in minutes. Make it larger than the run-test timeout to get a native thread dump by |
| 28 | // ART on timeout when running on the host. |
Mathieu Chartier | 8dcde23 | 2015-01-15 17:23:16 -0800 | [diff] [blame] | 29 | public final static long TIMEOUT_VALUE = 12; |
Andreas Gampe | ee576fa | 2015-01-15 08:02:22 -0800 | [diff] [blame] | 30 | |
Andreas Gampe | 93f3da1 | 2014-07-26 01:13:13 -0700 | [diff] [blame] | 31 | public final static long MAX_SIZE = 1000; // Maximum size of array-list to allocate. |
| 32 | |
Brian Carlstrom | 5562174 | 2011-10-17 00:41:56 -0700 | [diff] [blame] | 33 | public static void main(String[] args) throws Exception { |
| 34 | Thread[] threads = new Thread[16]; |
Andreas Gampe | 93f3da1 | 2014-07-26 01:13:13 -0700 | [diff] [blame] | 35 | |
| 36 | // Use a cyclic system of synchronous queues to pass a boolean token around. |
| 37 | // |
| 38 | // The combinations are: |
| 39 | // |
| 40 | // Worker receives: true false false true |
| 41 | // Worker has OOM: false false true true |
| 42 | // | |
| 43 | // v |
| 44 | // Value to pass: true false false false |
| 45 | // Exit out of loop: false true true true |
| 46 | // Wait on in queue: true false false true |
| 47 | // |
| 48 | // Finally, the workers are supposed to wait on the barrier to synchronize the GC run. |
| 49 | |
| 50 | CyclicBarrier barrier = new CyclicBarrier(threads.length); |
| 51 | List<SynchronousQueue<Boolean>> queues = new ArrayList<SynchronousQueue<Boolean>>( |
| 52 | threads.length); |
Brian Carlstrom | 5562174 | 2011-10-17 00:41:56 -0700 | [diff] [blame] | 53 | for (int i = 0; i < threads.length; i++) { |
Andreas Gampe | 93f3da1 | 2014-07-26 01:13:13 -0700 | [diff] [blame] | 54 | queues.add(new SynchronousQueue<Boolean>()); |
| 55 | } |
| 56 | |
| 57 | for (int i = 0; i < threads.length; i++) { |
| 58 | threads[i] = new Thread(new Main(i, queues.get(i), queues.get((i + 1) % threads.length), |
| 59 | barrier)); |
Brian Carlstrom | 5562174 | 2011-10-17 00:41:56 -0700 | [diff] [blame] | 60 | } |
| 61 | for (Thread thread : threads) { |
| 62 | thread.start(); |
| 63 | } |
Andreas Gampe | 93f3da1 | 2014-07-26 01:13:13 -0700 | [diff] [blame] | 64 | |
| 65 | // Push off the cycle. |
| 66 | checkTimeout(queues.get(0).offer(Boolean.TRUE, TIMEOUT_VALUE, TimeUnit.MINUTES)); |
| 67 | |
| 68 | // Wait for the threads to finish. |
Brian Carlstrom | 5562174 | 2011-10-17 00:41:56 -0700 | [diff] [blame] | 69 | for (Thread thread : threads) { |
| 70 | thread.join(); |
| 71 | } |
Andreas Gampe | 93f3da1 | 2014-07-26 01:13:13 -0700 | [diff] [blame] | 72 | |
| 73 | // Allocate objects to definitely run GC before quitting. |
| 74 | try { |
| 75 | for (int i = 0; i < 1000; i++) { |
| 76 | new ArrayList<Object>(i); |
| 77 | } |
| 78 | } catch (OutOfMemoryError oom) { |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | private static void checkTimeout(Object o) { |
| 83 | checkTimeout(o != null); |
| 84 | } |
| 85 | |
| 86 | private static void checkTimeout(boolean b) { |
| 87 | if (!b) { |
| 88 | // Something went wrong. |
| 89 | System.out.println("Bad things happened, timeout."); |
| 90 | System.exit(1); |
| 91 | } |
Brian Carlstrom | 5562174 | 2011-10-17 00:41:56 -0700 | [diff] [blame] | 92 | } |
| 93 | |
| 94 | private final int id; |
Andreas Gampe | 93f3da1 | 2014-07-26 01:13:13 -0700 | [diff] [blame] | 95 | private final SynchronousQueue<Boolean> waitOn; |
| 96 | private final SynchronousQueue<Boolean> pushTo; |
| 97 | private final CyclicBarrier finalBarrier; |
Brian Carlstrom | 5562174 | 2011-10-17 00:41:56 -0700 | [diff] [blame] | 98 | |
Andreas Gampe | 93f3da1 | 2014-07-26 01:13:13 -0700 | [diff] [blame] | 99 | private Main(int id, SynchronousQueue<Boolean> waitOn, SynchronousQueue<Boolean> pushTo, |
| 100 | CyclicBarrier finalBarrier) { |
Brian Carlstrom | 5562174 | 2011-10-17 00:41:56 -0700 | [diff] [blame] | 101 | this.id = id; |
Andreas Gampe | 93f3da1 | 2014-07-26 01:13:13 -0700 | [diff] [blame] | 102 | this.waitOn = waitOn; |
| 103 | this.pushTo = pushTo; |
| 104 | this.finalBarrier = finalBarrier; |
Brian Carlstrom | 5562174 | 2011-10-17 00:41:56 -0700 | [diff] [blame] | 105 | } |
| 106 | |
| 107 | public void run() { |
Andreas Gampe | 93f3da1 | 2014-07-26 01:13:13 -0700 | [diff] [blame] | 108 | try { |
| 109 | work(); |
| 110 | } catch (Exception exc) { |
| 111 | // Any exception is bad. |
| 112 | exc.printStackTrace(System.err); |
| 113 | System.exit(1); |
Brian Carlstrom | 5562174 | 2011-10-17 00:41:56 -0700 | [diff] [blame] | 114 | } |
| 115 | } |
Andreas Gampe | 21b4bf8 | 2014-07-25 16:37:09 -0700 | [diff] [blame] | 116 | |
Andreas Gampe | 93f3da1 | 2014-07-26 01:13:13 -0700 | [diff] [blame] | 117 | public void work() throws BrokenBarrierException, InterruptedException, TimeoutException { |
| 118 | ArrayList<Object> l = new ArrayList<Object>(); |
| 119 | |
| 120 | // Main loop. |
| 121 | for (int i = 0; ; i++) { |
| 122 | Boolean receivedB = waitOn.poll(TIMEOUT_VALUE, TimeUnit.MINUTES); |
| 123 | checkTimeout(receivedB); |
| 124 | boolean received = receivedB; |
| 125 | |
| 126 | // This is the first stage, try to allocate up till MAX_SIZE. |
| 127 | boolean oom = i >= MAX_SIZE; |
| 128 | try { |
| 129 | l.add(new ArrayList<Object>(i)); |
| 130 | } catch (OutOfMemoryError oome) { |
| 131 | oom = true; |
| 132 | } |
| 133 | |
| 134 | if (!received || oom) { |
| 135 | // First stage, always push false. |
| 136 | checkTimeout(pushTo.offer(Boolean.FALSE, TIMEOUT_VALUE, TimeUnit.MINUTES)); |
| 137 | |
| 138 | // If we received true, wait for the false to come around. |
| 139 | if (received) { |
| 140 | checkTimeout(waitOn.poll(TIMEOUT_VALUE, TimeUnit.MINUTES)); |
| 141 | } |
| 142 | |
| 143 | // Break out of the loop. |
| 144 | break; |
| 145 | } else { |
| 146 | // Pass on true. |
| 147 | checkTimeout(pushTo.offer(Boolean.TRUE, TIMEOUT_VALUE, TimeUnit.MINUTES)); |
| 148 | } |
| 149 | } |
| 150 | |
| 151 | // We have reached the final point. Wait on the barrier, but at most a minute. |
| 152 | finalBarrier.await(TIMEOUT_VALUE, TimeUnit.MINUTES); |
| 153 | |
| 154 | // Done. |
| 155 | } |
Brian Carlstrom | 5562174 | 2011-10-17 00:41:56 -0700 | [diff] [blame] | 156 | } |