/* * 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.jmh; import java.util.ArrayList; import java.util.Collection; 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.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; import com.gs.collections.api.bag.MutableBag; import com.gs.collections.api.list.MutableList; import com.gs.collections.api.set.MutableSet; import com.gs.collections.impl.bag.mutable.HashBag; import com.gs.collections.impl.jmh.runner.AbstractJMHTestRunner; import com.gs.collections.impl.list.Interval; import com.gs.collections.impl.list.mutable.CompositeFastList; import com.gs.collections.impl.list.mutable.FastList; import com.gs.collections.impl.parallel.ParallelIterate; import com.gs.collections.impl.set.mutable.UnifiedSet; import com.gs.collections.impl.test.Verify; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Warmup; @State(Scope.Thread) @BenchmarkMode(Mode.Throughput) @OutputTimeUnit(TimeUnit.SECONDS) public class FunctionalInterfaceTest extends AbstractJMHTestRunner { private static final int SIZE = 1_000_000; private static final int BATCH_SIZE = 10_000; @Param({"0", "1", "2", "3"}) public int megamorphicWarmupLevel; private final List<Integer> integersJDK = new ArrayList<>(Interval.oneTo(SIZE)); private final FastList<Integer> integersGSC = new FastList<>(Interval.oneTo(SIZE)); private ExecutorService executorService; @Before @Setup public void setUp() { this.executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); } @Before @Setup(Level.Trial) public void setUp_megamorphic() { this.setUp(); com.gs.collections.api.block.predicate.Predicate<Integer> predicate1 = each -> (each + 2) % 10_000 != 0; com.gs.collections.api.block.predicate.Predicate<Integer> predicate2 = each -> (each + 3) % 10_000 != 0; com.gs.collections.api.block.predicate.Predicate<Integer> predicate3 = each -> (each + 4) % 10_000 != 0; com.gs.collections.api.block.predicate.Predicate<Integer> predicate4 = each -> (each + 5) % 10_000 != 0; com.gs.collections.api.block.function.Function<Integer, String> function1 = each -> { Assert.assertNotNull(each); return String.valueOf(each); }; com.gs.collections.api.block.function.Function<String, Integer> function2 = each -> { Assert.assertNotNull(each); return Integer.valueOf(each); }; com.gs.collections.api.block.function.Function<Integer, String> function3 = each -> { Assert.assertSame(each, each); return String.valueOf(each); }; com.gs.collections.api.block.function.Function<String, Integer> function4 = each -> { Assert.assertSame(each, each); return Integer.valueOf(each); }; if (this.megamorphicWarmupLevel > 0) { Predicate<Integer> predicateJDK1 = each -> (each + 2) % 10_000 != 0; Predicate<Integer> predicateJDK2 = each -> (each + 3) % 10_000 != 0; Predicate<Integer> predicateJDK3 = each -> (each + 4) % 10_000 != 0; Predicate<Integer> predicateJDK4 = each -> (each + 5) % 10_000 != 0; Function<Integer, String> mapper1 = each -> { Assert.assertNotNull(each); return String.valueOf(each); }; Function<String, Integer> mapper2 = each -> { Assert.assertNotNull(each); return Integer.valueOf(each); }; Function<Integer, String> mapper3 = each -> { Assert.assertSame(each, each); return String.valueOf(each); }; Function<String, Integer> mapper4 = each -> { Assert.assertSame(each, each); return Integer.valueOf(each); }; // serial, lazy, JDK { Set<Integer> set = this.integersJDK.stream() .filter(predicateJDK1) .map(mapper1) .map(mapper2) .filter(predicateJDK2) .collect(Collectors.toSet()); Verify.assertSize(999_800, set); List<Integer> collection = this.integersJDK.stream() .filter(predicateJDK3) .map(mapper3) .map(mapper4) .filter(predicateJDK4) .collect(Collectors.toCollection(ArrayList::new)); Verify.assertSize(999_800, collection); } // parallel, lazy, JDK { Set<Integer> set = this.integersJDK.parallelStream() .filter(predicateJDK1) .map(mapper1) .map(mapper2) .filter(predicateJDK2) .collect(Collectors.toSet()); Verify.assertSize(999_800, set); List<Integer> collection = this.integersJDK.parallelStream() .filter(predicateJDK3) .map(mapper3) .map(mapper4) .filter(predicateJDK4) .collect(Collectors.toCollection(ArrayList::new)); Verify.assertSize(999_800, collection); } // serial, lazy, GSC { MutableSet<Integer> set = this.integersGSC.asLazy() .select(predicate1) .collect(function1) .collect(function2) .select(predicate2) .toSet(); Verify.assertSize(999_800, set); MutableBag<Integer> bag = this.integersGSC.asLazy() .select(predicate3) .collect(function3) .collect(function4) .select(predicate4) .toBag(); Verify.assertIterableSize(999_800, bag); } // parallel, lazy, GSC { MutableSet<Integer> set = this.integersGSC.asParallel(this.executorService, BATCH_SIZE) .select(predicate1) .collect(function1) .collect(function2) .select(predicate2) .toSet(); Verify.assertSize(999_800, set); MutableBag<Integer> bag = this.integersGSC.asParallel(this.executorService, BATCH_SIZE) .select(predicate3) .collect(function3) .collect(function4) .select(predicate4) .toBag(); Verify.assertIterableSize(999_800, bag); } // serial, eager, GSC MutableSet<Integer> set = this.integersGSC .select(predicate1) .collect(function1) .collect(function2) .select(predicate2) .toSet(); Verify.assertSize(999_800, set); MutableBag<Integer> bag = this.integersGSC .select(predicate3) .collect(function3) .collect(function4) .select(predicate4) .toBag(); Verify.assertIterableSize(999_800, bag); } if (this.megamorphicWarmupLevel > 1) { // parallel, eager, GSC Collection<Integer> select1 = ParallelIterate.select(this.integersGSC, predicate1, new UnifiedSet<>(), true); Collection<String> collect1 = ParallelIterate.collect(select1, function1, new UnifiedSet<>(), true); Collection<Integer> collect2 = ParallelIterate.collect(collect1, function2, new UnifiedSet<>(), true); UnifiedSet<Integer> set = ParallelIterate.select(collect2, predicate2, new UnifiedSet<>(), true); Verify.assertSize(999_800, set); Collection<Integer> select3 = ParallelIterate.select(this.integersGSC, predicate3, new HashBag<>(), true); Collection<String> collect3 = ParallelIterate.collect(select3, function3, new HashBag<>(), true); Collection<Integer> collect4 = ParallelIterate.collect(collect3, function4, new HashBag<>(), true); HashBag<Integer> bag = ParallelIterate.select(collect4, predicate4, new HashBag<>(), true); Verify.assertSize(999_800, bag); } if (this.megamorphicWarmupLevel > 2) { // parallel, eager, GSC, executorService UnifiedSet<Integer> select1 = ParallelIterate.select(this.integersGSC, predicate1, new UnifiedSet<>(), BATCH_SIZE, this.executorService, true); UnifiedSet<String> collect1 = ParallelIterate.collect(select1, function1, new UnifiedSet<>(), BATCH_SIZE, this.executorService, true); UnifiedSet<Integer> collect2 = ParallelIterate.collect(collect1, function2, new UnifiedSet<>(), BATCH_SIZE, this.executorService, true); UnifiedSet<Integer> set = ParallelIterate.select(collect2, predicate2, new UnifiedSet<>(), BATCH_SIZE, this.executorService, true); Verify.assertSize(999_800, set); HashBag<Integer> select3 = ParallelIterate.select(this.integersGSC, predicate3, new HashBag<>(), BATCH_SIZE, this.executorService, true); HashBag<String> collect3 = ParallelIterate.collect(select3, function3, new HashBag<>(), BATCH_SIZE, this.executorService, true); HashBag<Integer> collect4 = ParallelIterate.collect(collect3, function4, new HashBag<>(), BATCH_SIZE, this.executorService, true); HashBag<Integer> bag = ParallelIterate.select(collect4, predicate4, new HashBag<>(), BATCH_SIZE, this.executorService, true); Verify.assertSize(999_800, bag); } FunctionalInterfaceScalaTest.megamorphic(this.megamorphicWarmupLevel); } @After @TearDown public void tearDown() throws InterruptedException { this.executorService.shutdownNow(); this.executorService.awaitTermination(1L, TimeUnit.SECONDS); } @Warmup(iterations = 20) @Measurement(iterations = 10) @Benchmark public List<Integer> serial_lazy_jdk() { List<Integer> list = this.integersJDK.stream() .filter(each -> each % 10_000 != 0) .map(String::valueOf) .map(Integer::valueOf) .filter(each -> (each + 1) % 10_000 != 0) .collect(Collectors.toList()); Verify.assertSize(999_800, list); return list; } @Test public void test_serial_lazy_jdk() { Verify.assertListsEqual( Interval.oneToBy(1_000_000, 10_000).flatCollect(each -> Interval.fromTo(each, each + 9_997)).toList(), this.serial_lazy_jdk()); } @Warmup(iterations = 50) @Measurement(iterations = 25) @Benchmark public List<Integer> parallel_lazy_jdk() { List<Integer> list = this.integersJDK.parallelStream() .filter(each -> each % 10_000 != 0) .map(String::valueOf) .map(Integer::valueOf) .filter(each -> (each + 1) % 10_000 != 0) .collect(Collectors.toList()); Verify.assertSize(999_800, list); return list; } @Warmup(iterations = 50) @Measurement(iterations = 25) @Test public void test_parallel_lazy_jdk() { Verify.assertListsEqual( Interval.oneToBy(1_000_000, 10_000).flatCollect(each -> Interval.fromTo(each, each + 9_997)).toList(), this.parallel_lazy_jdk()); } @Warmup(iterations = 20) @Measurement(iterations = 10) @Benchmark public MutableList<Integer> serial_eager_gsc() { FastList<Integer> select1 = this.integersGSC.select(each -> each % 10_000 != 0); FastList<String> collect1 = select1.collect(String::valueOf); FastList<Integer> collect2 = collect1.collect(Integer::valueOf); FastList<Integer> list = collect2.select(each -> (each + 1) % 10_000 != 0); Verify.assertSize(999_800, list); return list; } @Test public void test_serial_eager_gsc() { Verify.assertListsEqual( Interval.oneToBy(1_000_000, 10_000).flatCollect(each -> Interval.fromTo(each, each + 9_997)).toList(), this.serial_eager_gsc()); } @Warmup(iterations = 20) @Measurement(iterations = 10) @Benchmark public MutableList<Integer> serial_eager_gsc_hand_coded() { FastList<Integer> list = new FastList<>(); int size = this.integersGSC.size(); for (int i = 0; i < size; i++) { Integer integer = this.integersGSC.get(i); if (integer % 10_000 != 0 && (Integer.valueOf(String.valueOf(integer)) + 1) % 10_000 != 0) { list.add(integer); } } Verify.assertSize(999_800, list); return list; } @Test public void test_serial_eager_gsc_hand_coded() { Verify.assertListsEqual( Interval.oneToBy(1_000_000, 10_000).flatCollect(each -> Interval.fromTo(each, each + 9_997)).toList(), this.serial_eager_gsc_hand_coded()); } @Warmup(iterations = 20) @Measurement(iterations = 10) @Benchmark public MutableList<Integer> serial_lazy_gsc() { MutableList<Integer> list = this.integersGSC .asLazy() .select(each -> each % 10_000 != 0) .collect(String::valueOf) .collect(Integer::valueOf) .select(each -> (each + 1) % 10_000 != 0) .toList(); Verify.assertSize(999_800, list); return list; } @Test public void test_serial_lazy_gsc() { Verify.assertListsEqual( Interval.oneToBy(1_000_000, 10_000).flatCollect(each -> Interval.fromTo(each, each + 9_997)).toList(), this.serial_lazy_gsc()); } @Warmup(iterations = 50) @Measurement(iterations = 25) @Benchmark public MutableList<Integer> parallel_eager_gsc() { MutableList<Integer> select1 = ParallelIterate.select(this.integersGSC, each -> each % 10_000 != 0, new CompositeFastList<>(), BATCH_SIZE, this.executorService, false); MutableList<String> collect1 = ParallelIterate.collect(select1, String::valueOf, new CompositeFastList<>(), BATCH_SIZE, this.executorService, false); MutableList<Integer> collect2 = ParallelIterate.collect(collect1, Integer::valueOf, new CompositeFastList<>(), BATCH_SIZE, this.executorService, false); MutableList<Integer> list = ParallelIterate.select(collect2, each -> (each + 1) % 10_000 != 0, new CompositeFastList<>(), BATCH_SIZE, this.executorService, false); Verify.assertSize(999_800, list); return list; } @Test public void test_parallel_eager_gsc() { Verify.assertListsEqual( Interval.oneToBy(1_000_000, 10_000).flatCollect(each -> Interval.fromTo(each, each + 9_997)).toList(), this.parallel_eager_gsc()); } @Warmup(iterations = 50) @Measurement(iterations = 25) @Benchmark public MutableList<Integer> parallel_lazy_gsc() { MutableList<Integer> list = this.integersGSC .asParallel(this.executorService, BATCH_SIZE) .select(each -> each % 10_000 != 0) .collect(String::valueOf) .collect(Integer::valueOf) .select(each -> (each + 1) % 10_000 != 0) .toList(); Verify.assertSize(999_800, list); return list; } @Test public void test_parallel_lazy_gsc() { Verify.assertListsEqual( Interval.oneToBy(1_000_000, 10_000).flatCollect(each -> Interval.fromTo(each, each + 9_997)).toList(), this.parallel_lazy_gsc()); } @Warmup(iterations = 50) @Measurement(iterations = 25) @Benchmark public CompositeFastList<Integer> parallel_eager_gsc_hand_coded() { CompositeFastList<Integer> list = ParallelIterate.select( this.integersGSC, integer -> integer % 10_000 != 0 && (Integer.valueOf(String.valueOf(integer)) + 1) % 10_000 != 0, new CompositeFastList<>(), BATCH_SIZE, this.executorService, false); Verify.assertSize(999_800, list); return list; } @Test public void test_parallel_eager_gsc_hand_coded() { Verify.assertListsEqual( Interval.oneToBy(1_000_000, 10_000).flatCollect(each -> Interval.fromTo(each, each + 9_997)).toList(), this.parallel_eager_gsc_hand_coded()); } @Warmup(iterations = 50) @Measurement(iterations = 25) @Benchmark public MutableList<Integer> parallel_lazy_gsc_hand_coded() { MutableList<Integer> list = this.integersGSC .asParallel(this.executorService, BATCH_SIZE) .select(integer -> integer % 10_000 != 0 && (Integer.valueOf(String.valueOf(integer)) + 1) % 10_000 != 0).toList(); Verify.assertSize(999_800, list); return list; } @Warmup(iterations = 50) @Measurement(iterations = 25) @Test public void test_parallel_lazy_gsc_hand_coded() { Verify.assertListsEqual( Interval.oneToBy(1_000_000, 10_000).flatCollect(each -> Interval.fromTo(each, each + 9_997)).toList(), this.parallel_lazy_gsc_hand_coded()); } @Warmup(iterations = 20) @Measurement(iterations = 10) @Benchmark public void serial_eager_scala() { FunctionalInterfaceScalaTest.serial_eager_scala(); } @Test public void test_serial_eager_scala() { FunctionalInterfaceScalaTest.test_serial_eager_scala(); } @Warmup(iterations = 20) @Measurement(iterations = 10) @Benchmark public void serial_lazy_scala() { FunctionalInterfaceScalaTest.serial_lazy_scala(); } @Test public void test_serial_lazy_scala() { FunctionalInterfaceScalaTest.test_serial_lazy_scala(); } @Warmup(iterations = 50) @Measurement(iterations = 25) @Benchmark public void parallel_lazy_scala() { FunctionalInterfaceScalaTest.parallel_lazy_scala(); } @Test public void test_parallel_lazy_scala() { FunctionalInterfaceScalaTest.test_parallel_lazy_scala(); } @Warmup(iterations = 50) @Measurement(iterations = 25) @Benchmark public void parallel_lazy_scala_hand_coded() { FunctionalInterfaceScalaTest.parallel_lazy_scala_hand_coded(); } @Test public void test_parallel_lazy_scala_hand_coded() { FunctionalInterfaceScalaTest.test_parallel_lazy_scala_hand_coded(); } }