Skip to content

Instantly share code, notes, and snippets.

@bertm
Last active March 19, 2024 22:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bertm/94f3c97fd138fe075a1f54076c6bd3cf to your computer and use it in GitHub Desktop.
Save bertm/94f3c97fd138fe075a1f54076c6bd3cf to your computer and use it in GitHub Desktop.
Microbenchmark for Hyphanet Fred's SHA256 wrapper
package freenet.benchmark;
import java.lang.invoke.MethodHandles;
import java.lang.ref.SoftReference;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;
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.Threads;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
@Warmup(time = 3)
@Measurement(time = 3)
@OutputTimeUnit(TimeUnit.SECONDS)
@BenchmarkMode(Mode.Throughput)
@Threads(4)
public class DigestBenchmark {
@Benchmark
public byte[] pooled(SHA256 sha256, Input input) {
MessageDigest digest = sha256.borrowPooledDigest();
try {
return digest.digest(input.payload);
} finally {
sha256.returnPooledDigest(digest);
}
}
@Benchmark
public byte[] fresh(SHA256 sha256, Input input) {
MessageDigest digest = sha256.createFreshDigest();
return digest.digest(input.payload);
}
@State(Scope.Thread)
public static class Input {
@Param({"16", "256", "2048"})
public int payloadLength;
public byte[] payload;
@Setup(Level.Iteration)
public void init() {
payload = new byte[payloadLength];
new Random().nextBytes(payload);
}
}
@State(Scope.Benchmark)
public static class SHA256 {
private final Queue<SoftReference<MessageDigest>> digestPool = new ConcurrentLinkedQueue<>();
private Provider provider;
@Setup(Level.Trial)
public void init() throws NoSuchAlgorithmException {
provider = MessageDigest.getInstance("SHA-256").getProvider();
}
public MessageDigest createFreshDigest() {
try {
return MessageDigest.getInstance("SHA-256", provider);
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
}
public MessageDigest borrowPooledDigest() {
SoftReference<MessageDigest> item;
while (((item = digestPool.poll()) != null)) {
MessageDigest md = item.get();
if (md != null) {
return md;
}
}
return createFreshDigest();
}
public void returnPooledDigest(MessageDigest digest) {
digest.reset();
digestPool.add(new SoftReference<>(digest));
}
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(MethodHandles.lookup().lookupClass().getSimpleName())
.forks(1)
.build();
new Runner(opt).run();
}
}
@bertm
Copy link
Author

bertm commented Mar 19, 2024

Generate a Maven project for running the benchmark as follows (this will create a project directory fred-benchmark):

mvn archetype:generate \
  -DinteractiveMode=false \
  -DarchetypeGroupId=org.openjdk.jmh \
  -DarchetypeArtifactId=jmh-java-benchmark-archetype \
  -DgroupId=freenet.benchmark \
  -DartifactId=fred-benchmark \
  -Dversion=1.0

Now add the benchmark by adding this benchmark class to fred-benchmark/src/main/java/freenet/benchmark.
Then package & run:

cd fred-benchmark
mvn clean package
java -cp target/benchmarks.jar freenet.benchmark.DigestBenchmark

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment