/*
* 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.
*/
package test.org.jikesrvm.tbench;
/**
* This is based on the "benchmark" used to demonstrate differenced between
* the cost of erlang processes and java threads (Originally at Joe Armstrongs
* web page linked below). It gives us a simple basis with which to compare
* costs of thread creation and synchronization.
*
* <p>Why is it called zog? Who knows but it keeps the flavour of the orginal
* "benchmark" so lets keep it. ZugZug is "yes-yes" in the warcraft games!</p>
*
* @link http://www.sics.se/~joe/ericsson/du98024.html
*/
public class Zog extends Thread {
private static final boolean DEBUG = false;
private Zog next;
private boolean flag;
private int message;
public void link(final Zog zog) {
next = zog;
}
public void run() {
try {
do this.relay(); while (message > 0);
} catch (InterruptedException e) {
e.printStackTrace();
System.exit(66);
}
}
private synchronized void relay() throws InterruptedException {
while (!flag) wait();
flag = false;
next.send(message - 1);
}
public synchronized void send(int n) throws InterruptedException {
message = n;
flag = true;
notify();
}
static class ZugZug extends Zog {
public synchronized void send(int n) throws InterruptedException {
super.send(n);
if (DEBUG) {
final String marker = (n == 0) ? "." : (n % 100 == 0) ? "*\n" : (n % 10 == 0) ? "+" : ".";
System.out.print(marker);
}
}
}
public static void main(String[] args) {
final int threadCount = Integer.parseInt(args[0]);
final int messageCount = Integer.parseInt(args[1]);
final Results results = performTestRun(threadCount, messageCount);
results.displayResults();
}
static class Results {
final int threadCount;
final int messageCount;
final long initTime;
final long runTime;
public Results(final int threadCount, final int messageCount, final long initTime, final long runTime) {
this.threadCount = threadCount;
this.messageCount = messageCount;
this.initTime = initTime;
this.runTime = runTime;
}
void displayResults() {
final double timePerThreadSpawn = ((double) initTime) / threadCount;
final double timePerMessage = ((double) runTime) / messageCount;
final String message =
"initTime = " + initTime + " ns (" + timePerThreadSpawn + " us/thread) (" + threadCount + " threads)";
System.out.println(message);
final String message2 =
"runTime = " + runTime + " ns (" + timePerMessage + " us/message) (" + messageCount + " messages)";
System.out.println(message2);
}
}
private static Results performTestRun(final int threadCount, final int messageCount) {
final long startTime = System.nanoTime();
final ZugZug first = new ZugZug();
first.start();
Zog old = first;
for (int i = 0; i < threadCount; i++) {
if (DEBUG) {
final String marker = (i == 0) ? "." : (i % 100 == 0) ? "*\n" : (i % 10 == 0) ? "+" : ".";
System.out.print(marker);
}
final Zog current = new Zog();
current.link(old);
current.start();
old = current;
}
first.link(old);
final long linkTime = System.nanoTime();
final long initTime = linkTime - startTime;
try {
first.send(messageCount);
} catch (InterruptedException e) {
e.printStackTrace();
System.exit(13);
}
try {
first.join();
} catch (InterruptedException e) {
e.printStackTrace();
System.exit(16);
}
final long endTime = System.nanoTime();
final long runTime = endTime - linkTime;
return new Results(threadCount, messageCount, initTime, runTime);
}
}