-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reduce the garbage produced by GraphQL while handling the request #33676
Conversation
@jmartisk AS said, this is not a game changer, but it's implemented in a way that "common" charsets could be cached with ease eg Just want to be sure that my assumptions on the pre-validation hold |
Is it really a hot path when actually executing a query? Because if it's not a game changer, I'm not sure about the added complexity? |
Yep, it is hot, in the sense that is always hit, causing allocations for no reasons. |
Have you tried either compiling the pattern or using a StringTokenizer? Because that would be far more readable if it’s good enough. |
I will happily do it and will use the benchmark to check how it compare; do you want me to turn the pr in draft in the meantime? |
I did it. |
Not for single char strings use cases: there's an optimization to avoid creating any pattern, see: That's implementing something similar to what I do, but I cannot use it for longer Re Starting from recentish (I'm getting old really!) versions of JDK In summary, the tokenizer:
In short, to make it "right" doesn't seem again the right tool for the job |
@gsmet An additional commit to improve the code quality (and performance too): https://github.com/franz1981/java-puzzles/blob/d2d60af3d0dfe7a2567807395138edcb1d1c24f5/src/main/java/red/hat/puzzles/http/AcceptCharsetParseBenchmark.java#L198 it's the method using Reporting the code here for simplicity private static String getCharsetTokenizer(String mimeType) {
if (mimeType != null) {
var charsets = new StringTokenizer(mimeType, ";", false);
while (charsets.hasMoreTokens()) {
final String charset = charsets.nextToken().trim();
if (charset.startsWith("charset=")) {
return charset.substring(8);
}
}
}
return StandardCharsets.UTF_8.name();
} The reason why is slower, reported below, is because it doesn't use any intrinsic of the JVM but perform search one char at time, while the current PR is making use of some JVM optimized method to search for the charset string. The results are these (for the same commit) and e1cd392 as well:
In short, the new version is 10X faster and can be (we need to decide which charsets to look-up) 0 garbage. |
thanks to the latest changes mentioned in #33693, this PR now is a bit more relevant, because there's not anymore a single big bottleneck that's dominant if compared to this one. |
...ntime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLExecutionHandler.java
Show resolved
Hide resolved
7be2371
to
f3e89f8
Compare
f3e89f8
to
e52f492
Compare
e52f492
to
eb3ae88
Compare
✔️ The latest workflow run for the pull request has completed successfully. It should be safe to merge provided you have a look at the other checks in the summary. |
I've created a benchmark at https://github.com/franz1981/java-puzzles/blob/4a080cb08ada854a44877748f25a434e91b0b3a2/src/main/java/red/hat/puzzles/http/AcceptCharsetParseBenchmark.java can be run isolation.
The results using
JDK 17.0.6, OpenJDK 64-Bit Server VM, 17.0.6+10
are:The regression in the
*NoSplitNoCharsetNoSemicolon
case is due to a missing check for;
presence upfront, but the overall new performance justify it (ie it's a trade-off).The original issue has was due to the weird performance found at FgForrest/HttpServerEvaluationTest#1
And, by moving from HTTP 2 to 1.1, the allocation flamegraph report the
String::split
ongetCharset
as an (average) hot path, which this PR aim to fix.It's not a game changer, and, in order to make it faster, I'm not anymore checking for
semicolon
presence norOWS
presence before thecharset=
searched, assuming a validator has already enforced it upfront.