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 }