blob: 951b2d4fa655e35057a5e868725c3e21440a63dd [file] [log] [blame]
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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 org.jclouds;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.jclouds.date.DateServiceTest;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
/**
* // TODO: Adrian: Document this!
*
* @author Adrian Cole
*/
@Test(groups = "performance")
public class PerformanceTest {
protected static int LOOP_COUNT = 1000;
protected static int THREAD_COUNT = 1000;
protected ExecutorService exec;
@BeforeTest
public void setupExecutorService() {
exec = Executors.newCachedThreadPool();
}
@AfterTest
public void teardownExecutorService() {
exec.shutdownNow();
exec = null;
}
/**
* Executes a list of Runnable tasks in {@link #THREAD_COUNT} simultaneous threads, and outputs
* the timing results.
* <p>
* This method is careful to time only the actual task execution time, not the overhead of
* creating and queuing the tasks. We also use CountDownLatches to ensure that all tasks start at
* the same time, so concurrency is fully tested without ramp-up or ramp-down times.
* <p>
* This code is heavily based on Listing 5.11 in "Java Concurrency in Practice" by Brian Goetz et
* al, Addison-Wesley Professional.
*
* @see {@link DateServiceTest} for example usage.
*
* @param performanceTestName
* @param tasks
* @throws InterruptedException
* @throws ExecutionException
* @throws Throwable
*/
protected void executeMultiThreadedPerformanceTest(String performanceTestName,
List<Runnable> tasks) throws InterruptedException, ExecutionException, Throwable {
CompletionService<Throwable> completer = new ExecutorCompletionService<Throwable>(exec);
final CountDownLatch startGate = new CountDownLatch(1);
final CountDownLatch endGate = new CountDownLatch(THREAD_COUNT);
for (int i = 0; i < THREAD_COUNT; i++) {
final Runnable task = tasks.get(i % tasks.size());
// Wrap task so we can count down endGate.
completer.submit(new Callable<Throwable>() {
public Throwable call() {
try {
startGate.await(); // Wait to start simultaneously
task.run();
return null;
} catch (Throwable t) {
return t;
} finally {
endGate.countDown(); // Notify that I've finished
}
}
});
}
// Only time the execution time for all tasks, not start/stop times.
long startTime = System.nanoTime();
startGate.countDown(); // Trigger start of all tasks
endGate.await();
long endTime = System.nanoTime() - startTime;
// Check for assertion failures
Throwable t;
for (int i = 0; i < THREAD_COUNT; i++) {
t = completer.take().get();
if (t != null) {
throw t;
}
}
if (performanceTestName != null) {
System.out.printf("TIMING: Multi-threaded %s took %.3fms for %d threads\n",
performanceTestName, ((double) endTime / 1000000), THREAD_COUNT);
}
}
protected void executeMultiThreadedCorrectnessTest(List<Runnable> tasks)
throws InterruptedException, ExecutionException, Throwable {
executeMultiThreadedPerformanceTest(null, tasks);
}
}