Skip to content
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

use a strings.Replacer to reverse names in internal/abi #892

Merged
merged 2 commits into from
Dec 1, 2024

Conversation

mvdan
Copy link
Member

@mvdan mvdan commented Nov 27, 2024

(see commit message)

@mvdan mvdan requested a review from lu4p November 27, 2024 23:52
@mvdan
Copy link
Member Author

mvdan commented Nov 27, 2024

Here's my initial stab at a less naive algorithm.

@lu4p
Copy link
Member

lu4p commented Nov 28, 2024

This is a lot of code even if its lifted from std.

Can you time how long this actually takes with a huge struct and compare before after?

I did some napkin math and think the before is fine even for comically large structs.

@lu4p
Copy link
Member

lu4p commented Nov 28, 2024

If this is actually beneficial is there a way import/ linkname/ insert this code from std instead of having it in this repo?

@mvdan
Copy link
Member Author

mvdan commented Nov 29, 2024

Fair enough, I'll come back with some benchmarks.

We can't reuse strings.Replacer directly, no. For one, it uses reflection, which I explain in the comment at the top. And also, we can't assume that a main package already depends on strings, so we would have to inject it as a dependency before we do any go list -deps -json -compiled call, which complicates the tool. This copies what is effectively 100 or so lines of code, so I think that's fine in comparison.

This way, rather than using a double loop quadratic algorithm
to search for each name to replace in a string,
we can make use of the reasonably efficient generic replacer
which makes use of tries.

Copying some code from the strings package is not ideal,
but it beats having to re-implement such an algorithm ourselves.

Not only is the algorithm much faster, as we are no longer quadratic,
but the replacer also appends into a buffer to avoid repeated string
copies, which means we allocate fewer bytes per operation.

                       │      old       │                new                 │
                       │     sec/op     │   sec/op     vs base               │
    AbiOriginalNames-8   135708.0n ± 0%   391.1n ± 5%  -99.71% (p=0.001 n=7)

                       │     old      │                   new                    │
                       │     B/s      │      B/s        vs base                  │
    AbiOriginalNames-8   2.565Mi ± 0%   890.112Mi ± 4%  +34597.03% (p=0.001 n=7)

                       │     old     │                new                │
                       │    B/op     │    B/op     vs base               │
    AbiOriginalNames-8   5464.0 ± 0%   848.0 ± 0%  -84.48% (p=0.001 n=7)

                       │    old     │                new                │
                       │ allocs/op  │ allocs/op   vs base               │
    AbiOriginalNames-8   18.00 ± 0%   16.00 ± 0%  -11.11% (p=0.001 n=7)
@mvdan
Copy link
Member Author

mvdan commented Dec 1, 2024

The speedup, as measured, is over 200x. So yes, I still think this is worth adding. Plus, we allocate less too, which is also rather important for such a low level API.

Now that we only use the list to create a replacer at init time,
we no longer need to spend extra effort sorting by length first.
The benchmark shows no measurable difference in performance.
@lu4p lu4p merged commit 30d1d8c into burrowers:master Dec 1, 2024
4 checks passed
@mvdan mvdan deleted the abi-replacer branch December 2, 2024 19:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants