performancetestrunner.java

来自「Java mulitplayer strategy game. Adaptati」· Java 代码 · 共 437 行

JAVA
437
字号
/*
 * Created on 2005-09-23
 * $Id: PerformanceTestRunner.java,v 1.5 2005/10/14 20:26:12 overmindx Exp $
 */
package net.sf.jawp.util.test;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * <p>
 * A runner for performance test cases. This classes works with implementations
 * of {@link TestCase} interfaces.
 * </p>
 * 
 * TODO maciek: this class is in design stage and it's API may change!
 * 
 * @author Maciej Malecki
 * @version $Revision: 1.5 $
 */
public class PerformanceTestRunner
{
	private final int load;

	// TODO maciek: this is sort of hack!
	private int counter;

	/**
	 * Creates new instance of PerformanceTestRunner.
	 * 
	 * @param load
	 *            parameter used for load testing
	 */
	public PerformanceTestRunner(final int load)
	{
		this.load = load;
	}

	/**
	 * Runs specified test case.
	 * 
	 * @param testCaseClass
	 *            test case to be run
	 * @return statistics, never null
	 */
	public Statistics run(final Class<? extends TestCase> testCaseClass)
	{
		try
		{
			final TestCase testCase = testCaseClass.newInstance();
			final Method[] methods = testCaseClass.getMethods();
			final Statistics statistics = new Statistics(testCase.getClass()
					.getName());

			testCase.init();
			try
			{
				for (Method method : methods)
				{
					final PerformanceTestMethod ptm = method
							.getAnnotation(PerformanceTestMethod.class);
					if (ptm != null)
					{
						testCase.before();
						try
						{
							statistics.add(runMethodThreads(testCase, method,
									ptm));
						}
						finally
						{
							testCase.after();
						}
					}
				}
			}
			finally
			{
				testCase.destroy();
			}
			return statistics;
		}
		catch (final InstantiationException e)
		{
			throw new RuntimeException(e);
		}
		catch (final IllegalAccessException e)
		{
			throw new RuntimeException(e);
		}
	}

	private synchronized boolean dec()
	{
		--counter;
		return counter == 0;
	}

	private void setCounter(final int newCounter)
	{
		counter = newCounter;
	}

	private StatisticsItem runMethodThreads(final TestCase testCase,
			final Method method, final PerformanceTestMethod ptm)
	{
		setCounter(load);
		if (load <= 1)
		{
			final long iterations = runMethod(testCase, method, ptm);
			return new StatisticsItem(method, ptm, iterations, iterations,
					iterations, iterations);
		}

		final Object monitor = new Object();
		final TestThread[] threads = new TestThread[load];
		for (int i = 0; i < load; ++i)
		{
			threads[i] = new TestThread(monitor, testCase, method, ptm);
			threads[i].start();
		}

		sleepAndNotify(monitor);

		long total = 0L;
		long min = Long.MAX_VALUE;
		long max = 0L;
		for (TestThread thread : threads)
		{
			final long iterations = thread.getIterations();
			total += iterations;
			if (iterations < min)
			{
				min = iterations;
			}
			if (iterations > max)
			{
				max = iterations;
			}
		}
		return new StatisticsItem(method, ptm, total, total / load, min, max);
	}

	private void sleepAndNotify(final Object monitor)
	{
		try
		{
			Thread.sleep(200);
		}
		catch (final InterruptedException e1)
		{
			// specjalnie
		}

		synchronized (monitor)
		{
			monitor.notifyAll();

			try
			{
				monitor.wait();
			}
			catch (final InterruptedException e)
			{
				// specjalnie
			}
		}
	}

	private long runMethod(final TestCase testCase, final Method method,
			final PerformanceTestMethod ptm)
	{
		try
		{
			final long endTime = System.currentTimeMillis() + ptm.time();
			long iterations = 0;
			while (System.currentTimeMillis() < endTime)
			{
				method.invoke(testCase);
				++iterations;
			}
			return iterations;
		}
		catch (final IllegalAccessException e)
		{
			throw new RuntimeException(e);
		}
		catch (final InvocationTargetException e)
		{
			throw new RuntimeException(e);
		}
	}

	private final class TestThread extends Thread
	{
		private final Object monitor;

		private final Method method;

		private final TestCase testCase;

		private final PerformanceTestMethod ptm;

		private long iterations = 0;

		public TestThread(final Object monitor, final TestCase testCase,
				final Method method, final PerformanceTestMethod ptm)
		{
			this.monitor = monitor;
			this.method = method;
			this.testCase = testCase;
			this.ptm = ptm;
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void run()
		{
			synchronized (monitor)
			{
				try
				{
					monitor.wait();
				}
				catch (final InterruptedException e)
				{
					// specjalnie
				}
			}

			iterations = runMethod(testCase, method, ptm);
			if (dec())
			{
				// if this is the last thread, notify the runner that it's
				// finnished
				synchronized (monitor)
				{
					monitor.notifyAll();
				}
			}
		}

		/**
		 * Returns the iterations.
		 * 
		 * @return the value of iterations
		 */
		protected long getIterations()
		{
			return iterations;
		}
	}

	/**
	 * This is a statistics object which contains results of performance tests
	 * for particular test case.
	 * 
	 * @author maciek
	 * @version $Revision: 1.5 $
	 */
	public final class Statistics
	{
		private final String testCaseClass;

		private final List<StatisticsItem> items = new ArrayList<StatisticsItem>();

		private Statistics(final String testCaseClass)
		{
			this.testCaseClass = testCaseClass;
		}

		/**
		 * 
		 * @return list of detailed statistics per each test method
		 */
		public List<StatisticsItem> items()
		{
			return Collections.unmodifiableList(items);
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public String toString()
		{
			final StringBuffer sb = new StringBuffer();
			sb.append("Test case ");
			sb.append(testCaseClass);
			sb.append("\n");

			for (StatisticsItem item : items)
			{
				sb.append("  ");
				sb.append(item.toString());
				sb.append("\n");
			}
			return sb.toString();
		}

		/**
		 * Returns the testCaseClass.
		 * 
		 * @return the value of testCaseClass
		 */
		public String getTestCaseClass()
		{
			return testCaseClass;
		}

		private void add(final StatisticsItem item)
		{
			items.add(item);
		}
	}

	/**
	 * A statistic object describing result of performance test for particular
	 * test method.
	 * 
	 * @author maciek
	 * @version $Revision: 1.5 $
	 */
	public final class StatisticsItem
	{
		private String methodName;

		private String comment;

		private long total;

		private long average;

		private long min;

		private long max;

		private int threads;

		private StatisticsItem(final Method method,
				final PerformanceTestMethod ptm, final long total,
				final long average, final long min, final long max)
		{
			this.methodName = method.getName();
			this.comment = ptm.comment();
			this.total = total;
			this.average = average;
			this.threads = load;
			this.min = min;
			this.max = max;
		}

		/**
		 * Returns the comment.
		 * 
		 * @return the value of comment
		 */
		public String getComment()
		{
			return comment;
		}

		/**
		 * Returns the executions.
		 * 
		 * @return the value of executions
		 */
		public long getTotal()
		{
			return total;
		}

		/**
		 * Returns the methodName.
		 * 
		 * @return the value of methodName
		 */
		public String getMethodName()
		{
			return methodName;
		}

		/**
		 * Returns the threads.
		 * 
		 * @return the value of threads
		 */
		public int getThreads()
		{
			return threads;
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public String toString()
		{
			final StringBuffer sb = new StringBuffer();
			sb.append("Method " + methodName);
			sb.append(" (" + comment);
			sb.append(") load: " + threads);
			sb.append(", total: " + total);
			sb.append(", average: " + average);
			sb.append(", min: " + min);
			sb.append(", max: " + max);
			return sb.toString();
		}

		/**
		 * Returns the max.
		 * 
		 * @return the value of max
		 */
		public long getMax()
		{
			return max;
		}

		/**
		 * Returns the min.
		 * 
		 * @return the value of min
		 */
		public long getMin()
		{
			return min;
		}

	}
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?