Skip to content

Commit 21c983f

Browse files
feat: add proper JMH benchmarks
Signed-off-by: Andreas Reichel <[email protected]>
1 parent f2c87a3 commit 21c983f

File tree

8 files changed

+2318
-0
lines changed

8 files changed

+2318
-0
lines changed

build.gradle

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,3 +641,11 @@ tasks.register('upload') {
641641
check {
642642
dependsOn jacocoTestCoverageVerification
643643
}
644+
645+
jmh {
646+
includes = ['.*JSQLParserBenchmark.*']
647+
warmupIterations = 3
648+
fork = 3
649+
iterations = 10
650+
timeOnIteration = '1s'
651+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
-- Optimised LOOKAHEADS (replacing all syntactic lookahead by numeric lookaheads)
2+
Benchmark (version) Mode Cnt Score Error Units
3+
JSQLParserBenchmark.parseSQLStatements latest avgt 15 264.132 ± 9.636 ms/op
4+
JSQLParserBenchmark.parseSQLStatements 5.2 avgt 15 415.744 ± 20.602 ms/op
5+
JSQLParserBenchmark.parseSQLStatements 5.1 avgt 15 89.387 ± 1.916 ms/op
6+
JSQLParserBenchmark.parseSQLStatements 5.0 avgt 15 68.810 ± 2.591 ms/op
7+
JSQLParserBenchmark.parseSQLStatements 4.9 avgt 15 60.515 ± 1.650 ms/op
8+
JSQLParserBenchmark.parseSQLStatements 4.8 avgt 15 60.002 ± 1.259 ms/op
9+
JSQLParserBenchmark.parseSQLStatements 4.7 avgt 15 73.291 ± 3.049 ms/op
10+
11+
-- Optimised LOOKAHEADS (replacing huge numeric lookaheads with syntactic lookaheads again)
12+
Benchmark (version) Mode Cnt Score Error Units
13+
JSQLParserBenchmark.parseSQLStatements latest avgt 15 249.408 ± 11.340 ms/op
14+
JSQLParserBenchmark.parseSQLStatements 5.2 avgt 15 388.453 ± 13.149 ms/op
15+
16+
-- Disable `FunctionAllColumns()`
17+
Benchmark (version) Mode Cnt Score Error Units
18+
JSQLParserBenchmark.parseSQLStatements latest avgt 30 83.504 ± 1.557 ms/op
19+
JSQLParserBenchmark.parseSQLStatements 5.2 avgt 30 400.876 ± 8.291 ms/op
20+
JSQLParserBenchmark.parseSQLStatements 5.1 avgt 30 85.731 ± 1.288 ms/op
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2025 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.benchmark;
11+
12+
import net.sf.jsqlparser.parser.CCJSqlParser;
13+
import net.sf.jsqlparser.statement.Statements;
14+
15+
import java.lang.reflect.Method;
16+
import java.net.URLClassLoader;
17+
import java.util.concurrent.ExecutorService;
18+
import java.util.function.Consumer;
19+
20+
public class DynamicParserRunner implements SqlParserRunner {
21+
private final Method parseStatementsMethod;
22+
23+
public DynamicParserRunner(URLClassLoader loader) throws Exception {
24+
Class<?> utilClass = loader.loadClass("net.sf.jsqlparser.parser.CCJSqlParserUtil");
25+
Class<?> ccjClass = loader.loadClass("net.sf.jsqlparser.parser.CCJSqlParser");
26+
Class<?> consumerClass = Class.forName("java.util.function.Consumer"); // interface OK
27+
parseStatementsMethod = utilClass.getMethod(
28+
"parseStatements",
29+
String.class,
30+
ExecutorService.class,
31+
consumerClass);
32+
}
33+
34+
@Override
35+
public Statements parseStatements(String sql,
36+
ExecutorService executorService,
37+
Consumer<CCJSqlParser> consumer) throws Exception {
38+
return (Statements) parseStatementsMethod.invoke(null, sql, executorService, null);
39+
}
40+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2025 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.benchmark;
11+
12+
import net.sf.jsqlparser.parser.CCJSqlParser;
13+
import net.sf.jsqlparser.statement.Statements;
14+
import org.openjdk.jmh.annotations.*;
15+
16+
import java.io.IOException;
17+
import java.io.InputStream;
18+
import java.net.URL;
19+
import java.net.URLClassLoader;
20+
import java.nio.charset.StandardCharsets;
21+
import java.nio.file.*;
22+
import java.util.concurrent.*;
23+
import java.util.function.Consumer;
24+
25+
@BenchmarkMode(Mode.AverageTime)
26+
@OutputTimeUnit(TimeUnit.MILLISECONDS)
27+
@State(Scope.Benchmark)
28+
public class JSQLParserBenchmark {
29+
30+
private String sqlContent;
31+
private ExecutorService executorService;
32+
33+
SqlParserRunner runner;
34+
35+
// @Param({ "latest", "5.2", "5.1", "5.0", "4.9", "4.8", "4.7", "4.6", "4.5" })
36+
@Param({"latest", "5.2", "5.1"})
37+
public String version;
38+
39+
@Setup(Level.Trial)
40+
public void setup() throws Exception {
41+
if ("latest".equals(version)) {
42+
runner = new LatestClasspathRunner(); // direct call, no reflection
43+
} else {
44+
Path jarPath = downloadJsqlparserJar(version);
45+
URLClassLoader loader = new URLClassLoader(new URL[] {jarPath.toUri().toURL()}, null);
46+
runner = new DynamicParserRunner(loader);
47+
}
48+
49+
// Adjust path as necessary based on where source root is during test execution
50+
Path path = Paths.get("src/test/resources/net/sf/jsqlparser/performance.sql");
51+
sqlContent = Files.readString(path, StandardCharsets.UTF_8);
52+
executorService = Executors.newSingleThreadExecutor();
53+
}
54+
55+
private Path downloadJsqlparserJar(String version) throws IOException {
56+
String jarUrl = String.format(
57+
"https://repo1.maven.org/maven2/com/github/jsqlparser/jsqlparser/%s/jsqlparser-%s.jar",
58+
version, version);
59+
60+
Path cacheDir = Paths.get("build/libs/downloaded-jars");
61+
Files.createDirectories(cacheDir);
62+
Path jarFile = cacheDir.resolve("jsqlparser-" + version + ".jar");
63+
64+
if (!Files.exists(jarFile)) {
65+
System.out.println("Downloading " + version);
66+
try (InputStream in = new URL(jarUrl).openStream()) {
67+
Files.copy(in, jarFile);
68+
}
69+
}
70+
71+
return jarFile;
72+
}
73+
74+
@Benchmark
75+
public void parseSQLStatements() throws Exception {
76+
final Statements statements = runner.parseStatements(
77+
sqlContent,
78+
executorService,
79+
(Consumer<CCJSqlParser>) parser -> {
80+
// No-op consumer (or you can log/validate each parser if desired)
81+
});
82+
assert statements.size() == 4;
83+
}
84+
85+
@TearDown(Level.Trial)
86+
public void tearDown() {
87+
executorService.shutdown();
88+
}
89+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2025 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.benchmark;
11+
12+
import net.sf.jsqlparser.parser.CCJSqlParser;
13+
import net.sf.jsqlparser.statement.Statements;
14+
15+
import java.util.concurrent.ExecutorService;
16+
import java.util.function.Consumer;
17+
18+
public class LatestClasspathRunner implements SqlParserRunner {
19+
20+
@Override
21+
public Statements parseStatements(String sql,
22+
ExecutorService executorService,
23+
Consumer<CCJSqlParser> consumer) throws Exception {
24+
return net.sf.jsqlparser.parser.CCJSqlParserUtil.parseStatements(sql, executorService,
25+
consumer);
26+
}
27+
}
28+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2025 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.benchmark;
11+
12+
import net.sf.jsqlparser.parser.CCJSqlParser;
13+
import net.sf.jsqlparser.statement.Statements;
14+
15+
import java.util.concurrent.ExecutorService;
16+
import java.util.function.Consumer;
17+
18+
public interface SqlParserRunner {
19+
Statements parseStatements(String sql, ExecutorService executorService,
20+
Consumer<CCJSqlParser> consumer) throws Exception;
21+
}

src/test/java/net/sf/jsqlparser/statement/select/SpeedTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import net.sf.jsqlparser.statement.simpleparsing.CCJSqlParserManagerTest;
1616
import net.sf.jsqlparser.test.TestException;
1717
import net.sf.jsqlparser.util.TablesNamesFinder;
18+
import org.junit.jupiter.api.Disabled;
1819
import org.junit.jupiter.api.Test;
1920

2021
import java.io.BufferedReader;
@@ -30,6 +31,7 @@ public class SpeedTest {
3031
private final CCJSqlParserManager parserManager = new CCJSqlParserManager();
3132

3233
@Test
34+
@Disabled
3335
public void testSpeed() throws Exception {
3436
// all the statements in testfiles/simple_parsing.txt
3537
BufferedReader in = new BufferedReader(

0 commit comments

Comments
 (0)