blob: f026cd9ab6b374bd0fb4497e19cdf3267d4e88d7 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.ignite.loadtests.lang;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import org.apache.ignite.internal.util.typedef.C2;
import org.jsr166.ConcurrentLinkedHashMap;
/**
* Benchmark for different accessors in {@link org.jsr166.ConcurrentLinkedHashMap}.
*/
public class GridConcurrentLinkedHashMapBenchmark {
/** Number of keys to use in benchmark. */
private static final int KEY_RANGE = 1000;
/** Amount of writes from total number of iterations. */
private static final double WRITE_RATE = 0.2;
/**
* @param args Command-line arguments.
*/
public static void main(String[] args) {
System.out.printf("%8s, %8s, %12s, %12s, %12s, %8s, %8s\n",
"Method", "Threads", "It./s.", "It./s.*th.", "Iters.", "Time", "Writes");
for (int i = 1; i <= 32; i *= 2)
testGet(i, WRITE_RATE);
for (int i = 1; i <= 32; i *= 2)
testGetSafe(i, WRITE_RATE);
}
/**
* Tests {@link org.jsr166.ConcurrentLinkedHashMap#getSafe(Object)} method.
*
* @param threadCnt Number of threads to run.
* @param writeProportion Amount of writes from total number of iterations.
*/
public static void testGetSafe(int threadCnt, double writeProportion) {
test(new C2<Integer, ConcurrentLinkedHashMap<Integer, Integer>, Integer>() {
@Override public Integer apply(Integer key, ConcurrentLinkedHashMap<Integer, Integer> map) {
return map.getSafe(key);
}
@Override public String toString() {
return "getSafe";
}
}, threadCnt, writeProportion);
}
/**
* Tests {@link ConcurrentLinkedHashMap#get(Object)} method.
*
* @param threadCnt Number of threads to run.
* @param writeProportion Amount of writes from total number of iterations.
*/
public static void testGet(int threadCnt, double writeProportion) {
test(new C2<Integer, ConcurrentLinkedHashMap<Integer, Integer>, Integer>() {
@Override public Integer apply(Integer key, ConcurrentLinkedHashMap<Integer, Integer> map) {
return map.get(key);
}
@Override public String toString() {
return "get";
}
}, threadCnt, writeProportion);
}
/**
* Test a generic access method on map.
*
* @param readOp Access method to test.
* @param threadCnt Number of threads to run.
* @param writeProportion Amount of writes from total number of iterations.
*/
@SuppressWarnings({"BusyWait"})
private static void test(C2<Integer, ConcurrentLinkedHashMap<Integer, Integer>, Integer> readOp, int threadCnt,
double writeProportion) {
assert writeProportion < 1;
ConcurrentLinkedHashMap<Integer, Integer> map = new ConcurrentLinkedHashMap<>();
CyclicBarrier barrier = new CyclicBarrier(threadCnt + 1);
Collection<TestThread> threads = new ArrayList<>(threadCnt);
for (int i = 0; i < threadCnt; i++) {
TestThread thread = new TestThread(readOp, map, writeProportion, barrier);
threads.add(thread);
thread.start();
}
long start;
try {
// Wait threads warm-up.
while (barrier.getNumberWaiting() != threadCnt)
Thread.sleep(1);
// Starting test and letting it run for 1 minute.
barrier.await();
start = System.currentTimeMillis();
Thread.sleep(60000);
}
catch (InterruptedException ignored) {
return;
}
catch (BrokenBarrierException e) {
e.printStackTrace();
return;
}
for (TestThread th : threads)
th.interrupt();
try {
for (TestThread th : threads)
th.join();
}
catch (InterruptedException ignored) {
return;
}
long time = System.currentTimeMillis() - start;
long iters = 0;
for (TestThread th : threads)
iters += th.iterations();
System.out.printf(
"%8s, %8d, %12d, %12d, %12d, %8.3f, %8.2f\n",
readOp.toString(),
threadCnt,
1000 * iters / time,
1000 * iters / (time * threadCnt),
iters, time / (double)1000,
writeProportion
);
}
/**
* Test thread. Performs read/write operations on the given map
* with the given ration.
*/
private static class TestThread extends Thread {
/** */
private final C2<Integer, ConcurrentLinkedHashMap<Integer, Integer>, Integer> readOp;
/** */
private final ConcurrentLinkedHashMap<Integer, Integer> map;
/** */
private final double writeProportion;
/** */
private final CyclicBarrier barrier;
/** */
private final Random rnd = new Random();
/** Number of passed run iterations. */
private long iterations;
/**
* @param readOp Read operation to test.
* @param map Map to test.
* @param writeProportion Amount of writes from total number of iterations.
* @param barrier Barrier to await before starting 'clear' run.
*/
TestThread(final C2<Integer, ConcurrentLinkedHashMap<Integer, Integer>, Integer> readOp,
ConcurrentLinkedHashMap<Integer, Integer> map, double writeProportion, CyclicBarrier barrier) {
this.readOp = readOp;
this.map = map;
this.writeProportion = writeProportion;
this.barrier = barrier;
}
/** {@inheritDoc} */
@Override public void run() {
for (int i = 0; i < 1000000; i++)
doIteration();
try {
barrier.await();
}
catch (InterruptedException ignored) {
return;
}
catch (BrokenBarrierException e) {
e.printStackTrace();
return;
}
while (!interrupted()) {
doIteration();
iterations++;
}
}
/**
* Performs test iteration.
*/
private void doIteration() {
Integer key = rnd.nextInt(KEY_RANGE);
if (rnd.nextDouble() <= writeProportion)
map.put(key, rnd.nextInt());
else
readOp.apply(key, map);
}
/**
* @return Number of passes iterations.
*/
public long iterations() {
return iterations;
}
}
}