github.com/grafana/pyroscope-go/godeltaprof@v0.1.8-0.20240513050943-1b1f97373e2a/internal/pprof/delta_mutex.go (about) 1 package pprof 2 3 import ( 4 "io" 5 "runtime" 6 ) 7 8 type DeltaMutexProfiler struct { 9 m profMap 10 mem []memMap 11 Options ProfileBuilderOptions 12 } 13 14 // PrintCountCycleProfile outputs block profile records (for block or mutex profiles) 15 // as the pprof-proto format output. Translations from cycle count to time duration 16 // are done because The proto expects count and time (nanoseconds) instead of count 17 // and the number of cycles for block, contention profiles. 18 // Possible 'scaler' functions are scaleBlockProfile and scaleMutexProfile. 19 func (d *DeltaMutexProfiler) PrintCountCycleProfile(w io.Writer, countName, cycleName string, scaler MutexProfileScaler, records []runtime.BlockProfileRecord) error { 20 if d.mem == nil || !d.Options.LazyMapping { 21 d.mem = readMapping() 22 } 23 // Output profile in protobuf form. 24 b := newProfileBuilder(w, d.Options, d.mem) 25 b.pbValueType(tagProfile_PeriodType, countName, "count") 26 b.pb.int64Opt(tagProfile_Period, 1) 27 b.pbValueType(tagProfile_SampleType, countName, "count") 28 b.pbValueType(tagProfile_SampleType, cycleName, "nanoseconds") 29 30 cpuGHz := float64(runtime_cyclesPerSecond()) / 1e9 31 32 values := []int64{0, 0} 33 var locs []uint64 34 for _, r := range records { 35 count, nanosec := ScaleMutexProfile(scaler, r.Count, float64(r.Cycles)/cpuGHz) 36 inanosec := int64(nanosec) 37 38 // do the delta 39 entry := d.m.Lookup(r.Stack(), 0) 40 values[0] = count - entry.count.v1 41 values[1] = inanosec - entry.count.v2 42 entry.count.v1 = count 43 entry.count.v2 = inanosec 44 45 if values[0] < 0 || values[1] < 0 { 46 continue 47 } 48 if values[0] == 0 && values[1] == 0 { 49 continue 50 } 51 52 // For count profiles, all stack addresses are 53 // return PCs, which is what appendLocsForStack expects. 54 locs = b.appendLocsForStack(locs[:0], r.Stack()) 55 b.pbSample(values, locs, nil) 56 } 57 b.build() 58 return nil 59 }