blob: b55a9936325f47e8ff5f0bb420ab07569a640118 [file] [log] [blame]
// Copyright 2022 Code Intelligence GmbH
//
// 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.code_intelligence.jazzer.runtime;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
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.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.Warmup;
@Warmup(iterations = 5, time = 1)
@Measurement(iterations = 5, time = 1)
@Fork(value = 3)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.AverageTime)
public class FuzzerCallbacksBenchmark {
@State(Scope.Benchmark)
public static class TraceCmpIntState {
int arg1 = 0xCAFECAFE;
int arg2 = 0xFEEDFEED;
int pc = 0x12345678;
}
@Benchmark
public void traceCmpInt(TraceCmpIntState state) {
FuzzerCallbacks.traceCmpInt(state.arg1, state.arg2, state.pc);
}
@Benchmark
public void traceCmpIntWithPc(TraceCmpIntState state) {
FuzzerCallbacksWithPc.traceCmpInt(state.arg1, state.arg2, state.pc);
}
@Benchmark
@Fork(jvmArgsAppend = {"-XX:+CriticalJNINatives"})
public void traceCmpIntOptimizedCritical(TraceCmpIntState state) {
FuzzerCallbacksOptimizedCritical.traceCmpInt(state.arg1, state.arg2, state.pc);
}
// Uncomment to benchmark Project Panama-backed implementation (requires JDK 16+).
// @Benchmark
// @Fork(jvmArgsAppend = {"--enable-native-access=ALL-UNNAMED", "--add-modules",
// "jdk.incubator.foreign"})
// public void
// traceCmpIntPanama(TraceCmpIntState state) throws Throwable {
// FuzzerCallbacksPanama.traceCmpInt(state.arg1, state.arg2, state.pc);
// }
@State(Scope.Benchmark)
public static class TraceSwitchState {
@Param({"5", "10"}) int numCases;
long val;
long[] cases;
int pc = 0x12345678;
@Setup
public void setup() {
cases = new long[2 + numCases];
Random random = ThreadLocalRandom.current();
Arrays.setAll(cases, i -> {
switch (i) {
case 0:
return numCases;
case 1:
return 32;
default:
return random.nextInt();
}
});
Arrays.sort(cases, 2, cases.length);
val = random.nextInt();
}
}
@Benchmark
public void traceSwitch(TraceSwitchState state) {
FuzzerCallbacks.traceSwitch(state.val, state.cases, state.pc);
}
@Benchmark
public void traceSwitchWithPc(TraceSwitchState state) {
FuzzerCallbacksWithPc.traceSwitch(state.val, state.cases, state.pc);
}
@Benchmark
@Fork(jvmArgsAppend = {"-XX:+CriticalJNINatives"})
public void traceSwitchOptimizedCritical(TraceSwitchState state) {
FuzzerCallbacksOptimizedCritical.traceSwitch(state.val, state.cases, state.pc);
}
@Benchmark
public void traceSwitchOptimizedNonCritical(TraceSwitchState state) {
FuzzerCallbacksOptimizedNonCritical.traceSwitch(state.val, state.cases, state.pc);
}
// Uncomment to benchmark Project Panama-backed implementation (requires JDK 16+).
// @Benchmark
// @Fork(jvmArgsAppend = {"--enable-native-access=ALL-UNNAMED", "--add-modules",
// "jdk.incubator.foreign"})
// public void
// traceCmpSwitchPanama(TraceSwitchState state) throws Throwable {
// FuzzerCallbacksPanama.traceCmpSwitch(state.val, state.cases, state.pc);
// }
@State(Scope.Benchmark)
public static class TraceMemcmpState {
@Param({"10", "100", "1000"}) int length;
byte[] array1;
byte[] array2;
int pc = 0x12345678;
@Setup
public void setup() {
array1 = new byte[length];
array2 = new byte[length];
Random random = ThreadLocalRandom.current();
random.nextBytes(array1);
random.nextBytes(array2);
// Make the arrays agree unil the midpoint to benchmark the "average"
// case of an interesting memcmp.
System.arraycopy(array1, 0, array2, 0, length / 2);
}
}
@Benchmark
public void traceMemcmp(TraceMemcmpState state) {
FuzzerCallbacks.traceMemcmp(state.array1, state.array2, 1, state.pc);
}
@Benchmark
@Fork(jvmArgsAppend = {"-XX:+CriticalJNINatives"})
public void traceMemcmpOptimizedCritical(TraceMemcmpState state) {
FuzzerCallbacksOptimizedCritical.traceMemcmp(state.array1, state.array2, 1, state.pc);
}
@Benchmark
public void traceMemcmpOptimizedNonCritical(TraceMemcmpState state) {
FuzzerCallbacksOptimizedNonCritical.traceMemcmp(state.array1, state.array2, 1, state.pc);
}
@State(Scope.Benchmark)
public static class TraceStrstrState {
@Param({"10", "100", "1000"}) int length;
@Param({"true", "false"}) boolean asciiOnly;
String haystack;
String needle;
int pc = 0x12345678;
@Setup
public void setup() {
haystack = randomString(length, asciiOnly);
needle = randomString(length, asciiOnly);
}
private String randomString(int length, boolean asciiOnly) {
String asciiString =
ThreadLocalRandom.current()
.ints('a', 'z' + 1)
.limit(length)
.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
.toString();
if (asciiOnly) {
return asciiString;
}
// Force String to be non-Latin-1 to preclude compact string optimization.
return "\uFFFD" + asciiString.substring(1);
}
}
@Benchmark
public void traceStrstr(TraceStrstrState state) {
FuzzerCallbacks.traceStrstr(state.haystack, state.needle, state.pc);
}
@Benchmark
public void traceStrstrOptimizedNonCritical(TraceStrstrState state) {
FuzzerCallbacksOptimizedNonCritical.traceStrstr(state.haystack, state.needle, state.pc);
}
@Benchmark
@Fork(jvmArgsAppend = {"-XX:+CriticalJNINatives"})
public void traceStrstrOptimizedJavaCritical(TraceStrstrState state)
throws UnsupportedEncodingException {
FuzzerCallbacksOptimizedCritical.traceStrstrJava(state.haystack, state.needle, state.pc);
}
@Benchmark
public void traceStrstrOptimizedJavaNonCritical(TraceStrstrState state)
throws UnsupportedEncodingException {
FuzzerCallbacksOptimizedNonCritical.traceStrstrJava(state.haystack, state.needle, state.pc);
}
}