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

pat: remove allocation in match.Value(internal.Path) case #68

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

bpowers
Copy link

@bpowers bpowers commented Jul 26, 2022

hi @zenazn!

In an application I was benchmarking, about 40% of allocations per API request were from match.Value returning a string, and that return implicitly moving the string onto the heap for reference as an interface{} ( https://github.com/golang/go/blob/master/src/runtime/iface.go#L388-L396 ). I plan to separately deal with that inefficient call pattern, but it will be more involved, and removing this allocation is relatively straight forward.

I attempted a separate approach of trying to "just" use context.WithValue instead of match, but as you might have guessed that turned out to be ... not really workable ( https://github.com/goji/goji/compare/master...bpowers:goji:use-vanilla-ctx?expand=1 for reference).

I think the biggest thing would be a double-check on my assumption that matches are immutable, so taking a reference to an entry in the slice is safe.

I'd also be happy to rebase this on the v3 branch if thats more palatable!

return m.matches[len(m.matches)-1]
// matches are immutable once made, so return a pointer to
// the path string to avoid a hot-path allocation (passing
// string into an interface{} allocates 24-bytes on the heap)q
Copy link
Member

Choose a reason for hiding this comment

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

trailing q

@zenazn
Copy link
Member

zenazn commented Jul 28, 2022

Gosh, it's been a little while since I thought about this code! Some day I'd like to buy you a beer and figure out what kind of application you're running to make it worth chasing after 24-byte allocations :)

It weirds me out that the context value corresponding to internal.Path doesn't have a consistent type. For instance, why don't we need to update

path := ctx.Value(internal.Path).(string)
as well? If you have an explanation, happy to hear that, but as a general rule of thumb I think I'd feel better if the entire library agreed on what type that value had. (IIRC, the core goji code uses the internal names directly instead of the accessors for performance)

As for your match immutability question: yes—it's intended to be immutable! I think there's some version of this code that's safe. It might even be this one!

I think the v3 branch was a failed attempt to make Go modules work. Unfortunately the v2 tag of this repo predates the Go modules versioning rules :/

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.

None yet

2 participants