Skip to content

Conversation

@iamdanfox
Copy link
Contributor

@iamdanfox iamdanfox commented Jun 15, 2021

Before this PR: 416 bytes / op

From 1 minute JFR, the hottest method in my application is currently java.util.regex, and the biggest proportion of these Matcher constructions are coming from the lovely OrderableSlsVersion#safeValueOf

image

This seems a bit silly, given that most of the time we're trying to parse three numbers with dots in between them.

Benchmark                                                         (versionString)  Mode  Cnt     Score      Error   Units
SlsVersionBenchmark.safeValueOf                                           RELEASE  avgt    3   176.778 ±   30.231   ns/op
SlsVersionBenchmark.safeValueOf:·gc.alloc.rate                            RELEASE  avgt    3  7690.289 ± 1225.982  MB/sec
SlsVersionBenchmark.safeValueOf:·gc.alloc.rate.norm                       RELEASE  avgt    3   416.021 ±    0.007    B/op
SlsVersionBenchmark.safeValueOf:·gc.churn.G1_Eden_Space                   RELEASE  avgt    3  7751.897 ± 1363.284  MB/sec
SlsVersionBenchmark.safeValueOf:·gc.churn.G1_Eden_Space.norm              RELEASE  avgt    3   419.352 ±   10.138    B/op
SlsVersionBenchmark.safeValueOf:·gc.churn.G1_Survivor_Space               RELEASE  avgt    3     0.035 ±    0.064  MB/sec
SlsVersionBenchmark.safeValueOf:·gc.churn.G1_Survivor_Space.norm          RELEASE  avgt    3     0.002 ±    0.004    B/op
SlsVersionBenchmark.safeValueOf:·gc.count                                 RELEASE  avgt    3   184.000             counts
SlsVersionBenchmark.safeValueOf:·gc.time                                  RELEASE  avgt    3   103.000                 ms

After this PR: 104 bytes / op

==COMMIT_MSG==
Deserializing a verison of the form x.y.z now allocates less. This should mean GC algorithms have less work to do.
==COMMIT_MSG==


Benchmark                                                         (versionString)  Mode  Cnt     Score       Error   Units
SlsVersionBenchmark.safeValueOf                                           RELEASE  avgt    3    55.592 ±   109.978   ns/op
SlsVersionBenchmark.safeValueOf:·gc.alloc.rate                            RELEASE  avgt    3  6158.567 ± 11630.568  MB/sec
SlsVersionBenchmark.safeValueOf:·gc.alloc.rate.norm                       RELEASE  avgt    3   104.006 ±     0.002    B/op
SlsVersionBenchmark.safeValueOf:·gc.churn.G1_Eden_Space                   RELEASE  avgt    3  6200.873 ± 12743.698  MB/sec
SlsVersionBenchmark.safeValueOf:·gc.churn.G1_Eden_Space.norm              RELEASE  avgt    3   104.656 ±    22.149    B/op
SlsVersionBenchmark.safeValueOf:·gc.churn.G1_Survivor_Space               RELEASE  avgt    3     0.019 ±     0.067  MB/sec
SlsVersionBenchmark.safeValueOf:·gc.churn.G1_Survivor_Space.norm          RELEASE  avgt    3    ≈ 10⁻³                B/op
SlsVersionBenchmark.safeValueOf:·gc.count                                 RELEASE  avgt    3   147.000              counts
SlsVersionBenchmark.safeValueOf:·gc.time                                  RELEASE  avgt    3    88.000                  ms

Possible downsides?

@policy-bot policy-bot bot requested a review from tetigi June 15, 2021 01:31
@iamdanfox iamdanfox removed the request for review from tetigi June 15, 2021 01:37
@iamdanfox iamdanfox changed the base branch from dfox/less-regex to develop June 15, 2021 16:04
@changelog-app
Copy link

changelog-app bot commented Jun 15, 2021

Generate changelog in changelog/@unreleased

Type

  • Feature
  • Improvement
  • Fix
  • Break
  • Deprecation
  • Manual task
  • Migration

Description

Parsing the simplest x.y.z type of OrderableSlsVersion no longer uses regexes. Allocation is reduced by about 75%

Check the box to generate changelog(s)

  • Generate changelog entry

* We bit-pack these two integer values into a single long using {@link Parsers#ok} and {@link Parsers#fail} functions
* because primitive longs live on the stack and don't impact GC.
*/
final class Parsers {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all these functions just got moved from SlsVersionMatcherParser.java - no changes made here.

@iamdanfox iamdanfox changed the title [mainly just for fun] Hand rolled parser for SlsVersionType.RELEASE (aka x.y.z) Hand rolled parser for SlsVersionType.RELEASE (aka x.y.z) Jun 16, 2021
state = Parsers.literalDot(string, Parsers.getIndex(state));
if (Parsers.failed(state)) {
return null;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just begging for some kind of monadic bind abstraction... but obviously that would require a lot of allocation in Java.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

totally agree

if (Parsers.failed(state)) {
return null;
}
int third = Parsers.getResult(state);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking maybe you could make this less duplicated by having a for loop - but then you'd need to either make an an array or have Int3MatchResult be mutable/have a builder.

You could also group literalDot/number into a method, but it would need to return Integer so it can be nullable, which would I guess would be bad.

@CRogers
Copy link

CRogers commented Jun 21, 2021

👍

@svc-autorelease
Copy link
Collaborator

Released 0.18.0

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants