Add JMH benchmark for programs

This commit is contained in:
aNNiMON 2023-08-30 18:21:58 +03:00 committed by Victor Melnik
parent fc1d8b4c75
commit 16de63f720
7 changed files with 99 additions and 22 deletions

View File

@ -14,6 +14,7 @@ dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.junit.jupiter:junit-jupiter'
testImplementation "org.openjdk.jmh:jmh-core:${versions.jmh}" testImplementation "org.openjdk.jmh:jmh-core:${versions.jmh}"
testImplementation "org.openjdk.jmh:jmh-generator-annprocess:${versions.jmh}" testImplementation "org.openjdk.jmh:jmh-generator-annprocess:${versions.jmh}"
testAnnotationProcessor "org.openjdk.jmh:jmh-generator-annprocess:${versions.jmh}"
} }
test { test {

View File

@ -6,6 +6,7 @@ import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.Options;
@ -23,13 +24,13 @@ public class LexerBenchmarkTest {
@Setup(Level.Trial) @Setup(Level.Trial)
public void initializeTrial() throws IOException { public void initializeTrial() throws IOException {
input = SourceLoader.readSource("program.own"); input = SourceLoader.readSource("../program.own");
} }
@Benchmark @Benchmark
public void lexerBenchmark() { public void lexerBenchmark(Blackhole bh) {
for (int i = 0; i < iterations; i++) { for (int i = 0; i < iterations; i++) {
Lexer.tokenize(input); bh.consume(Lexer.tokenize(input));
} }
} }

View File

@ -25,7 +25,7 @@ public class ParserBenchmarkTest {
@Setup(Level.Trial) @Setup(Level.Trial)
public void initializeTrial() throws IOException { public void initializeTrial() throws IOException {
input = Lexer.tokenize(SourceLoader.readSource("program.own")); input = Lexer.tokenize(SourceLoader.readSource("../program.own"));
} }
@Benchmark @Benchmark

View File

@ -0,0 +1,64 @@
package com.annimon.ownlang.parser;
import com.annimon.ownlang.parser.ast.Statement;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openjdk.jmh.annotations.*;
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;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.TimeUnit;
import static com.annimon.ownlang.parser.TestDataUtil.scanDirectory;
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Benchmark)
public class ProgramsBenchmarkTest {
private static final String RES_DIR = "src/test/resources/benchmarks";
@Param({"10"})
private int iterations;
@Param({"-"})
private String path;
private Statement program;
@Setup(Level.Trial)
public void initializeTrial() throws IOException {
if (!Files.exists(Path.of(path))) return;
final var source = SourceLoader.readSource(path);
final var tokens = Lexer.tokenize(source);
program = Parser.parse(tokens);
}
@Benchmark
public void programBenchmark() {
for (int i = 0; i < iterations; i++) {
program.execute();
}
}
@Disabled
@Test
public void executeBenchmark() throws RunnerException {
Options opt = new OptionsBuilder()
.include(ProgramsBenchmarkTest.class.getSimpleName())
.warmupIterations(3)
.measurementIterations(5)
.param("path", scanDirectory(RES_DIR)
.map(File::getPath)
.toArray(String[]::new))
.threads(1)
.forks(1)
.build();
new Runner(opt).run();
}
}

View File

@ -18,35 +18,19 @@ import org.junit.jupiter.params.provider.MethodSource;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import java.util.stream.Stream; import java.util.stream.Stream;
import static com.annimon.ownlang.parser.TestDataUtil.scanDirectory;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
public class ProgramsTest { public class ProgramsTest {
private static final String RES_DIR = "src/test/resources"; private static final String RES_DIR = "src/test/resources";
public static Stream<String> data() { public static Stream<String> data() {
final File resDir = new File(RES_DIR); return scanDirectory(RES_DIR)
return scanDirectory(resDir)
.map(File::getPath); .map(File::getPath);
} }
private static Stream<File> scanDirectory(File dir) {
final File[] files = dir.listFiles();
if (files == null || files.length == 0) {
return Stream.empty();
}
return Arrays.stream(files)
.flatMap(file -> {
if (file.isDirectory()) {
return scanDirectory(file);
}
return Stream.of(file);
})
.filter(f -> f.getName().endsWith(".own"));
}
@BeforeEach @BeforeEach
public void initialize() { public void initialize() {
Variables.clear(); Variables.clear();

View File

@ -0,0 +1,22 @@
package com.annimon.ownlang.parser;
import java.io.File;
import java.util.Arrays;
import java.util.stream.Stream;
public class TestDataUtil {
static Stream<File> scanDirectory(String dirPath) {
return scanDirectory(new File(dirPath));
}
static Stream<File> scanDirectory(File dir) {
final File[] files = dir.listFiles();
if (files == null || files.length == 0) {
return Stream.empty();
}
return Arrays.stream(files)
.flatMap(f -> f.isDirectory() ? scanDirectory(f) : Stream.of(f))
.filter(f -> f.getName().endsWith(".own"));
}
}

View File

@ -0,0 +1,5 @@
for i = 0, i < 50, i++ {
use "std"
use "files"
use ["math", "functional"]
}