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

Avoid expensive operations in CaptureEvent hot path #256

Merged
merged 4 commits into from
Jun 26, 2020

Conversation

rhcarvalho
Copy link
Contributor

The original motivation was noticing that calling rand.New in Client.processEvent was odd.

Writing a small benchmark reviewed that calling os.Hostname() for every event was also wasteful.

This PR addresses only those two points and is not meant as a comprehensive optimization effort.

The two changes combined result in this benchstat output:

go version go1.14.3 darwin/amd64

name             old time/op    new time/op    delta
ProcessEvent-16    10.3µs ±15%     0.8µs ± 3%  -92.11%  (p=0.000 n=8+7)

name             old alloc/op   new alloc/op   delta
ProcessEvent-16    6.45kB ± 1%    1.02kB ± 0%  -84.14%  (p=0.000 n=8+8)

name             old allocs/op  new allocs/op  delta
ProcessEvent-16      8.25 ± 9%      6.00 ± 0%  -27.27%  (p=0.000 n=8+8)

go version go1.14.4 linux/amd64

name            old time/op    new time/op    delta
ProcessEvent-8    10.9µs ± 0%     1.1µs ± 2%  -89.49%  (p=0.001 n=7+7)

name            old alloc/op   new alloc/op   delta
ProcessEvent-8    6.41kB ± 0%    1.02kB ± 0%  -84.02%  (p=0.000 n=8+8)

name            old allocs/op  new allocs/op  delta
ProcessEvent-8      7.50 ± 7%      6.00 ± 0%  -20.00%  (p=0.000 n=8+8)

The new test checks that the effective sample rate
(events_sent/events_seen ratio) converges to the configured
ClientOptions.SampleRate.

Additionally, because client values are shared among hubs and used
concurrently from multiple goroutines, the test simulates the concurrent
use of a client to detect data races.
The host name typically do not change for the lifetime of a program.

A CPU profile from BenchmarkProcessEvent shows that most of the time is
spent on syscalls to get the host name.

We can precompute the host name once during initialization and avoid
further syscalls, speeding up Client.prepareEvent and, transitively,
Client.processEvent.

name             old time/op    new time/op    delta
ProcessEvent-16    10.6µs ±12%     9.6µs ±12%   -9.31%  (p=0.021 n=8+8)

name             old alloc/op   new alloc/op   delta
ProcessEvent-16    6.49kB ± 0%    6.45kB ± 1%   -0.72%  (p=0.002 n=8+8)

name             old allocs/op  new allocs/op  delta
ProcessEvent-16      9.00 ± 0%      7.62 ± 8%  -15.28%  (p=0.000 n=8+8)
It is wasteful for the client to allocate a new random number generator
for every processed event. Instead, use a single generator, shared and
safe for concurrent use.

name             old time/op    new time/op    delta
ProcessEvent-16    9.08µs ± 2%    0.78µs ± 1%  -91.38%  (p=0.000 n=8+8)

name             old alloc/op   new alloc/op   delta
ProcessEvent-16    6.41kB ± 0%    1.02kB ± 0%  -84.02%  (p=0.000 n=8+8)

name             old allocs/op  new allocs/op  delta
ProcessEvent-16      7.00 ± 0%      6.00 ± 0%  -14.29%  (p=0.002 n=7+8)
// tolerated range is [SampleRate-MaxDelta, SampleRate+MaxDelta]
MaxDelta float64
}{
// {0.00, 0.0}, // oddly, sample rate = 0.0 means 1.0, skip test for now.
Copy link
Contributor

Choose a reason for hiding this comment

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

It's because of zero-value for floats. I had no idea how to reasonably go around it ¯_(ツ)_/¯

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There are a few possibilities like Functional Options; use pointers to detect zero-value vs not-set; etc. All with pros and cons.

Since this is part of sentry.Init, any change would break every example code out there :/

@kamilogorek
Copy link
Contributor

Nice patch!

@rhcarvalho rhcarvalho merged commit 09b37a5 into getsentry:master Jun 26, 2020
@rhcarvalho rhcarvalho deleted the bench-process-event branch June 26, 2020 13:06
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