/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Common Public License (CPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/cpl1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
import java.util.WeakHashMap;
/**
* Fill up a WeakHashSet with linked list elements. Kill off every second element
* and add new elements to the list. Rinse and repeat.
*/
public class ReferenceStress {
static boolean verbose = false;
static int elements = 0;
private static synchronized void report(int completed) {
elements += completed;
}
/**
* The element type of the hash table - a simple linked list
*/
private static class Element {
Element next;
Element(Element next) { this.next = next; }
void deleteNext() { if (next != null) next = next.next; }
int length() {
int result = 1;
Element cursor = next;
while (cursor != null) {
cursor = cursor.next;
result++;
}
return result;
}
}
/**
* The kernel of the test. Add elements to the linked list/hash table, while
* killing off half of them.
*
* @param liveSize
* @param iterations
*/
private static void thrash(int liveSize, int iterations) {
WeakHashMap<Element,Integer> map = new WeakHashMap<Element,Integer>();
Element list = new Element(null);
Integer serial = Integer.valueOf(0);
for (int i=0; i < liveSize; i++) {
list = new Element(list);
map.put(list, serial++);
}
for (int j=0; j < iterations; j++) {
Element cursor = list;
int inserts = 0;
while (cursor != null) {
cursor.deleteNext();
cursor = cursor.next;
list = new Element(list);
map.put(list, serial++);
inserts++;
}
if (verbose) {
System.out.println("Map size "+map.size()+", list length "+list.length());
}
report(inserts);
}
}
/**
* Print usage and die
*/
private static void usage() {
System.err.println("Usage: ReferenceStress [-verbose] [-threads n] [-size s] [-iterations i] [perf|base]");
System.exit(1);
}
public static void main(String[] args) {
/* Default values of parameters */
int liveSize = 5000;
int iterations = 100;
int threads = 2;
for (int i=0; i < args.length; i++) {
if (args[i].charAt(0) == '-') {
if (args[i].equals("-verbose")) {
verbose = true;
} else if (args[i].equals("-threads")) {
threads = Integer.valueOf(args[++i]);
} else if (args[i].equals("-iterations")) {
iterations = Integer.valueOf(args[++i]);
} else if (args[i].equals("-size")) {
liveSize = Integer.valueOf(args[++i]);
} else {
System.out.println("Unrecognized switch "+args[i]);
usage();
}
} else if (args[i].equals("perf") || args[i].equals("base")) {
// parameter has no effect
} else {
System.out.println("Unrecognized parameter "+args[i]);
usage();
}
}
System.out.println("Running "+threads+" threads with "+liveSize+" entries for "+iterations+" iterations");
Thread[] threadTable = new Thread[threads];
final int finalLiveSize = liveSize;
final int finalIterations = iterations;
for (int i=0; i < threads; i++) {
threadTable[i] = new Thread() {
public void run() {
thrash(finalLiveSize, finalIterations);
}
};
}
long start = System.nanoTime();
// Start the threads
for (int i=0; i < threads; i++) {
threadTable[i].start();
}
// Wait for them to complete
for (int i=0; i < threads; i++) {
try {
threadTable[i].join();
} catch (InterruptedException e) {
}
}
long time = (System.nanoTime() - start)/1000000;
System.out.println(elements + " references inserted in " + time + "ms.");
System.out.println("Overall: SUCCESS");
}
}