summaryrefslogtreecommitdiffstats
path: root/test/074-gc-thrash
diff options
context:
space:
mode:
authorjeffhao <jeffhao@google.com>2011-09-29 17:41:15 -0700
committerjeffhao <jeffhao@google.com>2011-09-29 17:41:15 -0700
commit5d1ac920fdaef5d4ec8f66bb734488cd9660b024 (patch)
treedd372f306ab70f4c86759869b1f74eca62ff6f2b /test/074-gc-thrash
parentc31664f3d82e6cd68275a529a8a73f067a52e8be (diff)
downloadandroid_art-5d1ac920fdaef5d4ec8f66bb734488cd9660b024.tar.gz
android_art-5d1ac920fdaef5d4ec8f66bb734488cd9660b024.tar.bz2
android_art-5d1ac920fdaef5d4ec8f66bb734488cd9660b024.zip
Adding old unit tests to test suite.
These tests are copied straight over. They'll still run, but they're using the old system. Change-Id: If494519e52ddf858a9febfc55bdae830468cb3c8
Diffstat (limited to 'test/074-gc-thrash')
-rw-r--r--test/074-gc-thrash/expected.txt2
-rw-r--r--test/074-gc-thrash/info.txt1
-rw-r--r--test/074-gc-thrash/src/Main.java337
3 files changed, 340 insertions, 0 deletions
diff --git a/test/074-gc-thrash/expected.txt b/test/074-gc-thrash/expected.txt
new file mode 100644
index 0000000000..26691659be
--- /dev/null
+++ b/test/074-gc-thrash/expected.txt
@@ -0,0 +1,2 @@
+Running (10 seconds) ...
+Done.
diff --git a/test/074-gc-thrash/info.txt b/test/074-gc-thrash/info.txt
new file mode 100644
index 0000000000..ded1582ca2
--- /dev/null
+++ b/test/074-gc-thrash/info.txt
@@ -0,0 +1 @@
+This thrashes the memory allocator and garbage collector for a brief period.
diff --git a/test/074-gc-thrash/src/Main.java b/test/074-gc-thrash/src/Main.java
new file mode 100644
index 0000000000..f85aa4bde5
--- /dev/null
+++ b/test/074-gc-thrash/src/Main.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2009 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.io.File;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+
+public class Main {
+ public static volatile boolean quit = false;
+ public static final boolean DEBUG = false;
+
+ private static final boolean WRITE_HPROF_DATA = false;
+ private static final int TEST_TIME = 10;
+ private static final String OUTPUT_FILE = "gc-thrash.hprof";
+
+ public static void main(String[] args) {
+ // dump heap before
+
+ System.out.println("Running (" + TEST_TIME + " seconds) ...");
+ runTests();
+
+ Method dumpHprofDataMethod = null;
+ String dumpFile = null;
+
+ if (WRITE_HPROF_DATA) {
+ dumpHprofDataMethod = getDumpHprofDataMethod();
+ if (dumpHprofDataMethod != null) {
+ dumpFile = getDumpFileName();
+ System.out.println("Sending output to " + dumpFile);
+ }
+ }
+
+ System.gc();
+ System.runFinalization();
+ System.gc();
+
+ if (WRITE_HPROF_DATA && dumpHprofDataMethod != null) {
+ try {
+ dumpHprofDataMethod.invoke(null, dumpFile);
+ } catch (IllegalAccessException iae) {
+ System.err.println(iae);
+ } catch (InvocationTargetException ite) {
+ System.err.println(ite);
+ }
+ }
+
+ System.out.println("Done.");
+ }
+
+ /**
+ * Finds VMDebug.dumpHprofData() through reflection. In the reference
+ * implementation this will not be available.
+ *
+ * @return the reflection object, or null if the method can't be found
+ */
+ private static Method getDumpHprofDataMethod() {
+ ClassLoader myLoader = Main.class.getClassLoader();
+ Class vmdClass;
+ try {
+ vmdClass = myLoader.loadClass("dalvik.system.VMDebug");
+ } catch (ClassNotFoundException cnfe) {
+ return null;
+ }
+
+ Method meth;
+ try {
+ meth = vmdClass.getMethod("dumpHprofData",
+ new Class[] { String.class });
+ } catch (NoSuchMethodException nsme) {
+ System.err.println("Found VMDebug but not dumpHprofData method");
+ return null;
+ }
+
+ return meth;
+ }
+
+ private static String getDumpFileName() {
+ File tmpDir = new File("/tmp");
+ if (tmpDir.exists() && tmpDir.isDirectory()) {
+ return "/tmp/" + OUTPUT_FILE;
+ }
+
+ File sdcard = new File("/sdcard");
+ if (sdcard.exists() && sdcard.isDirectory()) {
+ return "/sdcard/" + OUTPUT_FILE;
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Run the various tests for a set period.
+ */
+ public static void runTests() {
+ Robin robin = new Robin();
+ Deep deep = new Deep();
+ Large large = new Large();
+
+ /* start all threads */
+ robin.start();
+ deep.start();
+ large.start();
+
+ /* let everybody run for 10 seconds */
+ sleep(TEST_TIME * 1000);
+
+ quit = true;
+
+ try {
+ /* wait for all threads to stop */
+ robin.join();
+ deep.join();
+ large.join();
+ } catch (InterruptedException ie) {
+ System.err.println("join was interrupted");
+ }
+ }
+
+ /**
+ * Sleeps for the "ms" milliseconds.
+ */
+ public static void sleep(int ms) {
+ try {
+ Thread.sleep(ms);
+ } catch (InterruptedException ie) {
+ System.err.println("sleep was interrupted");
+ }
+ }
+
+ /**
+ * Sleeps briefly, allowing other threads some CPU time to get started.
+ */
+ public static void startupDelay() {
+ sleep(500);
+ }
+}
+
+
+/**
+ * Allocates useless objects and holds on to several of them.
+ *
+ * Uses a single large array of references, replaced repeatedly in round-robin
+ * order.
+ */
+class Robin extends Thread {
+ private static final int ARRAY_SIZE = 40960;
+ int sleepCount = 0;
+
+ public void run() {
+ Main.startupDelay();
+
+ String strings[] = new String[ARRAY_SIZE];
+ int idx = 0;
+
+ while (!Main.quit) {
+ strings[idx] = makeString(idx);
+
+ if (idx % (ARRAY_SIZE / 4) == 0) {
+ Main.sleep(400);
+ sleepCount++;
+ }
+
+ idx = (idx + 1) % ARRAY_SIZE;
+ }
+
+ if (Main.DEBUG)
+ System.out.println("Robin: sleepCount=" + sleepCount);
+ }
+
+ private String makeString(int val) {
+ return new String("Robin" + val);
+ }
+}
+
+
+/**
+ * Allocates useless objects in recursive calls.
+ */
+class Deep extends Thread {
+ private static final int MAX_DEPTH = 61;
+
+ private static String strong[] = new String[MAX_DEPTH];
+ private static WeakReference weak[] = new WeakReference[MAX_DEPTH];
+
+ public void run() {
+ int iter = 0;
+ boolean once = false;
+
+ Main.startupDelay();
+
+ while (!Main.quit) {
+ dive(0, iter);
+ once = true;
+ iter += MAX_DEPTH;
+ }
+
+ if (!once) {
+ System.err.println("not even once?");
+ return;
+ }
+
+ /*
+ * Check the results of the last trip through. Everything in
+ * "weak" should be matched in "strong", and the two should be
+ * equivalent (object-wise, not just string-equality-wise).
+ */
+ for (int i = 0; i < MAX_DEPTH; i++) {
+ if (strong[i] != weak[i].get()) {
+ System.err.println("Deep: " + i + " strong=" + strong[i] +
+ ", weak=" + weak[i].get());
+ }
+ }
+
+ /*
+ * Wipe "strong", do a GC, see if "weak" got collected.
+ */
+ for (int i = 0; i < MAX_DEPTH; i++)
+ strong[i] = null;
+
+ System.gc();
+
+ for (int i = 0; i < MAX_DEPTH; i++) {
+ if (weak[i].get() != null) {
+ System.err.println("Deep: weak still has " + i);
+ }
+ }
+
+ if (Main.DEBUG)
+ System.out.println("Deep: iters=" + iter / MAX_DEPTH);
+ }
+
+ /**
+ * Recursively dive down, setting one or more local variables.
+ *
+ * We pad the stack out with locals, attempting to create a mix of
+ * valid and invalid references on the stack.
+ */
+ private String dive(int depth, int iteration) {
+ String str0;
+ String str1;
+ String str2;
+ String str3;
+ String str4;
+ String str5;
+ String str6;
+ String str7;
+ String funStr;
+
+ funStr = "";
+
+ switch (iteration % 8) {
+ case 0:
+ funStr = str0 = makeString(iteration);
+ break;
+ case 1:
+ funStr = str1 = makeString(iteration);
+ break;
+ case 2:
+ funStr = str2 = makeString(iteration);
+ break;
+ case 3:
+ funStr = str3 = makeString(iteration);
+ break;
+ case 4:
+ funStr = str4 = makeString(iteration);
+ break;
+ case 5:
+ funStr = str5 = makeString(iteration);
+ break;
+ case 6:
+ funStr = str6 = makeString(iteration);
+ break;
+ case 7:
+ funStr = str7 = makeString(iteration);
+ break;
+ }
+
+ strong[depth] = funStr;
+ weak[depth] = new WeakReference(funStr);
+
+ if (depth+1 < MAX_DEPTH)
+ dive(depth+1, iteration+1);
+ else
+ Main.sleep(100);
+
+ return funStr;
+ }
+
+ private String makeString(int val) {
+ return new String("Deep" + val);
+ }
+}
+
+
+/**
+ * Allocates large useless objects.
+ */
+class Large extends Thread {
+ public void run() {
+ byte[] chunk;
+ int count = 0;
+ int sleepCount = 0;
+
+ Main.startupDelay();
+
+ while (!Main.quit) {
+ chunk = new byte[100000];
+ pretendToUse(chunk);
+
+ count++;
+ if ((count % 500) == 0) {
+ Main.sleep(400);
+ sleepCount++;
+ }
+ }
+
+ if (Main.DEBUG)
+ System.out.println("Large: sleepCount=" + sleepCount);
+ }
+
+ public void pretendToUse(byte[] chunk) {}
+}