aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Cottrell <iancottrell@google.com>2020-04-14 13:46:09 -0400
committerIan Cottrell <iancottrell@google.com>2020-04-16 04:05:44 +0000
commit18395615f27d20f395846ededb3929c61a03f9ef (patch)
tree77aad04710900cf6db4da33762a49aa90f216a7e
parentbe55493b8865eee6276c0e29aa5890654e65c8a1 (diff)
downloadgolang-x-tools-18395615f27d20f395846ededb3929c61a03f9ef.tar.gz
internal/telemetry: pack strings efficiently into tags
TagOfString() deconstructs a string into length and data pointer using the unsafe package, and then stores the length into Tag.packed and the pointer into Tag.untyped, which it can do without allocations. Tag.UnpackString can reconstruct a string on access also using the unsafe package to rebuild the string header. This makes tag significantly smaller, which in turn makes things a faster name old time/op new time/op delta /Baseline-8 160ns ± 6% 158ns ± 8% ~ /StdLog-8 7.50µs ± 8% 7.47µs ±20% ~ /LogNoExporter-8 1.13µs ± 7% 1.04µs ± 2% -8.08% /TraceNoExporter-8 3.61µs ±15% 2.96µs ± 5% -18.08% /StatsNoExporter-8 1.65µs ± 7% 1.39µs ± 7% -16.14% /LogNoop-8 4.43µs ±14% 4.05µs ± 7% ~ /TraceNoop-8 10.9µs ± 5% 10.1µs ± 8% ~ /StatsNoop-8 8.08µs ± 3% 7.42µs ±13% ~ /Log-8 16.2µs ±14% 13.4µs ± 3% -17.10% /Trace-8 61.7µs ±22% 53.6µs ± 7% ~ /Stats-8 11.3µs ±10% 9.5µs ± 4% -15.56% name old alloc/op new alloc/op delta /Baseline-8 0.00B 0.00B ~ /StdLog-8 552B ± 0% 552B ± 0% ~ /LogNoExporter-8 0.00B 0.00B ~ /TraceNoExporter-8 3.58kB ± 0% 2.82kB ± 0% -21.43% /StatsNoExporter-8 0.00B 0.00B ~ /LogNoop-8 3.58kB ± 0% 2.82kB ± 0% -21.43% /TraceNoop-8 11.5kB ± 0% 9.2kB ± 0% -20.00% /StatsNoop-8 7.17kB ± 0% 5.63kB ± 0% -21.43% /Log-8 3.58kB ± 0% 2.82kB ± 0% -21.43% /Trace-8 27.9kB ± 0% 23.6kB ± 0% -15.60% /Stats-8 7.17kB ± 0% 5.63kB ± 0% -21.43% name old allocs/op new allocs/op delta /Baseline-8 0.00 0.00 ~ /StdLog-8 30.0 ± 0% 30.0 ± 0% ~ /LogNoExporter-8 0.00 0.00 ~ /TraceNoExporter-8 16.0 ± 0% 16.0 ± 0% ~ /StatsNoExporter-8 0.00 0.00 ~ /LogNoop-8 16.0 ± 0% 16.0 ± 0% ~ /TraceNoop-8 64.0 ± 0% 64.0 ± 0% ~ /StatsNoop-8 32.0 ± 0% 32.0 ± 0% ~ /Log-8 16.0 ± 0% 16.0 ± 0% ~ /Trace-8 384 ± 0% 384 ± 0% ~ /Stats-8 32.0 ± 0% 32.0 ± 0% ~ Change-Id: If5c369f138b60435f1aa74120aa3c1b68baae402 Reviewed-on: https://go-review.googlesource.com/c/tools/+/228234 Run-TryBot: Ian Cottrell <iancottrell@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
-rw-r--r--internal/telemetry/event/tag.go20
1 files changed, 17 insertions, 3 deletions
diff --git a/internal/telemetry/event/tag.go b/internal/telemetry/event/tag.go
index 2d4fa506c..8476bc967 100644
--- a/internal/telemetry/event/tag.go
+++ b/internal/telemetry/event/tag.go
@@ -7,6 +7,8 @@ package event
import (
"fmt"
"io"
+ "reflect"
+ "unsafe"
)
// Tag holds a key and value pair.
@@ -14,7 +16,6 @@ import (
type Tag struct {
key Key
packed uint64
- str string
untyped interface{}
}
@@ -82,13 +83,26 @@ func (t Tag) Unpack64() uint64 { return t.packed }
// TagOfString creates a new tag from a key and a string.
// This method is for implementing new key types, tag creation should
// normally be done with the Of method of the key.
-func TagOfString(k Key, v string) Tag { return Tag{key: k, str: v} }
+func TagOfString(k Key, v string) Tag {
+ hdr := (*reflect.StringHeader)(unsafe.Pointer(&v))
+ return Tag{
+ key: k,
+ packed: uint64(hdr.Len),
+ untyped: unsafe.Pointer(hdr.Data),
+ }
+}
// UnpackString assumes the tag was built using TagOfString and returns the
// value that was passed to that constructor.
// This method is for implementing new key types, for type safety normal
// access should be done with the From method of the key.
-func (t Tag) UnpackString() string { return t.str }
+func (t Tag) UnpackString() string {
+ var v string
+ hdr := (*reflect.StringHeader)(unsafe.Pointer(&v))
+ hdr.Data = uintptr(t.untyped.(unsafe.Pointer))
+ hdr.Len = int(t.packed)
+ return *(*string)(unsafe.Pointer(hdr))
+}
// Valid returns true if the Tag is a valid one (it has a key).
func (t Tag) Valid() bool { return t.key != nil }