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  }