/*
* Copyright 2015 Goldman Sachs.
*
* Licensed 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 com.gs.collections.impl.parallel;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import com.gs.collections.api.block.function.Function;
import com.gs.collections.api.block.function.Function0;
import com.gs.collections.api.block.predicate.Predicate;
import com.gs.collections.api.block.procedure.Procedure;
import com.gs.collections.api.block.procedure.primitive.IntProcedure;
import com.gs.collections.api.list.MutableList;
import com.gs.collections.api.map.MutableMap;
import com.gs.collections.impl.ParallelTests;
import com.gs.collections.impl.block.factory.IntegerPredicates;
import com.gs.collections.impl.block.factory.Predicates;
import com.gs.collections.impl.block.factory.Procedures;
import com.gs.collections.impl.list.Interval;
import com.gs.collections.impl.list.mutable.FastList;
import com.gs.collections.impl.list.primitive.IntInterval;
import com.gs.collections.impl.map.mutable.ConcurrentHashMap;
import com.gs.collections.impl.set.mutable.UnifiedSet;
import com.gs.collections.impl.test.Verify;
import com.gs.collections.impl.utility.Iterate;
import org.apache.commons.lang.RandomStringUtils;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@SuppressWarnings("Convert2MethodRef")
public class SerialParallelLazyPerformanceTest
{
public static final MutableList<Predicate<Integer>> PREDICATES_LAMBDA = FastList.newListWith(
item -> item > 0 && (item & 1) != 0,
item -> item > 0 && (item & 1) == 0,
item -> item < 0 && (item & 1) != 0,
item -> item > 1000000);
public static final MutableList<Predicate<Integer>> PREDICATES_METHOD_REF = FastList.newListWith(
SerialParallelLazyPerformanceTest::isPositiveAndEven,
SerialParallelLazyPerformanceTest::isPositiveAndEven,
SerialParallelLazyPerformanceTest::isNegativeAndOdd,
SerialParallelLazyPerformanceTest::isGreaterThanMillion);
public static final MutableList<java.util.function.Predicate<Integer>> JAVA_PREDICATES_LAMBDA = FastList.newListWith(
item -> item > 0 && (item & 1) != 0,
item -> item > 0 && (item & 1) == 0,
item -> item < 0 && (item & 1) != 0,
item -> item > 1000000);
public static final MutableList<java.util.function.Predicate<Integer>> JAVA_PREDICATES_METHOD_REF = FastList.newListWith(
SerialParallelLazyPerformanceTest::isPositiveAndEven,
SerialParallelLazyPerformanceTest::isPositiveAndEven,
SerialParallelLazyPerformanceTest::isNegativeAndOdd,
SerialParallelLazyPerformanceTest::isGreaterThanMillion);
public static final Predicate<Integer> PREDICATE_1 = IntegerPredicates.isPositive().and(IntegerPredicates.isOdd());
public static final Predicate<Integer> PREDICATE_2 = IntegerPredicates.isPositive().and(IntegerPredicates.isEven());
public static final Predicate<Integer> PREDICATE_3 = IntegerPredicates.isNegative().and(IntegerPredicates.isOdd());
public static final Predicate<Integer> PREDICATE_4 = Predicates.greaterThan(1000000);
public static final MutableList<Predicate<Integer>> PREDICATES = FastList.newListWith(PREDICATE_1, PREDICATE_2, PREDICATE_3, PREDICATE_4);
public static final java.util.function.Predicate<Integer> JAVA_PREDICATE_1 = new java.util.function.Predicate<Integer>()
{
@Override
public boolean test(Integer item)
{
return item > 0 && (item & 1) != 0;
}
};
public static final java.util.function.Predicate<Integer> JAVA_PREDICATE_2 = new java.util.function.Predicate<Integer>()
{
@Override
public boolean test(Integer item)
{
return item > 0 && (item & 1) == 0;
}
};
public static final java.util.function.Predicate<Integer> JAVA_PREDICATE_3 = new java.util.function.Predicate<Integer>()
{
@Override
public boolean test(Integer item)
{
return item < 0 && (item & 1) != 0;
}
};
public static final java.util.function.Predicate<Integer> JAVA_PREDICATE_4 = new java.util.function.Predicate<Integer>()
{
@Override
public boolean test(Integer item)
{
return item > 1000000;
}
};
public static final MutableList<java.util.function.Predicate<Integer>> JAVA_PREDICATES = FastList.newListWith(JAVA_PREDICATE_1, JAVA_PREDICATE_2, JAVA_PREDICATE_3, JAVA_PREDICATE_4);
public static final Function<Integer, ?> LONG_FUNCTION = new Function<Integer, Long>()
{
@Override
public Long valueOf(Integer value)
{
return value.longValue();
}
};
public static final Function<Integer, ?> SHORT_FUNCTION = new Function<Integer, Short>()
{
@Override
public Short valueOf(Integer value)
{
return value.shortValue();
}
};
public static final java.util.function.Function<Integer, ?> JAVA_LONG_FUNCTION = new java.util.function.Function<Integer, Long>()
{
@Override
public Long apply(Integer value)
{
return value.longValue();
}
};
public static final java.util.function.Function<Integer, ?> JAVA_SHORT_FUNCTION = new java.util.function.Function<Integer, Short>()
{
@Override
public Short apply(Integer value)
{
return value.shortValue();
}
};
public static final MutableList<Function<Integer, ?>> FUNCTIONS = FastList.newListWith(LONG_FUNCTION, SHORT_FUNCTION);
public static final MutableList<java.util.function.Function<Integer, ?>> JAVA_FUNCTIONS = FastList.newListWith(JAVA_LONG_FUNCTION, JAVA_SHORT_FUNCTION);
public static final MutableList<Function<Integer, ?>> FUNCTIONS_LAMBDA = FastList.newListWith(
value -> value.longValue(),
value -> value.shortValue());
public static final MutableList<java.util.function.Function<Integer, ?>> JAVA_FUNCTIONS_LAMBDA = FastList.newListWith(
value -> value.longValue(),
value -> value.shortValue());
public static final MutableList<Function<Integer, ?>> FUNCTIONS_METHOD_REF = FastList.newListWith(
Integer::longValue,
Integer::shortValue);
public static final MutableList<java.util.function.Function<Integer, ?>> JAVA_FUNCTIONS_METHOD_REF = FastList.newListWith(
Integer::longValue,
Integer::shortValue);
private static final Function<String, Alphagram> ALPHAGRAM_LAMBDA = value -> new Alphagram(value);
private static final java.util.function.Function<String, Alphagram> JAVA_ALPHAGRAM_LAMBDA = value -> new Alphagram(value);
private static final Function<String, Alphagram> ALPHAGRAM_FUNCTION = new Function<String, Alphagram>()
{
@Override
public Alphagram valueOf(String each)
{
return new Alphagram(each);
}
};
private static final java.util.function.Function<String, Alphagram> JAVA_ALPHAGRAM_FUNCTION = new java.util.function.Function<String, Alphagram>()
{
@Override
public Alphagram apply(String each)
{
return new Alphagram(each);
}
};
private static final Function<String, Alphagram> ALPHAGRAM_METHOD_REF = Alphagram::new;
private static final java.util.function.Function<String, Alphagram> JAVA_ALPHAGRAM_METHOD_REF = Alphagram::new;
private static final Logger LOGGER = LoggerFactory.getLogger(SerialParallelLazyPerformanceTest.class);
private static final int SCALE_FACTOR = Integer.parseInt(System.getProperty("scaleFactor", "100"));
private static final int WARM_UP_COUNT = Integer.parseInt(System.getProperty("WarmupCount", "100"));
private static final int PARALLEL_RUN_COUNT = Integer.parseInt(System.getProperty("ParallelRunCount", "200"));
private static final int SERIAL_RUN_COUNT = Integer.parseInt(System.getProperty("SerialRunCount", "200"));
private static final int SMALL_COUNT = 100 * SCALE_FACTOR;
private static final int MEDIUM_COUNT = 1000 * SCALE_FACTOR;
private static final int LARGE_COUNT = 10000 * SCALE_FACTOR;
private static boolean isPositiveAndEven(Integer item)
{
return item > 0 && (item & 1) == 0;
}
private static boolean isNegativeAndOdd(Integer item)
{
return item < 0 && (item & 1) != 0;
}
private static boolean isGreaterThanMillion(Integer item)
{
return item > 1000000;
}
@Before
public void setup()
{
Procedure<java.util.function.Function<Integer, ?>> applyConsumer = each -> each.apply(0);
JAVA_FUNCTIONS.forEach(applyConsumer);
JAVA_FUNCTIONS_LAMBDA.forEach(applyConsumer);
JAVA_FUNCTIONS_METHOD_REF.forEach(applyConsumer);
JAVA_ALPHAGRAM_FUNCTION.apply("test");
JAVA_ALPHAGRAM_LAMBDA.apply("test");
JAVA_ALPHAGRAM_METHOD_REF.apply("test");
Procedure<java.util.function.Predicate<Integer>> applyPredicate = each -> each.test(0);
JAVA_PREDICATES.forEach(applyPredicate);
JAVA_PREDICATES_LAMBDA.forEach(applyPredicate);
JAVA_PREDICATES_METHOD_REF.forEach(applyPredicate);
}
@Test
@Category(ParallelTests.class)
public void forEach()
{
this.measureAlgorithmForIntegerIterable("forEach", each -> this.forEach(each.value()), true);
}
@Test
@Category(ParallelTests.class)
public void toList()
{
this.measureAlgorithmForIntegerIterable("toList", each -> this.toList(each.value()), true);
}
@Test
@Category(ParallelTests.class)
public void select()
{
this.measureAlgorithmForIntegerIterable("Select", each -> this.select(each.value()), true);
}
@Test
@Category(ParallelTests.class)
public void reject()
{
this.measureAlgorithmForIntegerIterable("Reject", each -> this.reject(each.value()), true);
}
@Test
@Category(ParallelTests.class)
public void anySatisfyShortCircuitInBeginning()
{
this.measureAlgorithmForIntegerIterable("AnySatisfy Short Circuit In The Beginning", each -> this.anySatisfy(each.value(), 2, true), false);
}
@Test
@Category(ParallelTests.class)
public void anySatisfyShortCircuitInMiddle()
{
this.measureAlgorithmForIntegerIterable(
"AnySatisfy Short Circuit In The Middle",
each -> this.anySatisfy(each.value(), 0, true),
false);
}
@Test
@Category(ParallelTests.class)
public void anySatisfyShortCircuitInEnd()
{
this.measureAlgorithmForIntegerIterable(
"AnySatisfy Short Circuit In The End",
each -> this.anySatisfy(each.value(), 3, false),
false);
}
@Test
@Category(ParallelTests.class)
public void detectShortCircuitInBeginning()
{
this.measureAlgorithmForIntegerIterable(
"Detect Short Circuit In The Beginning",
each -> this.detect(each.value(), 2, true),
false);
}
@Test
@Category(ParallelTests.class)
public void detectShortCircuitInMiddle()
{
this.measureAlgorithmForIntegerIterable(
"Detect Short Circuit In The Middle",
each -> this.detect(each.value(), 0, true),
false);
}
@Test
@Category(ParallelTests.class)
public void detectShortCircuitInEnd()
{
this.measureAlgorithmForIntegerIterable(
"Detect Short Circuit In The End",
each -> this.detect(each.value(), 3, false),
false);
}
@Test
@Category(ParallelTests.class)
public void collect()
{
this.measureAlgorithmForIntegerIterable("Collect", each -> this.collect(each.value()), true);
}
@Test
@Category(ParallelTests.class)
public void groupBy()
{
this.measureAlgorithmForRandomStringIterable("GroupBy", each -> this.groupBy(each.value()));
}
@After
public void tearDown()
{
SerialParallelLazyPerformanceTest.forceGC();
}
private static void forceGC()
{
IntInterval.oneTo(20).forEach((IntProcedure) each -> {
System.gc();
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
throw new RuntimeException(e);
}
});
}
public void printMachineAndTestConfiguration(String serialParallelAlgorithm)
{
LOGGER.info("*** Algorithm: {}", serialParallelAlgorithm);
LOGGER.info("Available Processors: {}", Runtime.getRuntime().availableProcessors());
LOGGER.info("Default Thread Pool Size: {}", ParallelIterate.getDefaultMaxThreadPoolSize());
LOGGER.info("Default Task Count: {}", ParallelIterate.getDefaultTaskCount());
LOGGER.info("Scale Factor: {}", SCALE_FACTOR);
LOGGER.info("Warm up count: {}", WARM_UP_COUNT);
LOGGER.info("Parallel Run Count: {}", PARALLEL_RUN_COUNT);
LOGGER.info("Serial** Run Count: {}", SERIAL_RUN_COUNT);
}
private MutableList<Integer> getSizes()
{
MutableList<Integer> sizes = FastList.newListWith(LARGE_COUNT, MEDIUM_COUNT, SMALL_COUNT);
return sizes.shuffleThis();
}
private MutableList<Function0<FastList<Integer>>> getIntegerListGenerators(int count, boolean shuffle)
{
Interval interval = Interval.fromTo(-(count / 2), count / 2 - 1);
MutableList<Function0<FastList<Integer>>> generators = FastList.newList();
generators.add(() -> {
FastList<Integer> integers = FastList.newList(interval);
if (shuffle)
{
integers.shuffleThis();
}
return integers;
});
return generators.shuffleThis();
}
private void measureAlgorithmForIntegerIterable(String algorithmName, Procedure<Function0<FastList<Integer>>> algorithm, boolean shuffle)
{
this.printMachineAndTestConfiguration(algorithmName);
for (int i = 0; i < 4; i++)
{
this.getSizes().forEach(Procedures.cast(count -> this.getIntegerListGenerators(count, shuffle).forEach(algorithm)));
}
}
private MutableList<Function0<UnifiedSet<String>>> getRandomWordsGenerators(int count)
{
MutableList<Function0<UnifiedSet<String>>> generators = FastList.newList();
generators.add(() -> this.generateWordsList(count));
return generators;
}
public UnifiedSet<String> generateWordsList(int count)
{
UnifiedSet<String> words = UnifiedSet.newSet();
while (words.size() < count)
{
words.add(RandomStringUtils.randomAlphabetic(5));
}
return words;
}
private void measureAlgorithmForRandomStringIterable(String algorithmName, Procedure<Function0<UnifiedSet<String>>> algorithm)
{
this.printMachineAndTestConfiguration(algorithmName);
for (int i = 0; i < 4; i++)
{
this.getSizes().forEach(Procedures.cast(count -> this.getRandomWordsGenerators(count).forEach(algorithm)));
}
}
private void shuffleAndRun(MutableList<Runnable> runnables)
{
runnables.shuffleThis();
runnables.forEach(Procedures.cast(Runnable::run));
}
private void forEach(FastList<Integer> collection)
{
MutableList<Runnable> runnables = FastList.newList();
runnables.add(() -> this.basicSerialForEachPerformance(collection, SERIAL_RUN_COUNT));
int cores = Runtime.getRuntime().availableProcessors();
ExecutorService service = Executors.newFixedThreadPool(cores);
runnables.add(() -> {
MutableMap<Integer, Boolean> map = new ConcurrentHashMap<>();
this.basicParallelLazyForEachPerformance(collection, "Lambda", item -> map.put(item, Boolean.TRUE), PARALLEL_RUN_COUNT, cores, service);
});
runnables.add(() -> {
MutableMap<Integer, Boolean> map = new ConcurrentHashMap<>();
this.basicParallelLazyForEachPerformance(collection, "Procedure", new Procedure<Integer>()
{
@Override
public void value(Integer each)
{
map.put(each, Boolean.TRUE);
}
}, PARALLEL_RUN_COUNT, cores, service);
});
runnables.add(() -> {
MutableMap<Integer, Boolean> map = new ConcurrentHashMap<>();
this.basicJava8ParallelLazyForEachPerformance(collection, "Lambda", item -> map.put(item, Boolean.TRUE), PARALLEL_RUN_COUNT);
});
List<Integer> arrayList = new ArrayList<>(collection);
runnables.add(() -> {
MutableMap<Integer, Boolean> map = new ConcurrentHashMap<>();
this.basicJava8ParallelLazyForEachPerformance(arrayList, "Lambda", item -> map.put(item, Boolean.TRUE), PARALLEL_RUN_COUNT);
});
runnables.add(() -> {
MutableMap<Integer, Boolean> map = new ConcurrentHashMap<>();
this.basicJava8ParallelLazyForEachPerformance(arrayList, "Consumer", new Consumer<Integer>()
{
@Override
public void accept(Integer each)
{
map.put(each, Boolean.TRUE);
}
}, PARALLEL_RUN_COUNT);
});
this.shuffleAndRun(runnables);
service.shutdown();
try
{
service.awaitTermination(1, TimeUnit.MINUTES);
}
catch (InterruptedException e)
{
throw new RuntimeException(e);
}
}
private void toList(FastList<Integer> collection)
{
MutableList<Runnable> runnables = FastList.newList();
runnables.add(() -> this.basicSerialToListPerformance(collection, SERIAL_RUN_COUNT));
int cores = Runtime.getRuntime().availableProcessors();
ExecutorService service = Executors.newFixedThreadPool(cores);
runnables.add(() -> this.basicParallelLazyToListPerformance(collection, PARALLEL_RUN_COUNT, cores, service));
runnables.add(() -> this.basicJava8ParallelLazyToListPerformance(collection, PARALLEL_RUN_COUNT));
List<Integer> arrayList = new ArrayList<>(collection);
runnables.add(() -> this.basicJava8ParallelLazyToListPerformance(arrayList, PARALLEL_RUN_COUNT));
this.shuffleAndRun(runnables);
service.shutdown();
try
{
service.awaitTermination(1, TimeUnit.MINUTES);
}
catch (InterruptedException e)
{
throw new RuntimeException(e);
}
}
private void select(FastList<Integer> collection)
{
MutableList<Runnable> runnables = FastList.newList();
runnables.add(() -> this.basicSerialSelectPerformance(collection, PREDICATES_LAMBDA, SERIAL_RUN_COUNT));
int cores = Runtime.getRuntime().availableProcessors();
ExecutorService service = Executors.newFixedThreadPool(cores);
runnables.add(() -> this.basicParallelLazySelectPerformance(collection, "Lambda", PREDICATES_LAMBDA, PARALLEL_RUN_COUNT, cores, service));
runnables.add(() -> this.basicParallelLazySelectPerformance(collection, "Predicate", PREDICATES, PARALLEL_RUN_COUNT, cores, service));
runnables.add(() -> this.basicParallelLazySelectPerformance(collection, "MethodRef", PREDICATES_METHOD_REF, PARALLEL_RUN_COUNT, cores, service));
runnables.add(() -> this.basicJava8ParallelLazySelectPerformance(collection, "Lambda", JAVA_PREDICATES_LAMBDA, PARALLEL_RUN_COUNT));
List<Integer> arrayList = new ArrayList<>(collection);
runnables.add(() -> this.basicJava8ParallelLazySelectPerformance(arrayList, "Lambda", JAVA_PREDICATES_LAMBDA, PARALLEL_RUN_COUNT));
runnables.add(() -> this.basicJava8ParallelLazySelectPerformance(arrayList, "Predicate", JAVA_PREDICATES, PARALLEL_RUN_COUNT));
runnables.add(() -> this.basicJava8ParallelLazySelectPerformance(arrayList, "MethodRef", JAVA_PREDICATES_METHOD_REF, PARALLEL_RUN_COUNT));
this.shuffleAndRun(runnables);
service.shutdown();
try
{
service.awaitTermination(1, TimeUnit.MINUTES);
}
catch (InterruptedException e)
{
throw new RuntimeException(e);
}
}
private void reject(FastList<Integer> collection)
{
MutableList<Runnable> runnables = FastList.newList();
runnables.add(() -> this.basicSerialRejectPerformance(collection, PREDICATES_LAMBDA, SERIAL_RUN_COUNT));
int cores = Runtime.getRuntime().availableProcessors();
ExecutorService service = Executors.newFixedThreadPool(cores);
runnables.add(() -> this.basicParallelLazyRejectPerformance(collection, "Lambda", PREDICATES_LAMBDA, PARALLEL_RUN_COUNT, cores, service));
runnables.add(() -> this.basicParallelLazyRejectPerformance(collection, "Predicate", PREDICATES, PARALLEL_RUN_COUNT, cores, service));
runnables.add(() -> this.basicParallelLazyRejectPerformance(collection, "MethodRef", PREDICATES_METHOD_REF, PARALLEL_RUN_COUNT, cores, service));
runnables.add(() -> this.basicJava8ParallelLazyRejectPerformance(collection, "Lambda", JAVA_PREDICATES_LAMBDA, PARALLEL_RUN_COUNT));
List<Integer> arrayList = new ArrayList<>(collection);
runnables.add(() -> this.basicJava8ParallelLazyRejectPerformance(arrayList, "Lambda", JAVA_PREDICATES_LAMBDA, PARALLEL_RUN_COUNT));
runnables.add(() -> this.basicJava8ParallelLazyRejectPerformance(arrayList, "Predicate", JAVA_PREDICATES, PARALLEL_RUN_COUNT));
runnables.add(() -> this.basicJava8ParallelLazyRejectPerformance(arrayList, "MethodRef", JAVA_PREDICATES_METHOD_REF, PARALLEL_RUN_COUNT));
this.shuffleAndRun(runnables);
service.shutdown();
try
{
service.awaitTermination(1, TimeUnit.MINUTES);
}
catch (InterruptedException e)
{
throw new RuntimeException(e);
}
}
private void anySatisfy(FastList<Integer> collection, int index, boolean expectedResult)
{
MutableList<Runnable> runnables = FastList.newList();
runnables.add(() -> this.basicSerialAnySatisfyPerformance(collection, PREDICATES_LAMBDA.get(index), expectedResult, SERIAL_RUN_COUNT));
int cores = Runtime.getRuntime().availableProcessors();
ExecutorService service = Executors.newFixedThreadPool(cores);
runnables.add(() -> this.basicParallelLazyAnySatisfyPerformance(collection, PREDICATES_LAMBDA.get(index), "Lambda", expectedResult, PARALLEL_RUN_COUNT, cores, service));
runnables.add(() -> this.basicParallelLazyAnySatisfyPerformance(collection, PREDICATES.get(index), "Predicate", expectedResult, PARALLEL_RUN_COUNT, cores, service));
runnables.add(() -> this.basicParallelLazyAnySatisfyPerformance(collection, PREDICATES_METHOD_REF.get(index), "MethodRef", expectedResult, PARALLEL_RUN_COUNT, cores, service));
runnables.add(() -> this.basicJava8ParallelLazyAnySatisfyPerformance(collection, "Lambda", JAVA_PREDICATES_LAMBDA.get(index), expectedResult, PARALLEL_RUN_COUNT));
List<Integer> arrayList = new ArrayList<>(collection);
runnables.add(() -> this.basicJava8ParallelLazyAnySatisfyPerformance(arrayList, "Lambda", JAVA_PREDICATES_LAMBDA.get(index), expectedResult, PARALLEL_RUN_COUNT));
runnables.add(() -> this.basicJava8ParallelLazyAnySatisfyPerformance(arrayList, "Predicate", JAVA_PREDICATES.get(index), expectedResult, PARALLEL_RUN_COUNT));
runnables.add(() -> this.basicJava8ParallelLazyAnySatisfyPerformance(arrayList, "MethodRef", JAVA_PREDICATES_METHOD_REF.get(index), expectedResult, PARALLEL_RUN_COUNT));
this.shuffleAndRun(runnables);
service.shutdown();
try
{
service.awaitTermination(1, TimeUnit.MINUTES);
}
catch (InterruptedException e)
{
throw new RuntimeException(e);
}
}
private void detect(FastList<Integer> collection, int index, boolean expectedResult)
{
MutableList<Runnable> runnables = FastList.newList();
runnables.add(() -> this.basicSerialDetectPerformance(collection, PREDICATES_LAMBDA.get(index), expectedResult, SERIAL_RUN_COUNT));
int cores = Runtime.getRuntime().availableProcessors();
ExecutorService service = Executors.newFixedThreadPool(cores);
runnables.add(() -> this.basicParallelLazyDetectPerformance(collection, PREDICATES_LAMBDA.get(index), "Lambda", expectedResult, PARALLEL_RUN_COUNT, cores, service));
runnables.add(() -> this.basicParallelLazyDetectPerformance(collection, PREDICATES.get(index), "Predicate", expectedResult, PARALLEL_RUN_COUNT, cores, service));
runnables.add(() -> this.basicParallelLazyDetectPerformance(collection, PREDICATES_METHOD_REF.get(index), "MethodRef", expectedResult, PARALLEL_RUN_COUNT, cores, service));
this.shuffleAndRun(runnables);
service.shutdown();
try
{
service.awaitTermination(1, TimeUnit.MINUTES);
}
catch (InterruptedException e)
{
throw new RuntimeException(e);
}
}
private void collect(FastList<Integer> collection)
{
MutableList<Runnable> runnables = FastList.newList();
runnables.add(() -> this.basicSerialCollectPerformance(collection, SERIAL_RUN_COUNT));
int cores = Runtime.getRuntime().availableProcessors();
ExecutorService service = Executors.newFixedThreadPool(cores);
runnables.add(() -> this.basicParallelLazyCollectPerformance(collection, "Lambda", FUNCTIONS_LAMBDA, PARALLEL_RUN_COUNT, cores, service));
runnables.add(() -> this.basicParallelLazyCollectPerformance(collection, "Function", FUNCTIONS, PARALLEL_RUN_COUNT, cores, service));
runnables.add(() -> this.basicParallelLazyCollectPerformance(collection, "MethodRef", FUNCTIONS_METHOD_REF, PARALLEL_RUN_COUNT, cores, service));
runnables.add(() -> this.basicJava8ParallelLazyCollectPerformance(collection, "Lambda", JAVA_FUNCTIONS_LAMBDA, PARALLEL_RUN_COUNT));
List<Integer> arrayList = new ArrayList<>(collection);
runnables.add(() -> this.basicJava8ParallelLazyCollectPerformance(arrayList, "Lambda", JAVA_FUNCTIONS_LAMBDA, PARALLEL_RUN_COUNT));
runnables.add(() -> this.basicJava8ParallelLazyCollectPerformance(arrayList, "Function", JAVA_FUNCTIONS, PARALLEL_RUN_COUNT));
runnables.add(() -> this.basicJava8ParallelLazyCollectPerformance(arrayList, "MethodRef", JAVA_FUNCTIONS_METHOD_REF, PARALLEL_RUN_COUNT));
this.shuffleAndRun(runnables);
service.shutdown();
try
{
service.awaitTermination(1, TimeUnit.MINUTES);
}
catch (InterruptedException e)
{
throw new RuntimeException(e);
}
}
private void groupBy(UnifiedSet<String> words)
{
MutableList<Runnable> runnables = FastList.newList();
runnables.add(() -> this.basicSerialGroupByPerformance(words, SERIAL_RUN_COUNT));
int cores = Runtime.getRuntime().availableProcessors();
ExecutorService service = Executors.newFixedThreadPool(cores);
runnables.add(() -> this.basicParallelLazyGroupByPerformance(words, "Lambda", ALPHAGRAM_LAMBDA, PARALLEL_RUN_COUNT, cores, service));
runnables.add(() -> this.basicParallelLazyGroupByPerformance(words, "Function", ALPHAGRAM_FUNCTION, PARALLEL_RUN_COUNT, cores, service));
runnables.add(() -> this.basicParallelLazyGroupByPerformance(words, "MethodRef", ALPHAGRAM_METHOD_REF, PARALLEL_RUN_COUNT, cores, service));
runnables.add(() -> this.basicParallelLazyJava8GroupByPerformance(words, "Lambda", JAVA_ALPHAGRAM_LAMBDA, PARALLEL_RUN_COUNT));
Set<String> hashSet = new HashSet<>(words);
runnables.add(() -> this.basicParallelLazyJava8GroupByPerformance(hashSet, "Lambda", JAVA_ALPHAGRAM_LAMBDA, PARALLEL_RUN_COUNT));
runnables.add(() -> this.basicParallelLazyJava8GroupByPerformance(hashSet, "Function", JAVA_ALPHAGRAM_FUNCTION, PARALLEL_RUN_COUNT));
runnables.add(() -> this.basicParallelLazyJava8GroupByPerformance(hashSet, "MethodRef", JAVA_ALPHAGRAM_METHOD_REF, PARALLEL_RUN_COUNT));
this.shuffleAndRun(runnables);
service.shutdown();
try
{
service.awaitTermination(1, TimeUnit.MINUTES);
}
catch (InterruptedException e)
{
throw new RuntimeException(e);
}
}
private double basicSerialToListPerformance(
FastList<Integer> iterable,
int count)
{
return TimeKeeper.logAverageMillisecondsToRun("Serial******* toList: "
+ this.getSimpleName(iterable)
+ " size: "
+ this.formatSizeOf(iterable) + " cores: 1", () -> Verify.assertNotEmpty(iterable.toList()), count, WARM_UP_COUNT);
}
private double basicSerialForEachPerformance(
FastList<Integer> iterable,
int count)
{
MutableMap<Integer, Boolean> map = new ConcurrentHashMap<>();
return TimeKeeper.logAverageMillisecondsToRun("Serial******* ForEach using: Lambda"
+ this.getSimpleName(iterable)
+ " size: "
+ this.formatSizeOf(iterable) + " cores: 1", () -> iterable.forEach((Procedure<Integer>) item -> map.put(item, Boolean.TRUE)), count, WARM_UP_COUNT);
}
private double basicSerialSelectPerformance(
FastList<Integer> iterable,
MutableList<Predicate<Integer>> predicateList,
int count)
{
return TimeKeeper.logAverageMillisecondsToRun("Serial******* Select using: Lambda "
+ this.getSimpleName(iterable)
+ " size: "
+ this.formatSizeOf(iterable) + " cores: 1", () -> {
Verify.assertNotEmpty(iterable.select(predicateList.get(0)).toList());
Verify.assertNotEmpty(iterable.select(predicateList.get(1)).toList());
Verify.assertNotEmpty(iterable.select(predicateList.get(2)).toList());
}, count, WARM_UP_COUNT);
}
private double basicSerialRejectPerformance(
FastList<Integer> iterable,
MutableList<Predicate<Integer>> predicateList,
int count)
{
return TimeKeeper.logAverageMillisecondsToRun("Serial******* Reject using: Lambda "
+ this.getSimpleName(iterable)
+ " size: "
+ this.formatSizeOf(iterable) + " cores: 1", () -> {
Verify.assertNotEmpty(iterable.reject(predicateList.get(0)).toList());
Verify.assertNotEmpty(iterable.reject(predicateList.get(1)).toList());
Verify.assertNotEmpty(iterable.reject(predicateList.get(2)).toList());
}, count, WARM_UP_COUNT);
}
private double basicSerialAnySatisfyPerformance(
FastList<Integer> iterable,
Predicate<? super Integer> predicate,
boolean expectedResult,
int count)
{
return TimeKeeper.logAverageMillisecondsToRun("Serial******* AnySatisfy using: Lambda "
+ this.getSimpleName(iterable)
+ " size: "
+ this.formatSizeOf(iterable) + " cores: 1", () -> Assert.assertEquals(expectedResult, iterable.anySatisfy(predicate)), count, WARM_UP_COUNT);
}
private double basicSerialDetectPerformance(
FastList<Integer> iterable,
Predicate<? super Integer> predicate,
boolean expectedResult,
int count)
{
return TimeKeeper.logAverageMillisecondsToRun("Serial******* Detect using: Lambda "
+ this.getSimpleName(iterable)
+ " size: "
+ this.formatSizeOf(iterable) + " cores: 1", () -> Assert.assertEquals(expectedResult, iterable.detect(predicate) != null), count, WARM_UP_COUNT);
}
private double basicSerialCollectPerformance(
FastList<Integer> iterable,
int count)
{
return TimeKeeper.logAverageMillisecondsToRun("Serial******* Collect using: Lambda "
+ this.getSimpleName(iterable)
+ " size: "
+ this.formatSizeOf(iterable) + " cores: 1", () -> {
Verify.assertNotEmpty(iterable.collect(value -> value.shortValue()).toList());
Verify.assertNotEmpty(iterable.collect(value -> value.longValue()).toList());
}, count, 10);
}
private double basicSerialGroupByPerformance(
UnifiedSet<String> iterable,
int count)
{
return TimeKeeper.logAverageMillisecondsToRun("Serial******* GroupBy using: Lambda "
+ this.getSimpleName(iterable)
+ " size: "
+ this.formatSizeOf(iterable) + " cores: 1", () -> Verify.assertNotEmpty(iterable.groupBy(ALPHAGRAM_LAMBDA)), count, 10);
}
private String formatSizeOf(Iterable<?> iterable)
{
return NumberFormat.getInstance().format(Iterate.sizeOf(iterable));
}
private static int getBatchSizeFor(Collection<?> iterable)
{
return iterable.size() == 1000000 ? 10000 : 1000;
}
private double basicParallelLazyForEachPerformance(
FastList<Integer> iterable,
String parameterType,
Procedure<Integer> procedure,
int count,
int cores,
ExecutorService service)
{
return TimeKeeper.logAverageMillisecondsToRun("Parallel Lazy ForEach using: "
+ parameterType + ' '
+ this.getSimpleName(iterable)
+ " size: "
+ this.formatSizeOf(iterable) + " cores: " + cores, () -> iterable.asParallel(service, iterable.size() / (cores * 3)).forEach(procedure), count, WARM_UP_COUNT);
}
private double basicJava8ParallelLazyForEachPerformance(
List<Integer> iterable,
String parameterType,
Consumer<Integer> consumer,
int count)
{
return TimeKeeper.logAverageMillisecondsToRun("Parallel Java8 ForEach using: "
+ parameterType + ' '
+ this.getSimpleName(iterable)
+ " size: "
+ this.formatSizeOf(iterable) + " cores: ?", () -> iterable.parallelStream().forEach(consumer), count, WARM_UP_COUNT);
}
private double basicParallelLazyToListPerformance(
FastList<Integer> iterable,
int count,
int cores,
ExecutorService service)
{
return TimeKeeper.logAverageMillisecondsToRun("Parallel Lazy toList: "
+ this.getSimpleName(iterable)
+ " size: "
+ this.formatSizeOf(iterable) + " cores: " + cores, () -> Verify.assertSize(iterable.size(), iterable.asParallel(service, iterable.size() / (cores * 3)).toList()), count, WARM_UP_COUNT);
}
private double basicJava8ParallelLazyToListPerformance(
List<Integer> iterable,
int count)
{
return TimeKeeper.logAverageMillisecondsToRun("Parallel Java8 toList: "
+ this.getSimpleName(iterable)
+ " size: "
+ this.formatSizeOf(iterable) + " cores: ?", () -> Verify.assertSize(iterable.size(), iterable.parallelStream().collect(Collectors.toList())), count, WARM_UP_COUNT);
}
private double basicJava8ParallelLazySelectPerformance(
List<Integer> iterable,
String parameterType,
MutableList<java.util.function.Predicate<Integer>> predicatesList,
int count)
{
return TimeKeeper.logAverageMillisecondsToRun("Parallel Java8 Select using: "
+ parameterType
+ ' '
+ this.getSimpleName(iterable)
+ " size: "
+ this.formatSizeOf(iterable) + " cores: ?", () -> {
iterable.parallelStream().filter(predicatesList.get(0)).collect(Collectors.toList());
iterable.parallelStream().filter(predicatesList.get(1)).collect(Collectors.toList());
iterable.parallelStream().filter(predicatesList.get(2)).collect(Collectors.toList());
}, count, WARM_UP_COUNT);
}
private double basicParallelLazySelectPerformance(
FastList<Integer> iterable,
String parameterType,
MutableList<Predicate<Integer>> predicateList,
int count,
int cores,
ExecutorService service)
{
int batchSize = SerialParallelLazyPerformanceTest.getBatchSizeFor(iterable);
return TimeKeeper.logAverageMillisecondsToRun("Parallel Lazy Select using: "
+ parameterType
+ ' '
+ this.getSimpleName(iterable)
+ " size: "
+ this.formatSizeOf(iterable) + " cores: " + cores, () -> {
iterable.asParallel(service, batchSize).select(predicateList.get(0)).toList();
iterable.asParallel(service, batchSize).select(predicateList.get(1)).toList();
iterable.asParallel(service, batchSize).select(predicateList.get(2)).toList();
}, count, WARM_UP_COUNT);
}
private double basicParallelLazyRejectPerformance(
FastList<Integer> iterable,
String parameterType,
MutableList<Predicate<Integer>> predicateList,
int count,
int cores,
ExecutorService service)
{
int batchSize = SerialParallelLazyPerformanceTest.getBatchSizeFor(iterable);
return TimeKeeper.logAverageMillisecondsToRun("Parallel Lazy Reject using: "
+ parameterType
+ ' '
+ this.getSimpleName(iterable)
+ " size: "
+ this.formatSizeOf(iterable) + " cores: " + cores, () -> {
Verify.assertNotEmpty(iterable.asParallel(service, batchSize).reject(predicateList.get(0)).toList());
Verify.assertNotEmpty(iterable.asParallel(service, batchSize).reject(predicateList.get(1)).toList());
Verify.assertNotEmpty(iterable.asParallel(service, batchSize).reject(predicateList.get(2)).toList());
}, count, WARM_UP_COUNT);
}
private double basicJava8ParallelLazyRejectPerformance(
List<Integer> iterable,
String parameterType,
MutableList<java.util.function.Predicate<Integer>> predicateList,
int count)
{
return TimeKeeper.logAverageMillisecondsToRun("Parallel Java8 Reject using: "
+ parameterType
+ ' '
+ this.getSimpleName(iterable)
+ " size: "
+ this.formatSizeOf(iterable) + " cores: ?", () -> {
Verify.assertNotEmpty(iterable.parallelStream().filter(predicateList.get(0).negate()).collect(Collectors.toList()));
Verify.assertNotEmpty(iterable.parallelStream().filter(predicateList.get(1).negate()).collect(Collectors.toList()));
Verify.assertNotEmpty(iterable.parallelStream().filter(predicateList.get(2).negate()).collect(Collectors.toList()));
}, count, WARM_UP_COUNT);
}
private double basicParallelLazyAnySatisfyPerformance(
FastList<Integer> iterable,
Predicate<? super Integer> predicate,
String parameterType,
boolean expectedResult,
int count,
int cores,
ExecutorService service)
{
int batchSize = SerialParallelLazyPerformanceTest.getBatchSizeFor(iterable);
return TimeKeeper.logAverageMillisecondsToRun("Parallel Lazy AnySatisfy using: "
+ parameterType
+ ' '
+ this.getSimpleName(iterable)
+ " size: "
+ this.formatSizeOf(iterable) + " cores: " + cores, () -> Assert.assertEquals(expectedResult, iterable.asParallel(service, batchSize).anySatisfy(predicate)), count, WARM_UP_COUNT);
}
private double basicJava8ParallelLazyAnySatisfyPerformance(
List<Integer> iterable,
String parameterType,
java.util.function.Predicate<? super Integer> predicate,
boolean expectedResult,
int count)
{
return TimeKeeper.logAverageMillisecondsToRun("Parallel Java8 AnySatisfy using: "
+ parameterType
+ ' '
+ this.getSimpleName(iterable)
+ " size: "
+ this.formatSizeOf(iterable) + " cores: ?", () -> Assert.assertEquals(expectedResult, iterable.parallelStream().anyMatch(predicate)), count, WARM_UP_COUNT);
}
private double basicParallelLazyDetectPerformance(
FastList<Integer> iterable,
Predicate<? super Integer> predicate,
String parameterType,
boolean expectedResult,
int count,
int cores,
ExecutorService service)
{
int batchSize = SerialParallelLazyPerformanceTest.getBatchSizeFor(iterable);
return TimeKeeper.logAverageMillisecondsToRun("Parallel Lazy Detect using: "
+ parameterType
+ ' '
+ this.getSimpleName(iterable)
+ " size: "
+ this.formatSizeOf(iterable) + " cores: " + cores, () -> Assert.assertEquals(expectedResult, iterable.asParallel(service, batchSize).detect(predicate) != null), count, WARM_UP_COUNT);
}
private double basicParallelLazyCollectPerformance(
FastList<Integer> iterable,
String parameterType,
MutableList<Function<Integer, ?>> functionsList,
int count,
int cores,
ExecutorService service)
{
int batchSize = SerialParallelLazyPerformanceTest.getBatchSizeFor(iterable);
return TimeKeeper.logAverageMillisecondsToRun("Parallel Lazy Collect using: "
+ parameterType
+ ' '
+ this.getSimpleName(iterable)
+ " size: "
+ this.formatSizeOf(iterable) + " cores: " + cores, () -> {
Verify.assertNotEmpty(iterable.asParallel(service, batchSize).collect(functionsList.get(0)).toList());
Verify.assertNotEmpty(iterable.asParallel(service, batchSize).collect(functionsList.get(1)).toList());
}, count, 10);
}
private double basicJava8ParallelLazyCollectPerformance(
List<Integer> iterable,
String parameterType,
MutableList<java.util.function.Function<Integer, ?>> functionsList,
int count)
{
return TimeKeeper.logAverageMillisecondsToRun("Parallel Java8 Collect using: "
+ parameterType
+ ' '
+ this.getSimpleName(iterable)
+ " size: "
+ this.formatSizeOf(iterable) + " cores: ?", () -> {
Verify.assertNotEmpty(iterable.parallelStream().map(functionsList.get(0)).collect(Collectors.toList()));
Verify.assertNotEmpty(iterable.parallelStream().map(functionsList.get(1)).collect(Collectors.toList()));
}, count, 10);
}
private double basicParallelLazyGroupByPerformance(UnifiedSet<String> iterable,
String parameterType,
Function<String, Alphagram> function,
int count,
int cores,
ExecutorService service)
{
int batchSize = SerialParallelLazyPerformanceTest.getBatchSizeFor(iterable);
return TimeKeeper.logAverageMillisecondsToRun("Parallel Lazy GroupBy using: "
+ parameterType
+ ' '
+ this.getSimpleName(iterable)
+ " size: "
+ this.formatSizeOf(iterable) + " cores: " + cores, () -> Verify.assertNotEmpty(iterable.asParallel(service, batchSize).groupBy(function)), count, WARM_UP_COUNT);
}
private double basicParallelLazyJava8GroupByPerformance(Set<String> iterable,
String parameterType,
java.util.function.Function<String, Alphagram> function,
int count)
{
return TimeKeeper.logAverageMillisecondsToRun("Parallel Java8 GroupBy using: "
+ parameterType
+ ' '
+ this.getSimpleName(iterable)
+ " size: "
+ this.formatSizeOf(iterable) + " cores: ?", () -> Verify.assertNotEmpty(iterable.parallelStream().collect(Collectors.groupingBy(function))), count, WARM_UP_COUNT);
}
private String getSimpleName(Object collection)
{
return collection.getClass().getSimpleName();
}
static final class TimeKeeper
{
private static final SystemTimeProvider PROVIDER = new SystemTimeProvider();
private static final long PAIN_THRESHOLD = 10000L;
private static final int MILLIS_TO_NANOS = 1000000;
private TimeKeeper()
{
throw new AssertionError("Suppress default constructor for noninstantiability");
}
/**
* This method can take either a Runnable or a RunnableWithSetup. In the case of RunnableWithSetup, the setup
* method will be called first, without impacting the timing.
*/
public static long millisecondsToRun(Runnable runnable)
{
return TimeKeeper.nanosecondsToRun(runnable) / (long) MILLIS_TO_NANOS;
}
public static long currentTimeNanoseconds()
{
return PROVIDER.currentTimeNanoseconds();
}
public static long currentTimeMilliseconds()
{
return PROVIDER.currentTimeMilliseconds();
}
/**
* This method can take either a Runnable or a RunnableWithSetup. In the case of RunnableWithSetup, the setup
* method will be called first, without impacting the timing.
*/
public static long nanosecondsToRun(Runnable runnable)
{
long start = TimeKeeper.getCurrentTimeAsNanos();
runnable.run();
long end = TimeKeeper.getCurrentTimeAsNanos();
return end - start;
}
private static long getCurrentTimeAsNanos()
{
return TimeKeeper.currentTimeNanoseconds();
}
private static void doLog(String message, int count, long total, double average)
{
LOGGER.info("{} Count: {} Total(ms): {} Avg(ms): {}", message, count, TimeKeeper.longNanosToMillisString(total), TimeKeeper.doubleNanosToMillisString(average));
}
public static double logAverageMillisecondsToRun(
String message,
Runnable runnable,
int count)
{
long start = TimeKeeper.getCurrentTimeAsNanos();
for (int i = 0; i < count; i++)
{
runnable.run();
}
long totalNanos = TimeKeeper.getCurrentTimeAsNanos() - start;
double averageTime = (double) totalNanos / (double) count;
TimeKeeper.doLog(message, count, totalNanos, averageTime);
return averageTime / (double) TimeKeeper.MILLIS_TO_NANOS;
}
private static String doubleNanosToMillisString(double nanos)
{
return NumberFormat.getInstance().format(nanos / MILLIS_TO_NANOS);
}
private static String longNanosToMillisString(long nanos)
{
return NumberFormat.getInstance().format(nanos / MILLIS_TO_NANOS);
}
public static double logAverageMillisecondsToRun(
String message,
Runnable runnable,
int count,
int warmUpCount)
{
TimeKeeper.warmUp(warmUpCount, runnable);
TimeKeeper.gcAndYield();
return TimeKeeper.logAverageMillisecondsToRun(message, runnable, count);
}
private static void gcAndYield()
{
SerialParallelLazyPerformanceTest.forceGC();
}
private static void warmUp(int warmUpCount, Runnable runnable)
{
long start = TimeKeeper.currentTimeMilliseconds();
for (int i = 0; i < warmUpCount; i++)
{
TimeKeeper.millisecondsToRun(runnable);
if (TimeKeeper.currentTimeMilliseconds() - start > PAIN_THRESHOLD)
{
break;
}
}
}
private static class SystemTimeProvider
{
public long currentTimeMilliseconds()
{
return System.currentTimeMillis();
}
public long currentTimeNanoseconds()
{
return System.nanoTime();
}
}
}
private static final class Alphagram
{
private final char[] key;
private final int hashCode;
private Alphagram(String string)
{
this.key = string.toLowerCase().toCharArray();
Arrays.sort(this.key);
this.hashCode = Arrays.hashCode(this.key);
}
@Override
public boolean equals(Object o)
{
return this == o || Arrays.equals(this.key, ((Alphagram) o).key);
}
@Override
public int hashCode()
{
return this.hashCode;
}
@Override
public String toString()
{
return new String(this.key);
}
}
public static final class AtomicIntegerWithEquals extends AtomicInteger
{
private AtomicIntegerWithEquals(int initialValue)
{
super(initialValue);
}
@Override
public int hashCode()
{
return this.get();
}
@Override
public boolean equals(Object obj)
{
return (obj instanceof AtomicIntegerWithEquals) && ((AtomicIntegerWithEquals) obj).get() == this.get();
}
}
}