Documentation ¶
Overview ¶
Package fastdelta tries to match up samples between two pprof profiles and take their difference. A sample is a unique (call stack, labels) pair with an associated sequence of values, where "call stack" refers to a sequence of program counters/instruction addresses, and labels are key/value pairs associated with a stack (so we can have the same call stack appear in two different samples if the labels are different)
The github.com/google/pprof already implements this functionality as profile.Merge, but unfortunately it's causing an extreme amount of allocations and memory usage. This package provides an alternative implementation that has been highly optimized to be allocation free once steady-state is reached (no more new samples are added) and to also use a minimum amount of memory and allocations while growing.
Implementation ¶
Computing the delta profile takes six passes over the input:
Pass 1 * Build a mapping of location IDs to instruction addresses * Build the string table, so we can resolve label keys and values * Find the sample types by name, so we know which sample values to compute differences for
Pass 2 * For each sample, aggregate the value for the sample. The Go runtime heap profile can sometimes contain multiple samples with the same call stack and labels, which should actually be aggregated into one sample.
Pass 3 * Compute the delta values for each sample usings its previous values and write them out if this leaves us with at least one non-zero values. * Update the previous sample values for the next round. * Keep track of the locations and strings we need given the samples we wrote out.
Pass 4 * Write out all fields that were referenced by the samples in Pass 3. * Keep track of strings and function ids we need to emit in the next pass.
Pass 5 * Write out the functions we need and keep track of their strings.
Pass 6 * Write out all the strings that were referenced by previous passes. * For strings not referenced, write out a zero-length byte to save space while preserving index references in the included messages
Note: It's possible to do all of the above with less passes, but doing so requires keeping more stuff in memory. Since extra passes are relatively cheap and our CPU usage is pretty low (~100ms for a 10MB heap profile), we prefer optimizing for lower memory usage as there is a larger chance that customers will complain about it.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type DeltaComputer ¶
type DeltaComputer struct {
// contains filtered or unexported fields
}
DeltaComputer calculates the difference between pprof-encoded profiles
func NewDeltaComputer ¶
func NewDeltaComputer(fields ...pprofutils.ValueType) *DeltaComputer
NewDeltaComputer initializes a DeltaComputer which will calculate the difference between the values for profile samples whose fields have the given names (e.g. "alloc_space", "contention", ...)
func (*DeltaComputer) Delta ¶
func (dc *DeltaComputer) Delta(p []byte, out io.Writer) error
Delta calculates the difference between the pprof-encoded profile p and the profile passed in to the previous call to Delta. The encoded delta profile will be written to out.
The first time Delta is called, the internal state of the DeltaComputer will be updated and the profile will be written unchanged.
type DeltaMap ¶
type DeltaMap struct {
// contains filtered or unexported fields
}
DeltaMap ...
func NewDeltaMap ¶
func NewDeltaMap(st *stringTable, lx *locationIndex, fields []valueType) *DeltaMap
NewDeltaMap ...
func (*DeltaMap) AddSampleType ¶
func (dm *DeltaMap) AddSampleType(st *pproflite.SampleType) error
AddSampleType ...
type DenseIntSet ¶
type DenseIntSet struct {
// contains filtered or unexported fields
}
DenseIntSet ...
type SparseIntSet ¶
type SparseIntSet struct {
// contains filtered or unexported fields
}
SparseIntSet ...