/*
* Copyright 2013 Thomas Bocek
*
* 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.
*/
package net.tomp2p.futures;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReferenceArray;
import net.tomp2p.peers.Number160;
import org.junit.Test;
/**
* Test the correctness and the performance of futures.
*
* @author Thomas Bocek
*
*/
public class TestFutures {
private Object lock = new Object();
private final int nr = 10;
private static final int RONUDS = 20000000;
private static final int SUB = 1;
private int steps = RONUDS / SUB;
private final Set<Integer> done = new HashSet<Integer>();
private final ExecutorService e = Executors.newFixedThreadPool(10);
/**
* Tests the performance of sequential processing as a base.
*/
@Test
public void testPerformanceSingle() {
Number160[] number160s = new Number160[nr];
Random rnd = new Random(1);
for (int i = 0; i < nr; i++) {
number160s[i] = new Number160(rnd);
}
// start test single-thread
long start = System.currentTimeMillis();
for (int i = 0; i < nr; i++) {
for (int j = 0; j < RONUDS; j++) {
number160s[i] = number160s[i].xor(new Number160(new Random(j * 31)));
// System.err.println("number160s[" + i + "]=" + number160s[i]);
}
}
// end test single-thread
long stop = System.currentTimeMillis();
System.out.println("XOR performance: single-thread: " + (stop - start) + "ms");
for (int i = 0; i < nr; i++) {
System.out.println("==> number160s[" + i + "]=" + number160s[i]);
}
}
/**
* Tests the performance of sequential processing as a base.
*
* @throws InterruptedException
*/
@Test
public void testPerformanceMulti() throws InterruptedException {
Number160[] number160s = new Number160[nr];
AtomicReferenceArray<FutureTest> array = new AtomicReferenceArray<FutureTest>(new FutureTest[nr]);
Random rnd = new Random(1);
for (int i = 0; i < nr; i++) {
number160s[i] = new Number160(rnd);
}
long start = System.currentTimeMillis();
recursive(array, number160s, 0, RONUDS / SUB, 0);
synchronized (lock) {
lock.wait();
}
// end test single-thread
long stop = System.currentTimeMillis();
System.out.println("XOR performance: multi-thread: " + (stop - start) + "ms");
for (int i = 0; i < nr; i++) {
System.out.println("==> number160s[" + i + "]=" + number160s[i]);
}
}
private void recursive(final AtomicReferenceArray<FutureTest> array, final Number160[] number160s, final int start,
final int rounds, final int counter) {
int active = 0;
for (int i = 0; i < nr; i++) {
if (array.get(i) == null) {
if (!done.contains(i)) {
array.set(i, startFuture(number160s[i], start, rounds, counter, i));
active++;
}
} else {
active++;
}
}
if (active == 0) {
System.err.println("we are done!");
synchronized (lock) {
lock.notifyAll();
}
}
FutureForkJoin<FutureTest> fork = new FutureForkJoin<FutureTest>(1, false, array);
fork.addListener(new BaseFutureAdapter<FutureForkJoin<FutureTest>>() {
@Override
public void operationComplete(final FutureForkJoin<FutureTest> future) throws Exception {
if (future.isFailed()) {
return;
}
if (future.getLast().getCounter() >= SUB - 1) {
done.add(future.getLast().getI());
// return;
}
number160s[future.getLast().getI()] = future.getLast().getResult();
// System.err.println("start over with start" + future.getLast().getStart() + "/round"
// + future.getLast().getRounds()+ " for "+future.getLast().getI()+
// "counter="+future.getLast().getCounter());
recursive(array, number160s, future.getLast().getStart() + steps, future.getLast().getRounds() + steps,
future.getLast().getCounter() + 1);
}
});
}
private FutureTest startFuture(final Number160 number, final int start, final int rounds, final int counter,
final int ii) {
final FutureTest futureTest = new FutureTest(ii, start, rounds);
Runnable r = new Runnable() {
@Override
public void run() {
// System.err.println("start theard (" + Thread.currentThread().getName() + ") " + number + "/" + start
// + "-" + rounds);
Number160 result = number;
for (int i = start; i < rounds; i++) {
result = result.xor(new Number160(new Random(i * 31)));
// System.err.println("number160s[" + ii + "]=" + result + "start="+start);
}
futureTest.setDone(result, counter);
}
};
e.submit(r);
return futureTest;
}
}