use of org.apache.sis.test.Performance in project sis by apache.
the class RangeSetTest method stress.
/**
* Tests the performance of {@link RangeSet} implementation. This test is not executed
* in normal SIS build. We run this test only when the {@link RangeSet} implementation
* changed, and we want to test the impact of that change on the performance.
*
* @throws InterruptedException if the test has been interrupted.
*/
@Performance
public void stress() throws InterruptedException {
final PrintWriter out = TestCase.out;
final Random r = TestUtilities.createRandomNumberGenerator();
for (int p = 0; p < 10; p++) {
final long start = System.nanoTime();
final RangeSet<Integer> set = RangeSet.create(Integer.class, true, false);
for (int i = 0; i < 100000; i++) {
final int lower = r.nextInt(1000000) - 500;
final int upper = lower + r.nextInt(100) + 1;
if (r.nextBoolean()) {
set.add(lower, upper);
} else {
set.remove(lower, upper);
}
}
out.print((System.nanoTime() - start) / (float) NANOS_PER_SECOND);
out.print(" seconds for a size of ");
out.println(set.size());
Thread.sleep(1000);
}
}
use of org.apache.sis.test.Performance in project sis by apache.
the class CacheTest method stress.
/**
* Starts many threads writing in the same cache, with a high probability that two threads
* ask for the same key in some occasions.
*
* @throws InterruptedException if the test has been interrupted.
*/
@Test
@Performance
@DependsOnMethod("testThreadBlocking")
public void stress() throws InterruptedException {
final int count = 5000;
final Cache<Integer, Integer> cache = new Cache<>();
final AtomicReference<Throwable> failures = new AtomicReference<>();
final class WriterThread extends Thread {
/**
* Incremented every time a value has been added. This is not the number of time the
* loop has been executed, since this variable is not incremented when a value already
* exists for a key.
*/
int addCount;
/**
* Creates a new thread.
*/
WriterThread(final int i) {
super(TestUtilities.THREADS, "CacheTest.stress() #" + i);
}
/**
* Puts random values in the map.
*/
@SuppressWarnings({ "UnnecessaryBoxing", "CallToThreadYield", "NumberEquality" })
@Override
public void run() {
for (int i = 0; i < count; i++) {
final Integer key = i;
// We really want new instance.
final Integer expected = new Integer(i * i);
final Integer value;
try {
value = cache.getOrCreate(key, () -> expected);
assertEquals(expected, value);
} catch (Throwable e) {
if (!failures.compareAndSet(null, e)) {
failures.get().addSuppressed(e);
}
continue;
}
if (expected == value) {
// Identity comparison (not value comparison).
addCount++;
// Gives a chance to other threads.
yield();
}
}
}
}
final WriterThread[] threads = new WriterThread[50];
for (int i = 0; i < threads.length; i++) threads[i] = new WriterThread(i);
for (int i = 0; i < threads.length; i++) threads[i].start();
for (int i = 0; i < threads.length; i++) threads[i].join();
TestUtilities.rethrownIfNotNull(failures.get());
/*
* Verifies the values.
*/
final Statistics beforeGC = validateStressEntries("Before GC", cache);
assertTrue("Should not have more entries than what we put in.", cache.size() <= count);
assertFalse("Some entries should be retained by strong references.", cache.isEmpty());
/*
* If verbose test output is enabled, report the number of cache hits.
* The numbers below are for tuning the test only. The output is somewhat
* random so we can not check it in a test suite. However if the test is
* properly tuned, most values should be non-zero.
*/
final PrintWriter out = CacheTest.out;
TestUtilities.printSeparator("CacheTest.stress() - testing concurrent accesses");
out.print("There is ");
out.print(threads.length);
out.print(" threads, each of them" + " fetching or creating ");
out.print(count);
out.println(" values.");
out.println("Number of times a new value has been created, for each thread:");
for (int i = 0; i < threads.length; ) {
final String n = String.valueOf(threads[i++].addCount);
out.print(CharSequences.spaces(6 - n.length()));
out.print(n);
if ((i % 10) == 0) {
out.println();
}
}
out.println();
out.println("Now observe how the background thread cleans the cache.");
long time = System.nanoTime();
for (int i = 0; i < 10; i++) {
final long t = System.nanoTime();
out.printf("Cache size: %4d (after %3d ms)%n", cache.size(), round((t - time) / (double) StandardDateFormat.NANOS_PER_MILLISECOND));
time = t;
Thread.sleep(250);
if (i >= 2) {
System.gc();
}
}
out.println();
/*
* Gets the statistics of key values after garbage collection. Most values should
* be higher, because oldest values (which should have been garbage collected first)
* have lower values. If verbose output is enabled, then we will print the statistics
* before to perform the actual check in order to allow the developer to have more
* information in case of failure.
*
* The mean value is often greater, but not always. Since we have fewer remaining values
* (100 instead of 10000), the remaining low values will have a much greater impact on
* the mean. Only the check on the minimal value is fully reliable.
*/
final Statistics afterGC = validateStressEntries("After GC", cache);
out.println("Statistics on the keys before and after garbage collection.");
out.println("The minimum value shall always be equals or greater after GC.");
out.println("The mean value is usually greater too, except by coincidence.");
final StatisticsFormat format = StatisticsFormat.getInstance();
format.setBorderWidth(1);
try {
format.format(new Statistics[] { beforeGC, afterGC }, out);
} catch (IOException e) {
throw new AssertionError(e);
}
assertTrue("Minimum key value should be greater after garbage collection.", afterGC.minimum() >= beforeGC.minimum());
}
Aggregations