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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert escapeMetricName to use strings.Builder #217

Merged
merged 1 commit into from May 17, 2019

Conversation

claytono
Copy link
Contributor

@claytono claytono commented May 16, 2019

This converts escapeMetricName to use strings.Builder instead of allocating a byte array, filling it and then converting it to a string. This also optimizes for the case where the metricName is already valid, and in that case, it just returns the original string.

This reduces memory allocations from 2 per call to 1 per call in the case when the string does need to be escaped, and reduces it to zero memory allocations when the string is already valid.

As discussed in #197, escapeMetricName is called a lot, and even after the improvements there, we still see this pretty far up the list in terms of cpu usage in profiling.

Benchmark before:

$ go test -benchmem -run=^$ github.com/prometheus/statsd_exporter -bench '^(BenchmarkEscapeMetricName)$' -benchtime 30s
goos: darwin
goarch: amd64
pkg: github.com/prometheus/statsd_exporter
BenchmarkEscapeMetricName/clean-8                       2000000000              33.6 ns/op            10 B/op          2 allocs/op
BenchmarkEscapeMetricName/0starts_with_digit-8          500000000               85.9 ns/op            64 B/op          2 allocs/op
BenchmarkEscapeMetricName/with_underscore-8             1000000000              55.7 ns/op            32 B/op          2 allocs/op
BenchmarkEscapeMetricName/with.dot-8                    1000000000              40.2 ns/op            16 B/op          2 allocs/op
BenchmarkEscapeMetricName/with馃槺emoji-8                 1000000000              57.4 ns/op            32 B/op          2 allocs/op
BenchmarkEscapeMetricName/with.*.multiple-8             1000000000              58.5 ns/op            32 B/op          2 allocs/op
BenchmarkEscapeMetricName/test.web-server.foo.bar-8     500000000               74.3 ns/op            64 B/op          2 allocs/op
BenchmarkEscapeMetricName/#00-8                         5000000000               9.59 ns/op            0 B/op          0 allocs/op
PASS
ok      github.com/prometheus/statsd_exporter   449.792s

Benchmark after:

go test -benchmem -run=^$ github.com/prometheus/statsd_exporter -bench '^(B
enchmarkEscapeMetricName)$' -benchtime 30s
goos: darwin
goarch: amd64
pkg: github.com/prometheus/statsd_exporter
BenchmarkEscapeMetricName/clean-8                       5000000000              8.42 ns/op            0 B/op          0 allocs/op
BenchmarkEscapeMetricName/0starts_with_digit-8          1000000000              45.0 ns/op            32 B/op          1 allocs/op
BenchmarkEscapeMetricName/with_underscore-8             3000000000              15.1 ns/op             0 B/op          0 allocs/op
BenchmarkEscapeMetricName/with.dot-8                    1000000000              37.3 ns/op             8 B/op          1 allocs/op
BenchmarkEscapeMetricName/with馃槺emoji-8                 1000000000              50.5 ns/op            16 B/op          1 allocs/op
BenchmarkEscapeMetricName/with.*.multiple-8             1000000000              58.9 ns/op            16 B/op          1 allocs/op
BenchmarkEscapeMetricName/test.web-server.foo.bar-8     500000000               75.3 ns/op            32 B/op          1 allocs/op
BenchmarkEscapeMetricName/#00-8                         10000000000             2.09 ns/op            0 B/op          0 allocs/op
PASS
ok      github.com/prometheus/statsd_exporter   367.326s

As you can see from the benchmarks, the common case where no escaping needs to be done is about 3-4x faster.

This converts escapeMetricName to use strings.Builder instead of
allocating a byte array, filling it and then converting it to a string.
This also optimizes for the case where the metricName is already valid,
and in that case, it just returns the original string.

This reduces memory allocations from 2 per call to 1 per call in the
case when the string does need to be escaped, and reduces it to zero
memory allocations when the string is already valid.

Signed-off-by: Clayton O'Neill <claytono@github.com>
@claytono claytono marked this pull request as ready for review May 16, 2019 13:42
@matthiasr
Copy link
Contributor

TIL about strings.Builder 馃槃 thank you!

@matthiasr matthiasr merged commit 27d9273 into prometheus:master May 17, 2019
matthiasr pushed a commit that referenced this pull request May 17, 2019
Signed-off-by: Matthias Rampke <mr@soundcloud.com>
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