ART: Make run tests out of oat tests
Transforms all former oat tests into run tests.
Change-Id: I190dd39456454c36e5538a2c044d993965a67533
diff --git a/test/004-ThreadStress/src/Main.java b/test/004-ThreadStress/src/Main.java
new file mode 100644
index 0000000..0c1c97d
--- /dev/null
+++ b/test/004-ThreadStress/src/Main.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+// Run on host with:
+// javac ThreadTest.java && java ThreadStress && rm *.class
+public class Main implements Runnable {
+
+ public static final boolean DEBUG = false;
+
+ enum Operation {
+ OOM(1),
+ SIGQUIT(19),
+ ALLOC(60),
+ STACKTRACE(20),
+ EXIT(50),
+
+ SLEEP(25),
+ TIMED_WAIT(10),
+ WAIT(15);
+
+ private final int frequency;
+ Operation(int frequency) {
+ this.frequency = frequency;
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+
+ final int numberOfThreads = 5;
+ final int totalOperations = 1000;
+ final int operationsPerThread = totalOperations/numberOfThreads;
+
+ // Lock used to notify threads performing Operation.WAIT
+ final Object lock = new Object();
+
+ // Each thread is going to do operationsPerThread
+ // operations. The distribution of operations is determined by
+ // the Operation.frequency values. We fill out an Operation[]
+ // for each thread with the operations it is to perform. The
+ // Operation[] is shuffled so that there is more random
+ // interactions between the threads.
+
+ // The simple-minded filling in of Operation[] based on
+ // Operation.frequency below won't have even have close to a
+ // reasonable distribution if the count of Operation
+ // frequencies is greater than the total number of
+ // operations. So here we do a quick sanity check in case
+ // people tweak the constants above.
+ int operationCount = 0;
+ for (Operation op : Operation.values()) {
+ operationCount += op.frequency;
+ }
+ if (operationCount > operationsPerThread) {
+ throw new AssertionError(operationCount + " > " + operationsPerThread);
+ }
+
+ // Fill in the Operation[] array for each thread by laying
+ // down references to operation according to their desired
+ // frequency.
+ final Main[] threadStresses = new Main[numberOfThreads];
+ for (int t = 0; t < threadStresses.length; t++) {
+ Operation[] operations = new Operation[operationsPerThread];
+ int o = 0;
+ LOOP:
+ while (true) {
+ for (Operation op : Operation.values()) {
+ for (int f = 0; f < op.frequency; f++) {
+ if (o == operations.length) {
+ break LOOP;
+ }
+ operations[o] = op;
+ o++;
+ }
+ }
+ }
+ // Randomize the oepration order
+ Collections.shuffle(Arrays.asList(operations));
+ threadStresses[t] = new Main(lock, t, operations);
+ }
+
+ // Enable to dump operation counds per thread to make sure its
+ // sane compared to Operation.frequency
+ if (DEBUG) {
+ for (int t = 0; t < threadStresses.length; t++) {
+ Operation[] operations = new Operation[operationsPerThread];
+ Map<Operation, Integer> distribution = new HashMap<Operation, Integer>();
+ for (Operation operation : operations) {
+ Integer ops = distribution.get(operation);
+ if (ops == null) {
+ ops = 1;
+ } else {
+ ops++;
+ }
+ distribution.put(operation, ops);
+ }
+ System.out.println("Distribution for " + t);
+ for (Operation op : Operation.values()) {
+ System.out.println(op + " = " + distribution.get(op));
+ }
+ }
+ }
+
+ // Create the runners for each thread. The runner Thread
+ // ensures that thread that exit due to Operation.EXIT will be
+ // restarted until they reach their desired
+ // operationsPerThread.
+ Thread[] runners = new Thread[numberOfThreads];
+ for (int r = 0; r < runners.length; r++) {
+ final Main ts = threadStresses[r];
+ runners[r] = new Thread("Runner thread " + r) {
+ final Main threadStress = ts;
+ public void run() {
+ int id = threadStress.id;
+ System.out.println("Starting worker for " + id);
+ while (threadStress.nextOperation < operationsPerThread) {
+ Thread thread = new Thread(ts, "Worker thread " + id);
+ thread.start();
+ try {
+ thread.join();
+ } catch (InterruptedException e) {
+ }
+ System.out.println("Thread exited for " + id + " with "
+ + (operationsPerThread - threadStress.nextOperation)
+ + " operations remaining.");
+ }
+ System.out.println("Finishing worker");
+ }
+ };
+ }
+
+ // The notifier thread is a daemon just loops forever to wake
+ // up threads in Operation.WAIT
+ Thread notifier = new Thread("Notifier") {
+ public void run() {
+ while (true) {
+ synchronized (lock) {
+ lock.notifyAll();
+ }
+ }
+ }
+ };
+ notifier.setDaemon(true);
+ notifier.start();
+
+ for (int r = 0; r < runners.length; r++) {
+ runners[r].start();
+ }
+ for (int r = 0; r < runners.length; r++) {
+ runners[r].join();
+ }
+ }
+
+ private final Operation[] operations;
+ private final Object lock;
+ private final int id;
+
+ private int nextOperation;
+
+ private Main(Object lock, int id, Operation[] operations) {
+ this.lock = lock;
+ this.id = id;
+ this.operations = operations;
+ }
+
+ public void run() {
+ try {
+ if (DEBUG) {
+ System.out.println("Starting ThreadStress " + id);
+ }
+ while (nextOperation < operations.length) {
+ Operation operation = operations[nextOperation];
+ if (DEBUG) {
+ System.out.println("ThreadStress " + id
+ + " operation " + nextOperation
+ + " is " + operation);
+ }
+ nextOperation++;
+ switch (operation) {
+ case EXIT: {
+ return;
+ }
+ case SIGQUIT: {
+ try {
+ SIGQUIT();
+ } catch (Exception ex) {
+ }
+ }
+ case SLEEP: {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ignored) {
+ }
+ }
+ case TIMED_WAIT: {
+ synchronized (lock) {
+ try {
+ lock.wait(100, 0);
+ } catch (InterruptedException ignored) {
+ }
+ }
+ break;
+ }
+ case WAIT: {
+ synchronized (lock) {
+ try {
+ lock.wait();
+ } catch (InterruptedException ignored) {
+ }
+ }
+ break;
+ }
+ case OOM: {
+ try {
+ List<byte[]> l = new ArrayList<byte[]>();
+ while (true) {
+ l.add(new byte[1024]);
+ }
+ } catch (OutOfMemoryError e) {
+ }
+ break;
+ }
+ case ALLOC: {
+ try {
+ List<byte[]> l = new ArrayList<byte[]>();
+ for (int i = 0; i < 1024; i++) {
+ l.add(new byte[1024]);
+ }
+ } catch (OutOfMemoryError e) {
+ }
+ break;
+ }
+ case STACKTRACE: {
+ Thread.currentThread().getStackTrace();
+ break;
+ }
+ default: {
+ throw new AssertionError(operation.toString());
+ }
+ }
+ }
+ } finally {
+ if (DEBUG) {
+ System.out.println("Finishing ThreadStress for " + id);
+ }
+ }
+ }
+
+ private static void SIGQUIT() throws Exception {
+ Class<?> osClass = Class.forName("android.system.Os");
+ Method getpid = osClass.getDeclaredMethod("getpid");
+ int pid = (Integer)getpid.invoke(null);
+
+ Class<?> osConstants = Class.forName("android.system.OsConstants");
+ Field sigquitField = osConstants.getDeclaredField("SIGQUIT");
+ int sigquit = (Integer)sigquitField.get(null);
+
+ Method kill = osClass.getDeclaredMethod("kill", int.class, int.class);
+ kill.invoke(null, pid, sigquit);
+ }
+}