Skip to content
This repository has been archived by the owner on Jul 31, 2023. It is now read-only.

Commit

Permalink
Convert Attribute to a struct (#581)
Browse files Browse the repository at this point in the history
This avoids about 30% of allocations in benchmarks with 3 or more
attributes and sampling enabled.

```
name                     old time/op    new time/op    delta
StartEndSpan-8              522ns ± 0%     502ns ± 0%   ~     (p=1.000 n=1+1)
SpanWithAnnotations_3-8    1.22µs ± 0%    1.08µs ± 0%   ~     (p=1.000 n=1+1)
SpanWithAnnotations_6-8    1.66µs ± 0%    1.29µs ± 0%   ~     (p=1.000 n=1+1)
TraceID_DotString-8         191ns ± 0%     185ns ± 0%   ~     (p=1.000 n=1+1)
SpanID_DotString-8          172ns ± 0%     174ns ± 0%   ~     (p=1.000 n=1+1)

name                     old alloc/op   new alloc/op   delta
StartEndSpan-8               576B ± 0%      576B ± 0%   ~     (all equal)
SpanWithAnnotations_3-8    1.37kB ± 0%    1.27kB ± 0%   ~     (p=1.000 n=1+1)
SpanWithAnnotations_6-8    1.49kB ± 0%    1.30kB ± 0%   ~     (p=1.000 n=1+1)
TraceID_DotString-8         80.0B ± 0%     80.0B ± 0%   ~     (all equal)
SpanID_DotString-8          56.0B ± 0%     56.0B ± 0%   ~     (all equal)

name                     old allocs/op  new allocs/op  delta
StartEndSpan-8               4.00 ± 0%      4.00 ± 0%   ~     (all equal)
SpanWithAnnotations_3-8      13.0 ± 0%      10.0 ± 0%   ~     (p=1.000 n=1+1)
SpanWithAnnotations_6-8      18.0 ± 0%      12.0 ± 0%   ~     (p=1.000 n=1+1)
TraceID_DotString-8          3.00 ± 0%      3.00 ± 0%   ~     (all equal)
SpanID_DotString-8           3.00 ± 0%      3.00 ± 0%   ~     (all equal)
```
  • Loading branch information
Ramon Nogueira authored Mar 14, 2018
1 parent 3539f4d commit 821173a
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 82 deletions.
36 changes: 8 additions & 28 deletions trace/basetypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,46 +41,26 @@ type Annotation struct {
Attributes map[string]interface{}
}

// Attribute is an interface for attributes;
// it is implemented by BoolAttribute, IntAttribute, and StringAttribute.
type Attribute interface {
isAttribute()
// Attribute represents a key-value pair on a span, link or annotation.
// Construct with one of: BoolAttribute, Int64Attribute, or StringAttribute.
type Attribute struct {
key string
value interface{}
}

// BoolAttribute returns a bool-valued attribute.
func BoolAttribute(key string, value bool) Attribute {
return boolAttribute{key: key, value: value}
}

type boolAttribute struct {
key string
value bool
return Attribute{key: key, value: value}
}

func (b boolAttribute) isAttribute() {}

type int64Attribute struct {
key string
value int64
}

func (i int64Attribute) isAttribute() {}

// Int64Attribute returns an int64-valued attribute.
func Int64Attribute(key string, value int64) Attribute {
return int64Attribute{key: key, value: value}
}

type stringAttribute struct {
key string
value string
return Attribute{key: key, value: value}
}

func (s stringAttribute) isAttribute() {}

// StringAttribute returns a string-valued attribute.
func StringAttribute(key string, value string) Attribute {
return stringAttribute{key: key, value: value}
return Attribute{key: key, value: value}
}

// LinkType specifies the relationship between the span that had the link
Expand Down
112 changes: 66 additions & 46 deletions trace/benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,66 +20,86 @@ import (
)

func BenchmarkStartEndSpan(b *testing.B) {
ctx := context.Background()
b.ResetTimer()

for i := 0; i < b.N; i++ {
_, span := StartSpan(ctx, "/foo")
span.End()
}
traceBenchmark(b, func(b *testing.B) {
ctx := context.Background()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, span := StartSpan(ctx, "/foo")
span.End()
}
})
}

func BenchmarkSpanWithAnnotations_3(b *testing.B) {
ctx := context.Background()
b.ResetTimer()
traceBenchmark(b, func(b *testing.B) {
ctx := context.Background()
b.ResetTimer()

for i := 0; i < b.N; i++ {
_, span := StartSpan(ctx, "/foo")
span.SetAttributes(
BoolAttribute("key1", false),
StringAttribute("key2", "hello"),
Int64Attribute("key3", 123),
)
span.End()
}
for i := 0; i < b.N; i++ {
_, span := StartSpan(ctx, "/foo")
span.SetAttributes(
BoolAttribute("key1", false),
StringAttribute("key2", "hello"),
Int64Attribute("key3", 123),
)
span.End()
}
})
}

func BenchmarkSpanWithAnnotations_6(b *testing.B) {
ctx := context.Background()
b.ResetTimer()
traceBenchmark(b, func(b *testing.B) {
ctx := context.Background()
b.ResetTimer()

for i := 0; i < b.N; i++ {
_, span := StartSpan(ctx, "/foo")
span.SetAttributes(
BoolAttribute("key1", false),
BoolAttribute("key2", true),
StringAttribute("key3", "hello"),
StringAttribute("key4", "hello"),
Int64Attribute("key5", 123),
Int64Attribute("key6", 456),
)
span.End()
}
for i := 0; i < b.N; i++ {
_, span := StartSpan(ctx, "/foo")
span.SetAttributes(
BoolAttribute("key1", false),
BoolAttribute("key2", true),
StringAttribute("key3", "hello"),
StringAttribute("key4", "hello"),
Int64Attribute("key5", 123),
Int64Attribute("key6", 456),
)
span.End()
}
})
}

func BenchmarkTraceID_DotString(b *testing.B) {
b.ReportAllocs()
t := TraceID{0x0D, 0x0E, 0x0A, 0x0D, 0x0B, 0x0E, 0x0E, 0x0F, 0x0F, 0x0E, 0x0E, 0x0B, 0x0D, 0x0A, 0x0E, 0x0D}
want := "0d0e0a0d0b0e0e0f0f0e0e0b0d0a0e0d"
for i := 0; i < b.N; i++ {
if got := t.String(); got != want {
b.Fatalf("got = %q want = %q", got, want)
traceBenchmark(b, func(b *testing.B) {
t := TraceID{0x0D, 0x0E, 0x0A, 0x0D, 0x0B, 0x0E, 0x0E, 0x0F, 0x0F, 0x0E, 0x0E, 0x0B, 0x0D, 0x0A, 0x0E, 0x0D}
want := "0d0e0a0d0b0e0e0f0f0e0e0b0d0a0e0d"
for i := 0; i < b.N; i++ {
if got := t.String(); got != want {
b.Fatalf("got = %q want = %q", got, want)
}
}
}
})
}

func BenchmarkSpanID_DotString(b *testing.B) {
b.ReportAllocs()
s := SpanID{0x0D, 0x0E, 0x0A, 0x0D, 0x0B, 0x0E, 0x0E, 0x0F}
want := "0d0e0a0d0b0e0e0f"
for i := 0; i < b.N; i++ {
if got := s.String(); got != want {
b.Fatalf("got = %q want = %q", got, want)
traceBenchmark(b, func(b *testing.B) {
s := SpanID{0x0D, 0x0E, 0x0A, 0x0D, 0x0B, 0x0E, 0x0E, 0x0F}
want := "0d0e0a0d0b0e0e0f"
for i := 0; i < b.N; i++ {
if got := s.String(); got != want {
b.Fatalf("got = %q want = %q", got, want)
}
}
}
})
}

func traceBenchmark(b *testing.B, fn func(*testing.B)) {
b.Run("AlwaysSample", func(b *testing.B) {
b.ReportAllocs()
SetDefaultSampler(AlwaysSample())
fn(b)
})
b.Run("NeverSample", func(b *testing.B) {
b.ReportAllocs()
SetDefaultSampler(NeverSample())
fn(b)
})
}
9 changes: 1 addition & 8 deletions trace/trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,14 +273,7 @@ func (s *Span) SetAttributes(attributes ...Attribute) {
// copyAttributes copies a slice of Attributes into a map.
func copyAttributes(m map[string]interface{}, attributes []Attribute) {
for _, a := range attributes {
switch a := a.(type) {
case boolAttribute:
m[a.key] = a.value
case int64Attribute:
m[a.key] = a.value
case stringAttribute:
m[a.key] = a.value
}
m[a.key] = a.value
}
}

Expand Down

0 comments on commit 821173a

Please sign in to comment.