diff options
author | Andreas Gampe <agampe@google.com> | 2014-07-26 01:13:13 -0700 |
---|---|---|
committer | Andreas Gampe <agampe@google.com> | 2014-07-26 01:38:33 -0700 |
commit | 93f3da1578bf25d3bc8cf1d121477bf29b4d760a (patch) | |
tree | 379f11e1f9d52769e9b3b8cdb9d265b7830caffd /test/114-ParallelGC | |
parent | 3bcac48f23094fa0f46315a080ec47fc368fd4c2 (diff) | |
download | art-93f3da1578bf25d3bc8cf1d121477bf29b4d760a.tar.gz art-93f3da1578bf25d3bc8cf1d121477bf29b4d760a.tar.bz2 art-93f3da1578bf25d3bc8cf1d121477bf29b4d760a.zip |
ART: Rewrite ParallelGC run-test
To better test what ParallelGC is intended to do, write a version
that will more fairly allocate objects between the threads, and
will let each thread OOM only once. Use a barrier to wait for
completion of all threads, and force a final GC by allocating some
more objects.
Bug: 16406852
Change-Id: I019ddc08515b9610c18d55280cd46cbe3ae3e5ac
Diffstat (limited to 'test/114-ParallelGC')
-rw-r--r-- | test/114-ParallelGC/src/Main.java | 122 |
1 files changed, 111 insertions, 11 deletions
diff --git a/test/114-ParallelGC/src/Main.java b/test/114-ParallelGC/src/Main.java index 15d5e50796..8e2519dd0a 100644 --- a/test/114-ParallelGC/src/Main.java +++ b/test/114-ParallelGC/src/Main.java @@ -16,38 +16,138 @@ import java.util.ArrayList; import java.util.List; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; public class Main implements Runnable { + + public final static long TIMEOUT_VALUE = 5; // Timeout in minutes. + public final static long MAX_SIZE = 1000; // Maximum size of array-list to allocate. + public static void main(String[] args) throws Exception { Thread[] threads = new Thread[16]; + + // Use a cyclic system of synchronous queues to pass a boolean token around. + // + // The combinations are: + // + // Worker receives: true false false true + // Worker has OOM: false false true true + // | + // v + // Value to pass: true false false false + // Exit out of loop: false true true true + // Wait on in queue: true false false true + // + // Finally, the workers are supposed to wait on the barrier to synchronize the GC run. + + CyclicBarrier barrier = new CyclicBarrier(threads.length); + List<SynchronousQueue<Boolean>> queues = new ArrayList<SynchronousQueue<Boolean>>( + threads.length); + for (int i = 0; i < threads.length; i++) { + queues.add(new SynchronousQueue<Boolean>()); + } + for (int i = 0; i < threads.length; i++) { - threads[i] = new Thread(new Main(i)); + threads[i] = new Thread(new Main(i, queues.get(i), queues.get((i + 1) % threads.length), + barrier)); } for (Thread thread : threads) { thread.start(); } + + // Push off the cycle. + checkTimeout(queues.get(0).offer(Boolean.TRUE, TIMEOUT_VALUE, TimeUnit.MINUTES)); + + // Wait for the threads to finish. for (Thread thread : threads) { thread.join(); } + + // Allocate objects to definitely run GC before quitting. + try { + for (int i = 0; i < 1000; i++) { + new ArrayList<Object>(i); + } + } catch (OutOfMemoryError oom) { + } + } + + private static void checkTimeout(Object o) { + checkTimeout(o != null); + } + + private static void checkTimeout(boolean b) { + if (!b) { + // Something went wrong. + System.out.println("Bad things happened, timeout."); + System.exit(1); + } } private final int id; + private final SynchronousQueue<Boolean> waitOn; + private final SynchronousQueue<Boolean> pushTo; + private final CyclicBarrier finalBarrier; - private Main(int id) { + private Main(int id, SynchronousQueue<Boolean> waitOn, SynchronousQueue<Boolean> pushTo, + CyclicBarrier finalBarrier) { this.id = id; - // Allocate this early so it's independent of how the threads are scheduled on startup. - this.l = new ArrayList<Object>(); + this.waitOn = waitOn; + this.pushTo = pushTo; + this.finalBarrier = finalBarrier; } public void run() { - for (int i = 0; i < 1000; i++) { - try { - l.add(new ArrayList<Object>(i)); - } catch (OutOfMemoryError oom) { - // Ignore. - } + try { + work(); + } catch (Exception exc) { + // Any exception is bad. + exc.printStackTrace(System.err); + System.exit(1); } } - private List<Object> l; + public void work() throws BrokenBarrierException, InterruptedException, TimeoutException { + ArrayList<Object> l = new ArrayList<Object>(); + + // Main loop. + for (int i = 0; ; i++) { + Boolean receivedB = waitOn.poll(TIMEOUT_VALUE, TimeUnit.MINUTES); + checkTimeout(receivedB); + boolean received = receivedB; + + // This is the first stage, try to allocate up till MAX_SIZE. + boolean oom = i >= MAX_SIZE; + try { + l.add(new ArrayList<Object>(i)); + } catch (OutOfMemoryError oome) { + oom = true; + } + + if (!received || oom) { + // First stage, always push false. + checkTimeout(pushTo.offer(Boolean.FALSE, TIMEOUT_VALUE, TimeUnit.MINUTES)); + + // If we received true, wait for the false to come around. + if (received) { + checkTimeout(waitOn.poll(TIMEOUT_VALUE, TimeUnit.MINUTES)); + } + + // Break out of the loop. + break; + } else { + // Pass on true. + checkTimeout(pushTo.offer(Boolean.TRUE, TIMEOUT_VALUE, TimeUnit.MINUTES)); + } + } + + // We have reached the final point. Wait on the barrier, but at most a minute. + finalBarrier.await(TIMEOUT_VALUE, TimeUnit.MINUTES); + + // Done. + } } |