summaryrefslogtreecommitdiffstats
path: root/test/114-ParallelGC
diff options
context:
space:
mode:
authorAndreas Gampe <agampe@google.com>2015-01-20 21:26:43 -0800
committerAndreas Gampe <agampe@google.com>2015-01-21 23:23:39 -0800
commit6c957c521929ea66d098736995e27aae18be9e68 (patch)
tree4e235c48449c6f25b70f4d065ea72ce9b1a355f0 /test/114-ParallelGC
parentb061b894260df6b68bb8a89ed4a1e85e576bb696 (diff)
downloadart-6c957c521929ea66d098736995e27aae18be9e68.tar.gz
art-6c957c521929ea66d098736995e27aae18be9e68.tar.bz2
art-6c957c521929ea66d098736995e27aae18be9e68.zip
ART: Rewrite ParallelGC test
Make the setup simpler and less prone to OOME problems. Bug: 19027813 Change-Id: Ie2dbe1579a45d554f207a9bf84d53303acbe79d5
Diffstat (limited to 'test/114-ParallelGC')
-rw-r--r--test/114-ParallelGC/src/Main.java171
1 files changed, 76 insertions, 95 deletions
diff --git a/test/114-ParallelGC/src/Main.java b/test/114-ParallelGC/src/Main.java
index 48f9bd363f..df2243c27f 100644
--- a/test/114-ParallelGC/src/Main.java
+++ b/test/114-ParallelGC/src/Main.java
@@ -16,54 +16,36 @@
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.atomic.AtomicInteger;
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 {
// Timeout in minutes. Make it larger than the run-test timeout to get a native thread dump by
// ART on timeout when running on the host.
- public final static long TIMEOUT_VALUE = 12;
+ private final static long TIMEOUT_VALUE = 7;
- public final static long MAX_SIZE = 1000; // Maximum size of array-list to allocate.
+ private final static long MAX_SIZE = 1000; // Maximum size of array-list to allocate.
+
+ private final static int THREAD_COUNT = 16;
+
+ // Use a couple of different forms of synchronizing to test some of these...
+ private final static AtomicInteger counter = new AtomicInteger();
+ private final static Object gate = new Object();
+ private volatile static int waitCount = 0;
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>());
- }
+ Thread[] threads = new Thread[THREAD_COUNT];
+
+ // This barrier is used to synchronize the threads starting to allocate.
+ // Note: Even though a barrier is not allocation-free, this one is fine, as it will be used
+ // before filling the heap.
+ CyclicBarrier startBarrier = new CyclicBarrier(threads.length);
for (int i = 0; i < threads.length; i++) {
- threads[i] = new Thread(new Main(i, queues.get(i), queues.get((i + 1) % threads.length),
- barrier));
+ threads[i] = new Thread(new Main(startBarrier));
+ threads[i].start();
}
- 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) {
@@ -72,85 +54,84 @@ public class Main implements Runnable {
// Allocate objects to definitely run GC before quitting.
try {
- for (int i = 0; i < 1000; i++) {
- new ArrayList<Object>(i);
+ ArrayList<Object> l = new ArrayList<Object>();
+ for (int i = 0; i < 100000; i++) {
+ l.add(new ArrayList<Object>(i));
}
} catch (OutOfMemoryError oom) {
}
+ new ArrayList<Object>(50);
}
- 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 Main(CyclicBarrier startBarrier) {
+ this.startBarrier = startBarrier;
}
- private final int id;
- private final SynchronousQueue<Boolean> waitOn;
- private final SynchronousQueue<Boolean> pushTo;
- private final CyclicBarrier finalBarrier;
-
- private Main(int id, SynchronousQueue<Boolean> waitOn, SynchronousQueue<Boolean> pushTo,
- CyclicBarrier finalBarrier) {
- this.id = id;
- this.waitOn = waitOn;
- this.pushTo = pushTo;
- this.finalBarrier = finalBarrier;
- }
+ private ArrayList<Object> store;
+ private CyclicBarrier startBarrier;
public void run() {
try {
work();
- } catch (Exception exc) {
- // Any exception is bad.
- exc.printStackTrace(System.err);
+ } catch (Throwable t) {
+ // Any exception or error getting here is bad.
+ try {
+ // May need allocations...
+ t.printStackTrace(System.err);
+ } catch (Throwable tInner) {
+ }
System.exit(1);
}
}
- public void work() throws BrokenBarrierException, InterruptedException, TimeoutException {
+ private void work() throws Exception {
+ // Any exceptions except an OOME in the allocation loop are bad and handed off to the
+ // caller which should abort the whole runtime.
+
ArrayList<Object> l = new ArrayList<Object>();
+ store = l; // Keep it alive.
- // 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));
- }
+ // Wait for the start signal.
+ startBarrier.await(TIMEOUT_VALUE, java.util.concurrent.TimeUnit.MINUTES);
- // Break out of the loop.
- break;
- } else {
- // Pass on true.
- checkTimeout(pushTo.offer(Boolean.TRUE, TIMEOUT_VALUE, TimeUnit.MINUTES));
- }
+ // Allocate.
+ try {
+ for (int i = 0; i < MAX_SIZE; i++) {
+ l.add(new ArrayList<Object>(i));
+ }
+ } catch (OutOfMemoryError oome) {
+ // Fine, we're done.
}
- // We have reached the final point. Wait on the barrier, but at most a minute.
- finalBarrier.await(TIMEOUT_VALUE, TimeUnit.MINUTES);
+ // Atomically increment the counter and check whether we were last.
+ int number = counter.incrementAndGet();
+
+ if (number < THREAD_COUNT) {
+ // Not last.
+ synchronized (gate) {
+ // Increment the wait counter.
+ waitCount++;
+ gate.wait(TIMEOUT_VALUE * 1000 * 60);
+ }
+ } else {
+ // Last. Wait until waitCount == THREAD_COUNT - 1.
+ for (int loops = 0; ; loops++) {
+ synchronized (gate) {
+ if (waitCount == THREAD_COUNT - 1) {
+ // OK, everyone's waiting. Notify and break out.
+ gate.notifyAll();
+ break;
+ } else if (loops > 40) {
+ // 1s wait, too many tries.
+ System.out.println("Waited too long for the last thread.");
+ System.exit(1);
+ }
+ }
+ // Wait a bit.
+ Thread.sleep(25);
+ }
+ }
- // Done.
+ store = null; // Allow GC to reclaim it.
}
}