...
1
18
19 package profiling
20
21 import (
22 "fmt"
23 "strconv"
24 "sync"
25 "testing"
26 "time"
27
28 "google.golang.org/grpc/internal/grpctest"
29 "google.golang.org/grpc/internal/profiling/buffer"
30 )
31
32 type s struct {
33 grpctest.Tester
34 }
35
36 func Test(t *testing.T) {
37 grpctest.RunSubTests(t, s{})
38 }
39
40 func (s) TestProfiling(t *testing.T) {
41 cb, err := buffer.NewCircularBuffer(128)
42 if err != nil {
43 t.Fatalf("error creating circular buffer: %v", err)
44 }
45
46 stat := NewStat("foo")
47 cb.Push(stat)
48 bar := func(n int) {
49 if n%2 == 0 {
50 defer stat.NewTimer(strconv.Itoa(n)).Egress()
51 } else {
52 timer := NewTimer(strconv.Itoa(n))
53 stat.AppendTimer(timer)
54 defer timer.Egress()
55 }
56 time.Sleep(1 * time.Microsecond)
57 }
58
59 numTimers := int(8 * defaultStatAllocatedTimers)
60 for i := 0; i < numTimers; i++ {
61 bar(i)
62 }
63
64 results := cb.Drain()
65 if len(results) != 1 {
66 t.Fatalf("len(results) = %d; want 1", len(results))
67 }
68
69 statReturned := results[0].(*Stat)
70 if stat.Tags != "foo" {
71 t.Fatalf("stat.Tags = %s; want foo", stat.Tags)
72 }
73
74 if len(stat.Timers) != numTimers {
75 t.Fatalf("len(stat.Timers) = %d; want %d", len(stat.Timers), numTimers)
76 }
77
78 lastIdx := 0
79 for i, timer := range statReturned.Timers {
80
81 if n, err := strconv.Atoi(timer.Tags); err != nil && n != lastIdx {
82 t.Fatalf("stat.Timers[%d].Tags = %s; wanted %d", i, timer.Tags, lastIdx)
83 }
84
85
86 if diff := timer.End.Sub(timer.Begin); diff.Nanoseconds() < 1000 {
87 t.Fatalf("stat.Timers[%d].End - stat.Timers[%d].Begin = %v; want >= 1000ns", i, i, diff)
88 }
89
90 lastIdx++
91 }
92 }
93
94 func (s) TestProfilingRace(t *testing.T) {
95 stat := NewStat("foo")
96
97 var wg sync.WaitGroup
98 numTimers := int(8 * defaultStatAllocatedTimers)
99 wg.Add(numTimers)
100 for i := 0; i < numTimers; i++ {
101 go func(n int) {
102 defer wg.Done()
103 if n%2 == 0 {
104 defer stat.NewTimer(strconv.Itoa(n)).Egress()
105 } else {
106 timer := NewTimer(strconv.Itoa(n))
107 stat.AppendTimer(timer)
108 defer timer.Egress()
109 }
110 }(i)
111 }
112 wg.Wait()
113
114 if len(stat.Timers) != numTimers {
115 t.Fatalf("len(stat.Timers) = %d; want %d", len(stat.Timers), numTimers)
116 }
117
118
119
120 seen := make(map[int]bool)
121 for i, timer := range stat.Timers {
122 n, err := strconv.Atoi(timer.Tags)
123 if err != nil {
124 t.Fatalf("stat.Timers[%d].Tags = %s; wanted integer", i, timer.Tags)
125 }
126 seen[n] = true
127 }
128
129 for i := 0; i < numTimers; i++ {
130 if _, ok := seen[i]; !ok {
131 t.Fatalf("seen[%d] = false or does not exist; want it to be true", i)
132 }
133 }
134 }
135
136 func BenchmarkProfiling(b *testing.B) {
137 for routines := 1; routines <= 1<<8; routines <<= 1 {
138 b.Run(fmt.Sprintf("goroutines:%d", routines), func(b *testing.B) {
139 perRoutine := b.N / routines
140 stat := NewStat("foo")
141 var wg sync.WaitGroup
142 wg.Add(routines)
143 for r := 0; r < routines; r++ {
144 go func() {
145 for i := 0; i < perRoutine; i++ {
146 stat.NewTimer("bar").Egress()
147 }
148 wg.Done()
149 }()
150 }
151 wg.Wait()
152 })
153 }
154 }
155
View as plain text