/* * Carrot2 project. * * Copyright (C) 2002-2016, Dawid Weiss, Stanisław Osiński. * All rights reserved. * * Refer to the full license file "carrot2.LICENSE" * in the root folder of the repository checkout or at: * http://www.carrot2.org/carrot2.LICENSE */ package org.carrot2.core; import java.util.*; import java.util.concurrent.*; import org.carrot2.core.attribute.Processing; import org.carrot2.util.attribute.*; import org.junit.*; import com.carrotsearch.junitbenchmarks.AbstractBenchmark; import com.carrotsearch.junitbenchmarks.BenchmarkOptions; import com.carrotsearch.junitbenchmarks.h2.*; import org.carrot2.shaded.guava.common.collect.Lists; import org.carrot2.shaded.guava.common.collect.Maps; /** * This class measures the overhead added by the {@link Controller} in various * configurations. Processing in the components is relatively simple, so what we're * attempting to measure here is the impact of extra processing and synchronizations * within the controller itself. */ @AxisRange(min = 0) @BenchmarkMethodChart(filePrefix = "individual") @BenchmarkHistoryChart(filePrefix = "history") @BenchmarkOptions(benchmarkRounds = 20, warmupRounds = 5) public class ControllerOverheadBenchmark extends AbstractBenchmark { // Controllers under tests static final Controller simpleController = ControllerFactory.createSimple(); static final Controller poolingController = ControllerFactory.createPooling(); static final Controller cachingOffController = ControllerFactory.createCaching(); static final Controller cachingOnController = ControllerFactory .createCaching(IProcessingComponent.class); static final Controller poolingCachingOffController = ControllerFactory .createCachingPooling(); static final Controller poolingCachingOnController = ControllerFactory .createCachingPooling(IProcessingComponent.class); // Test callables static final List<Map<String, Object>> processingAttributeMaps = Lists.newArrayList(); static final Map<String, List<Callable<String>>> callables = Maps.newHashMap(); // Executor static final ExecutorService executorService = Executors.newFixedThreadPool(20); static final int internalRounds = 100; @BeforeClass public static void prepareRunnables() { final Random random = new Random(0); for (int i = 0; i < 100; i++) { final Map<String, Object> attributes = Maps.newHashMap(); attributes.put("int1", random.nextInt(100)); attributes.put("int2", random.nextInt(100)); attributes.put("double1", random.nextDouble()); attributes.put("double2", random.nextDouble()); attributes.put("data", "a" + Integer.toString(random.nextInt(20 + random.nextInt(10)))); attributes.put("boolean1", random.nextBoolean()); attributes.put("boolean2", random.nextBoolean()); attributes.put("in1", null); processingAttributeMaps.add(attributes); } callables.put("simple", createCallables(simpleController)); callables.put("pooling", createCallables(poolingController)); callables.put("cachingOff", createCallables(cachingOffController)); callables.put("cachingOn", createCallables(cachingOnController)); callables.put("poolingCachingOff", createCallables(poolingCachingOffController)); callables.put("poolingCachingOn", createCallables(poolingCachingOnController)); } private static List<Callable<String>> createCallables(Controller controller) { final List<Callable<String>> callables = Lists.newArrayList(); for (int r = 0; r < internalRounds; r++) { for (Map<String, Object> attributes : processingAttributeMaps) { callables.add(createCallable(attributes, controller)); } } return callables; } private static Callable<String> createCallable(final Map<String, Object> attributes, final Controller controller) { return new Callable<String>() { public String call() throws Exception { return controller.process(attributes, ProcessingComponent1.class, ProcessingComponent2.class).getAttribute("result"); } }; } @AfterClass public static void disposeControllers() { simpleController.dispose(); poolingController.dispose(); cachingOffController.dispose(); cachingOnController.dispose(); poolingCachingOffController.dispose(); poolingCachingOnController.dispose(); } @AfterClass public static void shutDownExecutor() throws InterruptedException { executorService.shutdown(); executorService.awaitTermination(5, TimeUnit.SECONDS); } @Test public void testSimpleController() throws InterruptedException { testWithController("simple"); } @Test public void testPoolingController() throws InterruptedException { testWithController("pooling"); } @Test public void testCachingOnController() throws InterruptedException { testWithController("cachingOn"); } @Test public void testCachingOffController() throws InterruptedException { testWithController("cachingOff"); } @Test public void testPoolingCachingOnController() throws InterruptedException { testWithController("poolingCachingOff"); } @Test public void testPoolingCachingOffController() throws InterruptedException { testWithController("poolingCachingOff"); } private void testWithController(String controllerName) throws InterruptedException { executorService.invokeAll(callables.get(controllerName)); } @Bindable public static class ProcessingComponent1 extends ProcessingComponentBase { @Processing @Input @Attribute(key = "int1") public int int1 = 0; @Processing @Input @Attribute(key = "double1") public double double1 = 1.0; @Processing @Input @Output @Attribute(key = "data") public String string1; @Processing @Input @Attribute(key = "boolean1") public boolean boolean1 = false; @Processing @Input @Attribute(key = "in1") public List<String> inAttribute = new ArrayList<String>(); @Processing @Output @Attribute(key = "out2") public List<String> outAttribute = new ArrayList<String>(); @Processing @Output @Attribute(key = "debug2") public List<String> debugAttribute = new ArrayList<String>(); @Override public void process() throws ProcessingException { string1 += join("-", string1, int1, double1, boolean1); } } @Bindable public static class ProcessingComponent2 extends ProcessingComponentBase { @Processing @Input @Attribute(key = "int2") public int int2 = 0; @Processing @Input @Attribute(key = "double2") public double double2 = 1.0; @Processing @Input @Attribute(key = "data") public String string2; @Processing @Output @Attribute(key = "result") public String result; @Processing @Input @Attribute(key = "boolean2") public boolean boolean2 = false; @Processing @Input @Attribute(key = "in2") public List<String> inAttribute = new ArrayList<String>(); @Processing @Output @Attribute(key = "out2") public List<String> outAttribute = new ArrayList<String>(); @Processing @Output @Attribute(key = "debug2") public List<String> debugAttribute = new ArrayList<String>(); @Override public void process() throws ProcessingException { result = join("-", string2, int2, double2, boolean2); } } private static String join(String separator, Object... objects) { final StringBuilder b = new StringBuilder(objects[0].toString()); for (int i = 1; i < objects.length; i++) { b.append(separator); b.append(objects[i]); } return b.toString(); } }