github.com/grafana/pyroscope@v1.18.0/pkg/phlaredb/schemas/v1/locations.go (about)

     1  package v1
     2  
     3  import (
     4  	"github.com/parquet-go/parquet-go"
     5  
     6  	profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1"
     7  )
     8  
     9  var locationsSchema = parquet.SchemaOf(new(profilev1.Location))
    10  
    11  type LocationPersister struct{}
    12  
    13  func (LocationPersister) Name() string { return "locations" }
    14  
    15  func (LocationPersister) Schema() *parquet.Schema { return locationsSchema }
    16  
    17  func (LocationPersister) Deconstruct(row parquet.Row, loc InMemoryLocation) parquet.Row {
    18  	var (
    19  		col    = -1
    20  		newCol = func() int {
    21  			col++
    22  			return col
    23  		}
    24  		totalCols = 4 + (2 * len(loc.Line))
    25  	)
    26  	if cap(row) < totalCols {
    27  		row = make(parquet.Row, 0, totalCols)
    28  	}
    29  	row = row[:0]
    30  	row = append(row, parquet.Int64Value(int64(loc.Id)).Level(0, 0, newCol()))
    31  	row = append(row, parquet.Int32Value(int32(loc.MappingId)).Level(0, 0, newCol()))
    32  	row = append(row, parquet.Int64Value(int64(loc.Address)).Level(0, 0, newCol()))
    33  
    34  	newCol()
    35  	if len(loc.Line) == 0 {
    36  		row = append(row, parquet.Value{}.Level(0, 0, col))
    37  	}
    38  	repetition := -1
    39  	for i := range loc.Line {
    40  		if repetition < 1 {
    41  			repetition++
    42  		}
    43  		row = append(row, parquet.Int32Value(int32(loc.Line[i].FunctionId)).Level(repetition, 1, col))
    44  	}
    45  
    46  	newCol()
    47  	if len(loc.Line) == 0 {
    48  		row = append(row, parquet.Value{}.Level(0, 0, col))
    49  	}
    50  	repetition = -1
    51  	for i := range loc.Line {
    52  		if repetition < 1 {
    53  			repetition++
    54  		}
    55  		row = append(row, parquet.Int32Value(loc.Line[i].Line).Level(repetition, 1, col))
    56  	}
    57  
    58  	row = append(row, parquet.BooleanValue(loc.IsFolded).Level(0, 0, newCol()))
    59  	return row
    60  }
    61  
    62  func (LocationPersister) Reconstruct(row parquet.Row) (InMemoryLocation, error) {
    63  	loc := InMemoryLocation{
    64  		Id:        row[0].Uint64(),
    65  		MappingId: uint32(row[1].Uint64()),
    66  		Address:   row[2].Uint64(),
    67  		IsFolded:  row[len(row)-1].Boolean(),
    68  	}
    69  	lines := row[3 : len(row)-1]
    70  	if len(lines) == 2 && lines[0].DefinitionLevel() == 0 {
    71  		loc.Line = make([]InMemoryLine, 0)
    72  		return loc, nil
    73  	}
    74  	loc.Line = make([]InMemoryLine, len(lines)/2)
    75  	for i, v := range lines[:len(lines)/2] {
    76  		loc.Line[i].FunctionId = uint32(v.Uint64())
    77  	}
    78  	for i, v := range lines[len(lines)/2:] {
    79  		loc.Line[i].Line = int32(v.Uint64())
    80  	}
    81  	return loc, nil
    82  }
    83  
    84  type InMemoryLocation struct {
    85  	// Unique nonzero id for the location.  A profile could use
    86  	// instruction addresses or any integer sequence as ids.
    87  	Id uint64
    88  	// The instruction address for this location, if available.  It
    89  	// should be within [Mapping.memory_start...Mapping.memory_limit]
    90  	// for the corresponding mapping. A non-leaf address may be in the
    91  	// middle of a call instruction. It is up to display tools to find
    92  	// the beginning of the instruction if necessary.
    93  	Address uint64
    94  	// The id of the corresponding profile.Mapping for this location.
    95  	// It can be unset if the mapping is unknown or not applicable for
    96  	// this profile type.
    97  	MappingId uint32
    98  	// Provides an indication that multiple symbols map to this location's
    99  	// address, for example due to identical code folding by the linker. In that
   100  	// case the line information above represents one of the multiple
   101  	// symbols. This field must be recomputed when the symbolization state of the
   102  	// profile changes.
   103  	IsFolded bool
   104  	// Multiple line indicates this location has inlined functions,
   105  	// where the last entry represents the caller into which the
   106  	// preceding entries were inlined.
   107  	//
   108  	// E.g., if memcpy() is inlined into printf:
   109  	//
   110  	//	line[0].function_name == "memcpy"
   111  	//	line[1].function_name == "printf"
   112  	Line []InMemoryLine
   113  }
   114  
   115  func (l InMemoryLocation) Clone() InMemoryLocation {
   116  	x := l
   117  	x.Line = make([]InMemoryLine, len(l.Line))
   118  	copy(x.Line, l.Line)
   119  	return x
   120  }
   121  
   122  type InMemoryLine struct {
   123  	// The id of the corresponding profile.Function for this line.
   124  	FunctionId uint32
   125  	// Line number in source code.
   126  	Line int32
   127  }