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

Performance improvements for formatPath #194

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

jcopi
Copy link

@jcopi jcopi commented Jan 22, 2025

The change reduces memory usage of the formatPath function by:

  • Using Grow after creating a strings.Builder to reduce the number of future allocations
  • Does not collect path segments into a slice using strings.Split, instead if iterates over the segments using strings.Cut so that there is no need to allocate a string header per path segment.
  • Changes the interface of Attributes so that the GetAttribute function returns (string, bool) rather than *string. This eliminates the need for a heap allocation of the attribute value in most cases.

The result of this is that formatPath is faster and has a single allocation (assuming the formatted string is <= 2x the length of the pattern).

Running tool: /usr/local/bin/go test -benchmem -run=^$ -bench ^BenchmarkFormatPath$ github.com/IBM-Cloud/go-etcd-rules/rules

goos: darwin
goarch: amd64
pkg: github.com/IBM-Cloud/go-etcd-rules/rules
cpu: Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
BenchmarkFormatPath/3_matching-16         	 7748780	       156.9 ns/op	      96 B/op	       1 allocs/op
BenchmarkFormatPath/5_matching-16         	 4493900	       278.2 ns/op	     112 B/op	       1 allocs/op
BenchmarkFormatPath/10_matching-16        	 2316057	       509.3 ns/op	     208 B/op	       1 allocs/op
BenchmarkFormatPath/3_no_matches-16       	 7766563	       155.1 ns/op	      96 B/op	       1 allocs/op
BenchmarkFormatPath/5_no_matches-16       	 3947868	       302.5 ns/op	     112 B/op	       1 allocs/op
BenchmarkFormatPath/10_no_matches-16      	 2283081	       539.2 ns/op	     208 B/op	       1 allocs/op
PASS
ok  	github.com/IBM-Cloud/go-etcd-rules/rules	10.219s

This also adds benchmarks and tests for the the formatPath function to ensure that functionality has not changed

ENSURE THE FOLLOWING ARE MET:

Below is a brief summary of PR requirements (full list).

  • Your PR title summarizes the changes at a high level (not simply "updated X" or "changes Y")
  • Your PR description links to the issue/design. If not available, includes a full description for the change.
  • Your code contains relevant unit tests.

By opening this PR for review, the author has agreed that these criteria must be met.

By approving this PR, the reviewers have also agreed these criteria have been met and it is ready to be merged.

rules/matcher.go Outdated Show resolved Hide resolved
rules/matcher.go Outdated Show resolved Hide resolved
Joel Copi added 2 commits January 22, 2025 16:36
…tests for that in formatPath

Adds the original implementation of formatPath for comparison in tests and benchmarks
rules/task.go Outdated Show resolved Hide resolved
Comment on lines +78 to +100
func originalFormatPath(pattern string, m Attributes) (string, bool) {
allFound := true
paths := strings.Split(pattern, "/")
result := strings.Builder{}
for _, path := range paths {
if len(path) == 0 {
continue
}
result.WriteString("/")
if strings.HasPrefix(path, ":") {
attr := m.GetAttribute(path[1:])
if attr == nil {
s := path
attr = &s
allFound = false
}
result.WriteString(*attr)
} else {
result.WriteString(path)
}
}
return result.String(), allFound
}
Copy link
Author

Choose a reason for hiding this comment

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

Added the original implementation temporarily as a point of comparison in tests and benchmarks.

Copy link
Contributor

Choose a reason for hiding this comment

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

Results are doc'd can remove this from the PR now.

@jcopi
Copy link
Author

jcopi commented Jan 25, 2025

Benchmark Results

curr_* benchmark runs represent the new implementation in this PR, orig_* runs represent the original implementation.

goos: darwin
goarch: amd64
pkg: github.com/IBM-Cloud/go-etcd-rules/rules
cpu: Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
Benchmark Name count ns/op B/op allocs/op
BenchmarkFormatPath/curr_03_matches-16 6861945 171.8 ns/op 112 B/op 1 allocs/op
BenchmarkFormatPath/orig_03_matches-16 2421471 475.7 ns/op 504 B/op 8 allocs/op
BenchmarkFormatPath/curr_05_matches-16 3146415 376.0 ns/op 432 B/op 2 allocs/op
BenchmarkFormatPath/orig_05_matches-16 1477287 821.0 ns/op 984 B/op 11 allocs/op
BenchmarkFormatPath/curr_10_matches-16 1734121 683.4 ns/op 768 B/op 2 allocs/op
BenchmarkFormatPath/orig_10_matches-16 733143 1516 ns/op 1944 B/op 17 allocs/op
BenchmarkFormatPath/curr_50_matches-16 503605 2241 ns/op 4352 B/op 3 allocs/op
BenchmarkFormatPath/orig_50_matches-16 218018 5055 ns/op 8760 B/op 60 allocs/op
BenchmarkFormatPath/curr_03_missing-16 7513495 151.0 ns/op 112 B/op 1 allocs/op
BenchmarkFormatPath/orig_03_missing-16 2917368 436.9 ns/op 280 B/op 8 allocs/op
BenchmarkFormatPath/curr_05_missing-16 3662947 346.7 ns/op 144 B/op 1 allocs/op
BenchmarkFormatPath/orig_05_missing-16 1734278 673.6 ns/op 376 B/op 10 allocs/op
BenchmarkFormatPath/curr_10_missing-16 2029881 571.8 ns/op 256 B/op 1 allocs/op
BenchmarkFormatPath/orig_10_missing-16 936805 1208 ns/op 760 B/op 16 allocs/op
BenchmarkFormatPath/curr_50_missing-16 934234 1165 ns/op 896 B/op 1 allocs/op
BenchmarkFormatPath/orig_50_missing-16 355747 3293 ns/op 2712 B/op 58 allocs/op
BenchmarkFormatPath/curr_all_slashes-16 5011110 223.8 ns/op 64 B/op 1 allocs/op
BenchmarkFormatPath/orig_all_slashes-16 3893077 303.3 ns/op 352 B/op 1 allocs/op
BenchmarkFormatPath/curr_all_patterns-16 2969810 379.1 ns/op 112 B/op 1 allocs/op
BenchmarkFormatPath/orig_all_patterns-16 871940 1222 ns/op 760 B/op 25 allocs/op

@jcopi jcopi marked this pull request as ready for review January 25, 2025 19:26
@jcopi jcopi marked this pull request as draft January 25, 2025 19:37
rules/matcher.go Outdated Show resolved Hide resolved
func formatPath(pattern string, m Attributes) (string, bool) {
sb := new(strings.Builder)
// If the formatted string can fit into 2x the length of the pattern
Copy link
Contributor

Choose a reason for hiding this comment

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

Cmt should be 2.5x now

@@ -20,6 +20,7 @@ type regexKeyMatcher struct {

type keyMatch interface {
GetAttribute(name string) *string
FindAttribute(name string) (string, bool)
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we add a cmt to the GetAttribute that it's been replaced by FindAttribute?

@kramvan1
Copy link
Contributor

@jcopi Thx for all your work here. We would like to get this in now. I added a few last minor updates and then can create the formal PR for finals reviews.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants