github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/convert/profile_extra_bench_test.go (about) 1 package convert 2 3 import ( 4 "bytes" 5 "compress/gzip" 6 "fmt" 7 "os" 8 "testing" 9 10 "github.com/pyroscope-io/pyroscope/pkg/agent/spy" 11 "github.com/pyroscope-io/pyroscope/pkg/storage/tree" 12 ) 13 14 func BenchmarkProfile_Get(b *testing.B) { 15 buf, _ := os.ReadFile("testdata/cpu.pprof") 16 g, _ := gzip.NewReader(bytes.NewReader(buf)) 17 p, _ := ParsePprof(g) 18 noop := func(labels *spy.Labels, name []byte, val int) error { return nil } 19 b.ResetTimer() 20 21 b.Run("ByteBufferPool", func(b *testing.B) { 22 for i := 0; i < b.N; i++ { 23 _ = p.Get("samples", noop) 24 } 25 }) 26 } 27 28 // parse emulates the parsing work needed to write profiles, without the writing part. 29 func parse(p *tree.Profile) int { 30 var b bytes.Buffer 31 for _, s := range p.Sample { 32 for i := len(s.LocationId) - 1; i >= 0; i-- { 33 loc, ok := tree.FindLocation(p, s.LocationId[i]) 34 if !ok { 35 continue 36 } 37 for j := len(loc.Line) - 1; j >= 0; j-- { 38 fn, found := tree.FindFunction(p, loc.Line[j].FunctionId) 39 if !found { 40 continue 41 } 42 if b.Len() > 0 { 43 _ = b.WriteByte(';') 44 } 45 _, _ = b.WriteString(p.StringTable[fn.Name]) 46 } 47 } 48 } 49 return len(b.Bytes()) 50 } 51 52 // parseWithCache is like parse, but locations and functions are tabled first. 53 func parseWithCache(p *tree.Profile) int { 54 finder := tree.NewFinder(p) 55 var b bytes.Buffer 56 for _, s := range p.Sample { 57 for i := len(s.LocationId) - 1; i >= 0; i-- { 58 loc, ok := finder.FindLocation(s.LocationId[i]) 59 if !ok { 60 continue 61 } 62 for j := len(loc.Line) - 1; j >= 0; j-- { 63 fn, ok := finder.FindFunction(loc.Line[j].FunctionId) 64 if !ok { 65 continue 66 } 67 if b.Len() > 0 { 68 _ = b.WriteByte(';') 69 } 70 _, _ = b.WriteString(p.StringTable[fn.Name]) 71 } 72 } 73 } 74 return len(b.Bytes()) 75 } 76 77 func BenchmarkProfile_ParseNoCache(b *testing.B) { 78 buf, _ := os.ReadFile("testdata/cpu.pprof") 79 p, _ := ParsePprof(bytes.NewReader(buf)) 80 81 b.ResetTimer() 82 83 b.Run(fmt.Sprintf("Locations: %d, functions %d", len(p.Location), len(p.Function)), func(b *testing.B) { 84 for i := 0; i < b.N; i++ { 85 _ = parse(p) 86 } 87 }) 88 } 89 90 func BenchmarkProfile_ParseWithCache(b *testing.B) { 91 buf, _ := os.ReadFile("testdata/cpu.pprof") 92 p, _ := ParsePprof(bytes.NewReader(buf)) 93 94 b.ResetTimer() 95 96 b.Run(fmt.Sprintf("Locations: %d, functions %d", len(p.Location), len(p.Function)), func(b *testing.B) { 97 for i := 0; i < b.N; i++ { 98 _ = parseWithCache(p) 99 } 100 }) 101 } 102 103 func BenchmarkProfile_ParseNoCache_Big(b *testing.B) { 104 buf, _ := os.ReadFile("testdata/cpu-big.pprof") 105 p, _ := ParsePprof(bytes.NewReader(buf)) 106 107 b.ResetTimer() 108 109 b.Run(fmt.Sprintf("Locations: %d, functions %d", len(p.Location), len(p.Function)), func(b *testing.B) { 110 for i := 0; i < b.N; i++ { 111 _ = parse(p) 112 } 113 }) 114 } 115 116 func BenchmarkProfile_ParseWithCache_Big(b *testing.B) { 117 buf, _ := os.ReadFile("testdata/cpu-big.pprof") 118 p, _ := ParsePprof(bytes.NewReader(buf)) 119 120 b.ResetTimer() 121 122 b.Run(fmt.Sprintf("Locations %d, functions %d", len(p.Location), len(p.Function)), func(b *testing.B) { 123 for i := 0; i < b.N; i++ { 124 _ = parseWithCache(p) 125 } 126 }) 127 }