Replace accumulation with blackhole.consume (#9275)

Motivation:

SpotJMHBugs reports that accumulating a value as a way of eliding dead code
elimination may be inadvisable, as discussed in
`JMHSample_34_SafeLooping::measureWrong_2`. Change the test so that it consumes
the response with `Blackhole::consume` instead.

Modifications:

- Replace addition of results with explicit `blackhole.consume()` call

Result:

Tests work as before, but with different benchmark numbers.
This commit is contained in:
Alex Blewitt 2019-06-25 20:46:26 +01:00 committed by Norman Maurer
parent c6114786ab
commit e233407e01
4 changed files with 40 additions and 58 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2017 The Netty Project
* Copyright 2019 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
@ -22,6 +22,7 @@ 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 org.openjdk.jmh.infra.Blackhole;
import java.util.HashMap;
import java.util.Map;
@ -151,68 +152,56 @@ public class HttpMethodMapBenchmark extends AbstractMicrobenchmark {
}
@Benchmark
public int oldMapKnownMethods() throws Exception {
int x = 0;
public void oldMapKnownMethods(Blackhole bh) throws Exception {
for (int i = 0; i < KNOWN_METHODS.length; ++i) {
x += OLD_MAP.get(KNOWN_METHODS[i]).toString().length();
bh.consume(OLD_MAP.get(KNOWN_METHODS[i]));
}
return x;
}
@Benchmark
public int newMapKnownMethods() throws Exception {
int x = 0;
public void newMapKnownMethods(Blackhole bh) throws Exception {
for (int i = 0; i < KNOWN_METHODS.length; ++i) {
x += NEW_MAP.get(KNOWN_METHODS[i]).toString().length();
bh.consume(NEW_MAP.get(KNOWN_METHODS[i]));
}
return x;
}
@Benchmark
public int oldMapMixMethods() throws Exception {
int x = 0;
public void oldMapMixMethods(Blackhole bh) throws Exception {
for (int i = 0; i < MIXED_METHODS.length; ++i) {
HttpMethod method = OLD_MAP.get(MIXED_METHODS[i]);
if (method != null) {
x += method.toString().length();
bh.consume(method);
}
}
return x;
}
@Benchmark
public int newMapMixMethods() throws Exception {
int x = 0;
public void newMapMixMethods(Blackhole bh) throws Exception {
for (int i = 0; i < MIXED_METHODS.length; ++i) {
HttpMethod method = NEW_MAP.get(MIXED_METHODS[i]);
if (method != null) {
x += method.toString().length();
bh.consume(method);
}
}
return x;
}
@Benchmark
public int oldMapUnknownMethods() throws Exception {
int x = 0;
public void oldMapUnknownMethods(Blackhole bh) throws Exception {
for (int i = 0; i < UNKNOWN_METHODS.length; ++i) {
HttpMethod method = OLD_MAP.get(UNKNOWN_METHODS[i]);
if (method != null) {
x += method.toString().length();
bh.consume(method);
}
}
return x;
}
@Benchmark
public int newMapUnknownMethods() throws Exception {
int x = 0;
public void newMapUnknownMethods(Blackhole bh) throws Exception {
for (int i = 0; i < UNKNOWN_METHODS.length; ++i) {
HttpMethod method = NEW_MAP.get(UNKNOWN_METHODS[i]);
if (method != null) {
x += method.toString().length();
bh.consume(method);
}
}
return x;
}
}

View File

@ -20,6 +20,7 @@ import io.netty.util.concurrent.FastThreadLocal;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Threads;
import org.openjdk.jmh.infra.Blackhole;
import java.util.Random;
@ -56,20 +57,16 @@ public class FastThreadLocalFastPathBenchmark extends AbstractMicrobenchmark {
}
@Benchmark
public int jdkThreadLocalGet() {
int result = 0;
public void jdkThreadLocalGet(Blackhole bh) {
for (ThreadLocal<Integer> i: jdkThreadLocals) {
result += i.get();
bh.consume(i.get());
}
return result;
}
@Benchmark
public int fastThreadLocal() {
int result = 0;
public void fastThreadLocal(Blackhole bh) {
for (FastThreadLocal<Integer> i: fastThreadLocals) {
result += i.get();
bh.consume(i.get());
}
return result;
}
}

View File

@ -20,6 +20,7 @@ import io.netty.util.concurrent.FastThreadLocal;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Threads;
import org.openjdk.jmh.infra.Blackhole;
import java.util.Random;
@ -60,20 +61,16 @@ public class FastThreadLocalSlowPathBenchmark extends AbstractMicrobenchmark {
}
@Benchmark
public int jdkThreadLocalGet() {
int result = 0;
public void jdkThreadLocalGet(Blackhole bh) {
for (ThreadLocal<Integer> i: jdkThreadLocals) {
result += i.get();
bh.consume(i.get());
}
return result;
}
@Benchmark
public int fastThreadLocal() {
int result = 0;
public void fastThreadLocal(Blackhole bh) {
for (FastThreadLocal<Integer> i: fastThreadLocals) {
result += i.get();
bh.consume(i.get());
}
return result;
}
}

View File

@ -35,6 +35,7 @@ import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Threads;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.infra.Blackhole;
import java.util.Map;
import java.util.UUID;
@ -68,23 +69,23 @@ public class ReadOnlyHttp2HeadersBenchmark extends AbstractMicrobenchmark {
@Benchmark
@BenchmarkMode(Mode.AverageTime)
public int defaultTrailers() {
public void defaultTrailers(Blackhole bh) {
Http2Headers headers = new DefaultHttp2Headers(false);
for (int i = 0; i < headerCount; ++i) {
headers.add(headerNames[i], headerValues[i]);
}
return iterate(headers);
iterate(headers, bh);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
public int readOnlyTrailers() {
return iterate(ReadOnlyHttp2Headers.trailers(false, buildPairs()));
public void readOnlyTrailers(Blackhole bh) {
iterate(ReadOnlyHttp2Headers.trailers(false, buildPairs()), bh);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
public int defaultClientHeaders() {
public void defaultClientHeaders(Blackhole bh) {
Http2Headers headers = new DefaultHttp2Headers(false);
for (int i = 0; i < headerCount; ++i) {
headers.add(headerNames[i], headerValues[i]);
@ -93,39 +94,37 @@ public class ReadOnlyHttp2HeadersBenchmark extends AbstractMicrobenchmark {
headers.scheme(HttpScheme.HTTPS.name());
headers.path(path);
headers.authority(authority);
return iterate(headers);
iterate(headers, bh);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
public int readOnlyClientHeaders() {
return iterate(ReadOnlyHttp2Headers.clientHeaders(false, HttpMethod.POST.asciiName(), path,
HttpScheme.HTTPS.name(), authority, buildPairs()));
public void readOnlyClientHeaders(Blackhole bh) {
iterate(ReadOnlyHttp2Headers.clientHeaders(false, HttpMethod.POST.asciiName(), path,
HttpScheme.HTTPS.name(), authority, buildPairs()), bh);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
public int defaultServerHeaders() {
public void defaultServerHeaders(Blackhole bh) {
Http2Headers headers = new DefaultHttp2Headers(false);
for (int i = 0; i < headerCount; ++i) {
headers.add(headerNames[i], headerValues[i]);
}
headers.status(HttpResponseStatus.OK.codeAsText());
return iterate(headers);
iterate(headers, bh);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
public int readOnlyServerHeaders() {
return iterate(ReadOnlyHttp2Headers.serverHeaders(false, HttpResponseStatus.OK.codeAsText(), buildPairs()));
public void readOnlyServerHeaders(Blackhole bh) {
iterate(ReadOnlyHttp2Headers.serverHeaders(false, HttpResponseStatus.OK.codeAsText(), buildPairs()), bh);
}
private static int iterate(Http2Headers headers) {
int length = 0;
private static void iterate(Http2Headers headers, Blackhole bh) {
for (Map.Entry<CharSequence, CharSequence> entry : headers) {
length += entry.getKey().length() + entry.getValue().length();
bh.consume(entry);
}
return length;
}
private AsciiString[] buildPairs() {