/* * 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; } } }