From 7e1371e34202d4cba981d689eff7911757907a16 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Thu, 25 Jun 2020 18:00:38 -0400 Subject: [PATCH 1/8] Add microbenchmark for LongKeyedBucketOrds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I've always been confused by the strange behavior that I saw when working on #57304. Specifically, I saw switching from a bimorphic invocation to a monomorphic invocation to give us a 7%-15% performance bump. This felt *bonkers* to me. And, it also made me wonder whether it'd be worth looking into doing it everywhere. It turns out that, no, it isn't needed everywhere. This benchmark shows that a bimorphic invocation like: ``` LongKeyedBucketOrds ords = new LongKeyedBucketOrds.ForSingle(); ords.add(0, 0); <------ this line ``` is 19% slower than a monomorphic invocation like: ``` LongKeyedBucketOrds.ForSingle ords = new LongKeyedBucketOrds.ForSingle(); ords.add(0, 0); <------ this line ``` But *only* when the reference is mutable. In the example above, if `ords` is never changed then both perform the same. But if the `ords` reference is assigned twice then we start to see the difference: ``` immutable bimorphic avgt 10 6.468 ± 0.045 ns/op immutable monomorphic avgt 10 6.756 ± 0.026 ns/op mutable bimorphic avgt 10 9.741 ± 0.073 ns/op mutable monomorphic avgt 10 8.190 ± 0.016 ns/op ``` So the conclusion from all this is that we've done the right thing: `auto_date_histogram` is the only aggregation in which `ords` isn't final and it is the only aggregation that forces monomorphic invocations. All other aggregations use an immutable bimorphic invocation. Which is fine. Relates to #56487 --- .../terms/LongKeyedBucketOrdsBenchmark.java | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 benchmarks/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java diff --git a/benchmarks/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java b/benchmarks/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java new file mode 100644 index 0000000000000..a414a709a9056 --- /dev/null +++ b/benchmarks/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java @@ -0,0 +1,148 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.search.aggregations.bucket.terms; + +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.BigArrays; +import org.elasticsearch.common.util.PageCacheRecycler; +import org.elasticsearch.search.aggregations.bucket.histogram.AutoDateHistogramAggregationBuilder; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OperationsPerInvocation; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.util.concurrent.TimeUnit; + +@Fork(2) +@Warmup(iterations = 10) +@Measurement(iterations = 5) +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@OperationsPerInvocation(1_000_000) +@State(Scope.Benchmark) +public class LongKeyedBucketOrdsBenchmark { + private static final long LIMIT = 1_000_000; + /** + * The number of distinct values to add to the buckets. + */ + private static final long DISTINCT_VALUES = 10; + /** + * The number of buckets to create in the {@link #multiBucket()} case. + *

+ * If this is not relatively prime to {@link #DISTINCT_VALUES} then the + * values won't be scattered evenly across the buckets. + */ + private static final long DISTINCT_BUCKETS = 21; + + PageCacheRecycler recycler = new PageCacheRecycler(Settings.EMPTY); + BigArrays bigArrays = new BigArrays(recycler, null, "REQUEST"); + + /** + * Emulates a way that we do not use {@link LongKeyedBucketOrds} + * because it is not needed. + */ + @Benchmark + public void singleBucketIntoSingleImmutableMonmorphicInvocation() { + try (LongKeyedBucketOrds.FromSingle ords = new LongKeyedBucketOrds.FromSingle(bigArrays)) { + for (long i = 0; i < LIMIT; i++) { + ords.add(0, i % DISTINCT_VALUES); + } + } + } + + /** + * Emulates the way that most aggregations use {@link LongKeyedBucketOrds}. + */ + @Benchmark + public void singleBucketIntoSingleImmutableBimorphicInvocation() { + try (LongKeyedBucketOrds ords = LongKeyedBucketOrds.build(bigArrays, true)) { + for (long i = 0; i < LIMIT; i++) { + ords.add(0, i % DISTINCT_VALUES); + } + } + } + + /** + * Emulates the way that {@link AutoDateHistogramAggregationBuilder} uses {@link LongKeyedBucketOrds}. + */ + @Benchmark + public void singleBucketIntoSingleMutableMonmorphicInvocation() { + LongKeyedBucketOrds.FromSingle ords = new LongKeyedBucketOrds.FromSingle(bigArrays); + for (long i = 0; i < LIMIT; i++) { + if (i % 100_000 == 0) { + ords.close(); + ords = new LongKeyedBucketOrds.FromSingle(bigArrays); + } + ords.add(0, i % DISTINCT_VALUES); + } + ords.close(); + } + + /** + * Emulates a way that we do not use {@link LongKeyedBucketOrds} + * because it is significantly slower than the + * {@link #singleBucketIntoSingleMutableMonmorphicInvocation() monomorphic invocation}. + */ + @Benchmark + public void singleBucketIntoSingleMutableBimorphicInvocation() { + LongKeyedBucketOrds ords = LongKeyedBucketOrds.build(bigArrays, true); + for (long i = 0; i < LIMIT; i++) { + if (i % 100_000 == 0) { + ords.close(); + ords = LongKeyedBucketOrds.build(bigArrays, true); + } + ords.add(0, i % DISTINCT_VALUES); + + } + ords.close(); + } + + /** + * Emulates an aggregation that collects from a single bucket "by accident". + * This can happen if an aggregation is under, say, a {@code terms} + * aggregation and there is only a single value for that term in the index. + */ + @Benchmark + public void singleBucketIntoMulti() { + try (LongKeyedBucketOrds ords = LongKeyedBucketOrds.build(bigArrays, false)) { + for (long i = 0; i < LIMIT; i++) { + ords.add(0, i % DISTINCT_VALUES); + } + } + } + + /** + * Emulates an aggregation that collects from many buckets. + */ + @Benchmark + public void multiBucket() { + try (LongKeyedBucketOrds ords = LongKeyedBucketOrds.build(bigArrays, false)) { + for (long i = 0; i < LIMIT; i++) { + ords.add(i % DISTINCT_BUCKETS, i % DISTINCT_VALUES); + } + } + } +} From 80ba140322035157349bb2a694c1a78301210a4d Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Mon, 6 Jul 2020 10:05:04 -0400 Subject: [PATCH 2/8] Move benchmark to proper package --- .../bucket/terms/LongKeyedBucketOrdsBenchmark.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) rename benchmarks/src/main/java/org/elasticsearch/{ => benchmark}/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java (97%) diff --git a/benchmarks/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java b/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java similarity index 97% rename from benchmarks/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java rename to benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java index a414a709a9056..1685ec45845a1 100644 --- a/benchmarks/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java +++ b/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java @@ -17,12 +17,13 @@ * under the License. */ -package org.elasticsearch.search.aggregations.bucket.terms; +package org.elasticsearch.benchmark.search.aggregations.bucket.terms; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.common.util.PageCacheRecycler; import org.elasticsearch.search.aggregations.bucket.histogram.AutoDateHistogramAggregationBuilder; +import org.elasticsearch.search.aggregations.bucket.terms.LongKeyedBucketOrds; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; From 0f46086db0c66023ebd6a4394fc7705259203582 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Wed, 8 Jul 2020 15:36:36 -0400 Subject: [PATCH 3/8] Blackhole --- .../terms/LongKeyedBucketOrdsBenchmark.java | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java b/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java index 1685ec45845a1..617826b02b50e 100644 --- a/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java +++ b/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java @@ -34,6 +34,7 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; import java.util.concurrent.TimeUnit; @@ -66,11 +67,12 @@ public class LongKeyedBucketOrdsBenchmark { * because it is not needed. */ @Benchmark - public void singleBucketIntoSingleImmutableMonmorphicInvocation() { + public void singleBucketIntoSingleImmutableMonmorphicInvocation(Blackhole bh) { try (LongKeyedBucketOrds.FromSingle ords = new LongKeyedBucketOrds.FromSingle(bigArrays)) { for (long i = 0; i < LIMIT; i++) { ords.add(0, i % DISTINCT_VALUES); } + bh.consume(ords); } } @@ -78,11 +80,12 @@ public void singleBucketIntoSingleImmutableMonmorphicInvocation() { * Emulates the way that most aggregations use {@link LongKeyedBucketOrds}. */ @Benchmark - public void singleBucketIntoSingleImmutableBimorphicInvocation() { + public void singleBucketIntoSingleImmutableBimorphicInvocation(Blackhole bh) { try (LongKeyedBucketOrds ords = LongKeyedBucketOrds.build(bigArrays, true)) { for (long i = 0; i < LIMIT; i++) { ords.add(0, i % DISTINCT_VALUES); } + bh.consume(ords); } } @@ -90,15 +93,17 @@ public void singleBucketIntoSingleImmutableBimorphicInvocation() { * Emulates the way that {@link AutoDateHistogramAggregationBuilder} uses {@link LongKeyedBucketOrds}. */ @Benchmark - public void singleBucketIntoSingleMutableMonmorphicInvocation() { + public void singleBucketIntoSingleMutableMonmorphicInvocation(Blackhole bh) { LongKeyedBucketOrds.FromSingle ords = new LongKeyedBucketOrds.FromSingle(bigArrays); for (long i = 0; i < LIMIT; i++) { if (i % 100_000 == 0) { ords.close(); + bh.consume(ords); ords = new LongKeyedBucketOrds.FromSingle(bigArrays); } ords.add(0, i % DISTINCT_VALUES); } + bh.consume(ords); ords.close(); } @@ -108,16 +113,18 @@ public void singleBucketIntoSingleMutableMonmorphicInvocation() { * {@link #singleBucketIntoSingleMutableMonmorphicInvocation() monomorphic invocation}. */ @Benchmark - public void singleBucketIntoSingleMutableBimorphicInvocation() { + public void singleBucketIntoSingleMutableBimorphicInvocation(Blackhole bh) { LongKeyedBucketOrds ords = LongKeyedBucketOrds.build(bigArrays, true); for (long i = 0; i < LIMIT; i++) { if (i % 100_000 == 0) { ords.close(); + bh.consume(ords); ords = LongKeyedBucketOrds.build(bigArrays, true); } ords.add(0, i % DISTINCT_VALUES); } + bh.consume(ords); ords.close(); } @@ -127,11 +134,12 @@ public void singleBucketIntoSingleMutableBimorphicInvocation() { * aggregation and there is only a single value for that term in the index. */ @Benchmark - public void singleBucketIntoMulti() { + public void singleBucketIntoMulti(Blackhole bh) { try (LongKeyedBucketOrds ords = LongKeyedBucketOrds.build(bigArrays, false)) { for (long i = 0; i < LIMIT; i++) { ords.add(0, i % DISTINCT_VALUES); } + bh.consume(ords); } } @@ -139,11 +147,12 @@ public void singleBucketIntoMulti() { * Emulates an aggregation that collects from many buckets. */ @Benchmark - public void multiBucket() { + public void multiBucket(Blackhole bh) { try (LongKeyedBucketOrds ords = LongKeyedBucketOrds.build(bigArrays, false)) { for (long i = 0; i < LIMIT; i++) { ords.add(i % DISTINCT_BUCKETS, i % DISTINCT_VALUES); } + bh.consume(ords); } } } From dde47b2c8c112bcac6d389715fe6bc22e91a5891 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Wed, 8 Jul 2020 15:38:52 -0400 Subject: [PATCH 4/8] Handle merge --- .../bucket/terms/LongKeyedBucketOrdsBenchmark.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java b/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java index 617826b02b50e..619131c27be68 100644 --- a/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java +++ b/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java @@ -22,6 +22,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.common.util.PageCacheRecycler; +import org.elasticsearch.search.aggregations.CardinalityUpperBound; import org.elasticsearch.search.aggregations.bucket.histogram.AutoDateHistogramAggregationBuilder; import org.elasticsearch.search.aggregations.bucket.terms.LongKeyedBucketOrds; import org.openjdk.jmh.annotations.Benchmark; @@ -81,7 +82,7 @@ public void singleBucketIntoSingleImmutableMonmorphicInvocation(Blackhole bh) { */ @Benchmark public void singleBucketIntoSingleImmutableBimorphicInvocation(Blackhole bh) { - try (LongKeyedBucketOrds ords = LongKeyedBucketOrds.build(bigArrays, true)) { + try (LongKeyedBucketOrds ords = LongKeyedBucketOrds.build(bigArrays, CardinalityUpperBound.ONE)) { for (long i = 0; i < LIMIT; i++) { ords.add(0, i % DISTINCT_VALUES); } @@ -114,12 +115,12 @@ public void singleBucketIntoSingleMutableMonmorphicInvocation(Blackhole bh) { */ @Benchmark public void singleBucketIntoSingleMutableBimorphicInvocation(Blackhole bh) { - LongKeyedBucketOrds ords = LongKeyedBucketOrds.build(bigArrays, true); + LongKeyedBucketOrds ords = LongKeyedBucketOrds.build(bigArrays, CardinalityUpperBound.ONE); for (long i = 0; i < LIMIT; i++) { if (i % 100_000 == 0) { ords.close(); bh.consume(ords); - ords = LongKeyedBucketOrds.build(bigArrays, true); + ords = LongKeyedBucketOrds.build(bigArrays, CardinalityUpperBound.ONE); } ords.add(0, i % DISTINCT_VALUES); @@ -135,7 +136,7 @@ public void singleBucketIntoSingleMutableBimorphicInvocation(Blackhole bh) { */ @Benchmark public void singleBucketIntoMulti(Blackhole bh) { - try (LongKeyedBucketOrds ords = LongKeyedBucketOrds.build(bigArrays, false)) { + try (LongKeyedBucketOrds ords = LongKeyedBucketOrds.build(bigArrays, CardinalityUpperBound.MANY)) { for (long i = 0; i < LIMIT; i++) { ords.add(0, i % DISTINCT_VALUES); } @@ -148,7 +149,7 @@ public void singleBucketIntoMulti(Blackhole bh) { */ @Benchmark public void multiBucket(Blackhole bh) { - try (LongKeyedBucketOrds ords = LongKeyedBucketOrds.build(bigArrays, false)) { + try (LongKeyedBucketOrds ords = LongKeyedBucketOrds.build(bigArrays, CardinalityUpperBound.MANY)) { for (long i = 0; i < LIMIT; i++) { ords.add(i % DISTINCT_BUCKETS, i % DISTINCT_VALUES); } From 7ab3390daa6a68a7a788fe86a56518230d2df0f9 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Wed, 8 Jul 2020 15:41:50 -0400 Subject: [PATCH 5/8] javadoc --- .../bucket/terms/LongKeyedBucketOrdsBenchmark.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java b/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java index 619131c27be68..064f726b3a823 100644 --- a/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java +++ b/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java @@ -53,7 +53,7 @@ public class LongKeyedBucketOrdsBenchmark { */ private static final long DISTINCT_VALUES = 10; /** - * The number of buckets to create in the {@link #multiBucket()} case. + * The number of buckets to create in the {@link #multiBucket} case. *

* If this is not relatively prime to {@link #DISTINCT_VALUES} then the * values won't be scattered evenly across the buckets. @@ -111,7 +111,7 @@ public void singleBucketIntoSingleMutableMonmorphicInvocation(Blackhole bh) { /** * Emulates a way that we do not use {@link LongKeyedBucketOrds} * because it is significantly slower than the - * {@link #singleBucketIntoSingleMutableMonmorphicInvocation() monomorphic invocation}. + * {@link #singleBucketIntoSingleMutableMonmorphicInvocation monomorphic invocation}. */ @Benchmark public void singleBucketIntoSingleMutableBimorphicInvocation(Blackhole bh) { From d31dd304434fb3e2175a6be44d130c5c31460b14 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Wed, 8 Jul 2020 15:47:59 -0400 Subject: [PATCH 6/8] Force init --- .../aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java | 1 + 1 file changed, 1 insertion(+) diff --git a/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java b/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java index 064f726b3a823..83edb53f51a22 100644 --- a/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java +++ b/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java @@ -115,6 +115,7 @@ public void singleBucketIntoSingleMutableMonmorphicInvocation(Blackhole bh) { */ @Benchmark public void singleBucketIntoSingleMutableBimorphicInvocation(Blackhole bh) { + bh.consume(LongKeyedBucketOrds.FromMany.class); LongKeyedBucketOrds ords = LongKeyedBucketOrds.build(bigArrays, CardinalityUpperBound.ONE); for (long i = 0; i < LIMIT; i++) { if (i % 100_000 == 0) { From 67b57dba147bc70ff40c5b0c0ccd794247f45164 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Wed, 8 Jul 2020 15:49:28 -0400 Subject: [PATCH 7/8] Force loading classes --- .../bucket/terms/LongKeyedBucketOrdsBenchmark.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java b/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java index 83edb53f51a22..6733a0d794330 100644 --- a/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java +++ b/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java @@ -69,6 +69,7 @@ public class LongKeyedBucketOrdsBenchmark { */ @Benchmark public void singleBucketIntoSingleImmutableMonmorphicInvocation(Blackhole bh) { + forceLoadClasses(bh); try (LongKeyedBucketOrds.FromSingle ords = new LongKeyedBucketOrds.FromSingle(bigArrays)) { for (long i = 0; i < LIMIT; i++) { ords.add(0, i % DISTINCT_VALUES); @@ -82,6 +83,7 @@ public void singleBucketIntoSingleImmutableMonmorphicInvocation(Blackhole bh) { */ @Benchmark public void singleBucketIntoSingleImmutableBimorphicInvocation(Blackhole bh) { + forceLoadClasses(bh); try (LongKeyedBucketOrds ords = LongKeyedBucketOrds.build(bigArrays, CardinalityUpperBound.ONE)) { for (long i = 0; i < LIMIT; i++) { ords.add(0, i % DISTINCT_VALUES); @@ -95,6 +97,7 @@ public void singleBucketIntoSingleImmutableBimorphicInvocation(Blackhole bh) { */ @Benchmark public void singleBucketIntoSingleMutableMonmorphicInvocation(Blackhole bh) { + forceLoadClasses(bh); LongKeyedBucketOrds.FromSingle ords = new LongKeyedBucketOrds.FromSingle(bigArrays); for (long i = 0; i < LIMIT; i++) { if (i % 100_000 == 0) { @@ -115,7 +118,7 @@ public void singleBucketIntoSingleMutableMonmorphicInvocation(Blackhole bh) { */ @Benchmark public void singleBucketIntoSingleMutableBimorphicInvocation(Blackhole bh) { - bh.consume(LongKeyedBucketOrds.FromMany.class); + forceLoadClasses(bh); LongKeyedBucketOrds ords = LongKeyedBucketOrds.build(bigArrays, CardinalityUpperBound.ONE); for (long i = 0; i < LIMIT; i++) { if (i % 100_000 == 0) { @@ -137,6 +140,7 @@ public void singleBucketIntoSingleMutableBimorphicInvocation(Blackhole bh) { */ @Benchmark public void singleBucketIntoMulti(Blackhole bh) { + forceLoadClasses(bh); try (LongKeyedBucketOrds ords = LongKeyedBucketOrds.build(bigArrays, CardinalityUpperBound.MANY)) { for (long i = 0; i < LIMIT; i++) { ords.add(0, i % DISTINCT_VALUES); @@ -150,6 +154,7 @@ public void singleBucketIntoMulti(Blackhole bh) { */ @Benchmark public void multiBucket(Blackhole bh) { + forceLoadClasses(bh); try (LongKeyedBucketOrds ords = LongKeyedBucketOrds.build(bigArrays, CardinalityUpperBound.MANY)) { for (long i = 0; i < LIMIT; i++) { ords.add(i % DISTINCT_BUCKETS, i % DISTINCT_VALUES); @@ -157,4 +162,9 @@ public void multiBucket(Blackhole bh) { bh.consume(ords); } } + + private void forceLoadClasses(Blackhole bh) { + bh.consume(LongKeyedBucketOrds.FromSingle.class); + bh.consume(LongKeyedBucketOrds.FromMany.class); + } } From f426b5575868bc6c0b90591bd3255e253ab26d3e Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Mon, 13 Jul 2020 14:38:24 -0400 Subject: [PATCH 8/8] Move force loading classes to setup --- .../terms/LongKeyedBucketOrdsBenchmark.java | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java b/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java index 6733a0d794330..adef011abfb1b 100644 --- a/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java +++ b/benchmarks/src/main/java/org/elasticsearch/benchmark/search/aggregations/bucket/terms/LongKeyedBucketOrdsBenchmark.java @@ -33,6 +33,7 @@ import org.openjdk.jmh.annotations.OperationsPerInvocation; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.infra.Blackhole; @@ -60,8 +61,20 @@ public class LongKeyedBucketOrdsBenchmark { */ private static final long DISTINCT_BUCKETS = 21; - PageCacheRecycler recycler = new PageCacheRecycler(Settings.EMPTY); - BigArrays bigArrays = new BigArrays(recycler, null, "REQUEST"); + private final PageCacheRecycler recycler = new PageCacheRecycler(Settings.EMPTY); + private final BigArrays bigArrays = new BigArrays(recycler, null, "REQUEST"); + + /** + * Force loading all of the implementations just for extra paranoia's sake. + * We really don't want the JVM to be able to eliminate one of them just + * because we don't use it in the particular benchmark. That is totally a + * thing it'd do. It is sneaky. + */ + @Setup + public void forceLoadClasses(Blackhole bh) { + bh.consume(LongKeyedBucketOrds.FromSingle.class); + bh.consume(LongKeyedBucketOrds.FromMany.class); + } /** * Emulates a way that we do not use {@link LongKeyedBucketOrds} @@ -69,7 +82,6 @@ public class LongKeyedBucketOrdsBenchmark { */ @Benchmark public void singleBucketIntoSingleImmutableMonmorphicInvocation(Blackhole bh) { - forceLoadClasses(bh); try (LongKeyedBucketOrds.FromSingle ords = new LongKeyedBucketOrds.FromSingle(bigArrays)) { for (long i = 0; i < LIMIT; i++) { ords.add(0, i % DISTINCT_VALUES); @@ -83,7 +95,6 @@ public void singleBucketIntoSingleImmutableMonmorphicInvocation(Blackhole bh) { */ @Benchmark public void singleBucketIntoSingleImmutableBimorphicInvocation(Blackhole bh) { - forceLoadClasses(bh); try (LongKeyedBucketOrds ords = LongKeyedBucketOrds.build(bigArrays, CardinalityUpperBound.ONE)) { for (long i = 0; i < LIMIT; i++) { ords.add(0, i % DISTINCT_VALUES); @@ -97,7 +108,6 @@ public void singleBucketIntoSingleImmutableBimorphicInvocation(Blackhole bh) { */ @Benchmark public void singleBucketIntoSingleMutableMonmorphicInvocation(Blackhole bh) { - forceLoadClasses(bh); LongKeyedBucketOrds.FromSingle ords = new LongKeyedBucketOrds.FromSingle(bigArrays); for (long i = 0; i < LIMIT; i++) { if (i % 100_000 == 0) { @@ -118,7 +128,6 @@ public void singleBucketIntoSingleMutableMonmorphicInvocation(Blackhole bh) { */ @Benchmark public void singleBucketIntoSingleMutableBimorphicInvocation(Blackhole bh) { - forceLoadClasses(bh); LongKeyedBucketOrds ords = LongKeyedBucketOrds.build(bigArrays, CardinalityUpperBound.ONE); for (long i = 0; i < LIMIT; i++) { if (i % 100_000 == 0) { @@ -140,7 +149,6 @@ public void singleBucketIntoSingleMutableBimorphicInvocation(Blackhole bh) { */ @Benchmark public void singleBucketIntoMulti(Blackhole bh) { - forceLoadClasses(bh); try (LongKeyedBucketOrds ords = LongKeyedBucketOrds.build(bigArrays, CardinalityUpperBound.MANY)) { for (long i = 0; i < LIMIT; i++) { ords.add(0, i % DISTINCT_VALUES); @@ -154,7 +162,6 @@ public void singleBucketIntoMulti(Blackhole bh) { */ @Benchmark public void multiBucket(Blackhole bh) { - forceLoadClasses(bh); try (LongKeyedBucketOrds ords = LongKeyedBucketOrds.build(bigArrays, CardinalityUpperBound.MANY)) { for (long i = 0; i < LIMIT; i++) { ords.add(i % DISTINCT_BUCKETS, i % DISTINCT_VALUES); @@ -162,9 +169,4 @@ public void multiBucket(Blackhole bh) { bh.consume(ords); } } - - private void forceLoadClasses(Blackhole bh) { - bh.consume(LongKeyedBucketOrds.FromSingle.class); - bh.consume(LongKeyedBucketOrds.FromMany.class); - } }