Skip to content

Commit 58e32e1

Browse files
committed
TODO: review this commit, it has logs and otel only smbolization disabled
1 parent 3bc7ea3 commit 58e32e1

File tree

5 files changed

+95
-44
lines changed

5 files changed

+95
-44
lines changed

pkg/experiment/symbolizer/addrmapper.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ func ExecutableInfoFromELF(f *elf.File) (*BinaryLayout, error) {
5454
// - Different segments might need different adjustments
5555
// - Various ELF types (EXEC, DYN, REL) handle addressing differently
5656
func MapRuntimeAddress(runtimeAddr uint64, ei *BinaryLayout, m Mapping) (uint64, error) {
57+
if runtimeAddr < m.Start || runtimeAddr >= m.Limit {
58+
return 0, fmt.Errorf("address 0x%x out of range for mapping [0x%x-0x%x]",
59+
runtimeAddr, m.Start, m.Limit)
60+
}
61+
5762
baseOffset, err := CalculateBase(ei, m, runtimeAddr)
5863
if err != nil {
5964
return runtimeAddr, fmt.Errorf("calculate base offset: %w", err)
@@ -86,8 +91,6 @@ func CalculateBase(ei *BinaryLayout, m Mapping, addr uint64) (uint64, error) {
8691
switch elf.Type(ei.ElfType) {
8792
case elf.ET_EXEC:
8893
return calculateExecBase(m, segment)
89-
case elf.ET_REL:
90-
return calculateRelocatableBase(m)
9194
case elf.ET_DYN:
9295
return calculateDynamicBase(m, segment)
9396
}
@@ -170,6 +173,7 @@ func (ei *BinaryLayout) FindProgramHeader(m Mapping, addr uint64) (*MemoryRegion
170173
}
171174

172175
func calculateExecBase(m Mapping, h *MemoryRegion) (uint64, error) {
176+
//return 0, nil
173177
if h == nil {
174178
// Check if this is likely a PIE executable or shared library
175179
if m.Start > 0 {

pkg/experiment/symbolizer/debuginfod_client.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func NewDebuginfodClient(l log.Logger, baseURL string, metrics *Metrics) (*Debug
5959
// userAgent: "Pyroscope-Symbolizer/1.0",
6060
httpClient: &http.Client{
6161
Transport: transport,
62-
Timeout: 30 * time.Second,
62+
Timeout: 120 * time.Second,
6363
CheckRedirect: func(req *http.Request, via []*http.Request) error {
6464
if len(via) >= 3 {
6565
return fmt.Errorf("stopped after 3 redirects")

pkg/experiment/symbolizer/dwarf.go

+44-16
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,17 @@ type InlineInfo struct {
3232

3333
// DWARFInfo implements the liner interface
3434
type DWARFInfo struct {
35-
debugData *dwarf.Data
36-
lineEntries map[dwarf.Offset][]dwarf.LineEntry
37-
subprograms map[dwarf.Offset][]*godwarf.Tree
38-
abstractSubprograms map[dwarf.Offset]*dwarf.Entry
39-
addressMap map[uint64]*FunctionInfo // Quick address lookups
40-
functionMap map[string]*FunctionRange // Function name lookups
35+
debugData *dwarf.Data
36+
lineEntries map[dwarf.Offset][]dwarf.LineEntry
37+
subprograms map[dwarf.Offset][]*godwarf.Tree
38+
abstractSubprograms map[dwarf.Offset]*dwarf.Entry
39+
addressMap map[uint64]*FunctionInfo // Quick address lookups
40+
functionMap map[string]*FunctionRange // Function name lookups
41+
lineEntriesSorted map[dwarf.Offset]bool
42+
scannedAbstractSubprograms bool
43+
lastRangeInfo *FunctionInfo
44+
lastRangeStart uint64
45+
lastRangeEnd uint64
4146
}
4247

4348
// NewDWARFInfo creates a new liner using DWARF debug info
@@ -49,6 +54,7 @@ func NewDWARFInfo(debugData *dwarf.Data) *DWARFInfo {
4954
abstractSubprograms: make(map[dwarf.Offset]*dwarf.Entry),
5055
addressMap: make(map[uint64]*FunctionInfo),
5156
functionMap: make(map[string]*FunctionRange),
57+
lineEntriesSorted: make(map[dwarf.Offset]bool),
5258
}
5359
}
5460

@@ -94,7 +100,7 @@ func (d *DWARFInfo) ResolveAddress(_ context.Context, addr uint64) ([]SymbolLoca
94100
declLine = 0
95101
}
96102

97-
file, line := d.findLineInfo(d.lineEntries[cu.Offset], targetTree.Ranges)
103+
file, line := d.findLineInfo(d.lineEntries[cu.Offset], targetTree.Ranges, cu.Offset)
98104
lines = append(lines, SymbolLocation{
99105
Function: &pprof.Function{
100106
Name: functionName,
@@ -247,12 +253,16 @@ func (d *DWARFInfo) processSubprogramEntries(cu *dwarf.Entry) error {
247253
return nil
248254
}
249255

250-
func (d *DWARFInfo) findLineInfo(entries []dwarf.LineEntry, ranges [][2]uint64) (string, int64) {
251-
sort.Slice(entries, func(i, j int) bool {
252-
return entries[i].Address < entries[j].Address
253-
})
256+
func (d *DWARFInfo) findLineInfo(entries []dwarf.LineEntry, ranges [][2]uint64, cuOffset dwarf.Offset) (string, int64) {
257+
// Sort only once per compilation unit
258+
if !d.lineEntriesSorted[cuOffset] {
259+
sort.Slice(entries, func(i, j int) bool {
260+
return entries[i].Address < entries[j].Address
261+
})
262+
d.lineEntriesSorted[cuOffset] = true
263+
}
254264

255-
// Try to find an entry that contains our target address
265+
// Try to find an entry that contains the target address
256266
targetAddr := ranges[0][0]
257267
for _, entry := range entries {
258268
if entry.Address >= targetAddr && entry.Address < ranges[0][1] {
@@ -279,30 +289,48 @@ func (d *DWARFInfo) findLineInfo(entries []dwarf.LineEntry, ranges [][2]uint64)
279289
}
280290

281291
func (d *DWARFInfo) scanAbstractSubprograms() error {
292+
if d.scannedAbstractSubprograms {
293+
return nil
294+
}
295+
282296
reader := d.debugData.Reader()
283-
// Scan from the start, don't stop at first CU
284297
for {
285298
entry, err := reader.Next()
286299
if err != nil || entry == nil {
287300
break
288301
}
289-
290302
if entry.Tag == dwarf.TagSubprogram {
291303
// Store ALL subprograms, not just inline ones
292304
d.abstractSubprograms[entry.Offset] = entry
293305
}
294306
}
307+
308+
d.scannedAbstractSubprograms = true
295309
return nil
296310
}
297311

298312
func (d *DWARFInfo) resolveFromOptimizedMaps(addr uint64) ([]SymbolLocation, bool) {
313+
if info, found := d.addressMap[addr]; found {
314+
return info.Locations, true
315+
}
316+
317+
// Use a simple caching mechanism for the last successful range lookup
318+
if d.lastRangeInfo != nil &&
319+
addr >= d.lastRangeStart && addr < d.lastRangeEnd {
320+
return d.lastRangeInfo.Locations, true
321+
}
322+
299323
for _, info := range d.addressMap {
300324
for _, rang := range info.Ranges {
301325
if addr >= rang.StartAddr && addr < rang.EndAddr {
326+
d.lastRangeInfo = info
327+
d.lastRangeStart = rang.StartAddr
328+
d.lastRangeEnd = rang.EndAddr
302329
return info.Locations, true
303330
}
304331
}
305332
}
333+
306334
return nil, false
307335
}
308336

@@ -317,7 +345,7 @@ func (d *DWARFInfo) buildOptimizedMaps(cuOffset dwarf.Offset) error {
317345
continue
318346
}
319347

320-
filename, line := d.findLineInfo(d.lineEntries[cuOffset], tree.Ranges)
348+
filename, line := d.findLineInfo(d.lineEntries[cuOffset], tree.Ranges, cuOffset)
321349

322350
// Build locations once
323351
locations := []SymbolLocation{{
@@ -375,7 +403,7 @@ func (d *DWARFInfo) processInlineFunctions(tree *godwarf.Tree, addr uint64, cuOf
375403
continue
376404
}
377405

378-
filename, line := d.findLineInfo(d.lineEntries[cuOffset], inline.Ranges)
406+
filename, line := d.findLineInfo(d.lineEntries[cuOffset], inline.Ranges, cuOffset)
379407
inlines = append(inlines, InlineInfo{
380408
Name: inlineName,
381409
File: filename,

pkg/experiment/symbolizer/symbolizer.go

+24-4
Original file line numberDiff line numberDiff line change
@@ -109,18 +109,26 @@ func NewProfileSymbolizer(logger log.Logger, client DebuginfodClient, store Debu
109109
}
110110

111111
func (s *ProfileSymbolizer) SymbolizePprof(ctx context.Context, profile *googlev1.Profile) error {
112+
level.Info(s.logger).Log("msg", ">> starting SymbolizePprof")
112113
start := time.Now()
113114
status := StatusSuccess
114115
defer func() {
115116
s.metrics.profileSymbolization.WithLabelValues(status).Observe(time.Since(start).Seconds())
116117
}()
117118

118-
if !s.NeedsSymbolization(profile) {
119+
if profile == nil || len(profile.Mapping) == 0 {
120+
level.Info(s.logger).Log("msg", "profile is either nil or has no mappings, skipping symbolization")
119121
status = "already_symbolized"
120-
level.Error(s.logger).Log("msg", "Symbolizer exited since profile don't need symbolization")
121122
return nil
122123
}
123124

125+
// if !s.NeedsSymbolization(profile) {
126+
// level.Info(s.logger).Log("msg", ">> don't need symbolization")
127+
// status = "already_symbolized"
128+
// level.Error(s.logger).Log("msg", "Symbolizer exited since profile don't need symbolization")
129+
// return nil
130+
// }
131+
124132
// Group locations by mapping ID
125133
type locToSymbolize struct {
126134
idx int
@@ -171,10 +179,12 @@ func (s *ProfileSymbolizer) SymbolizePprof(ctx context.Context, profile *googlev
171179
}
172180

173181
buildID := profile.StringTable[mapping.BuildId]
182+
level.Info(s.logger).Log("msg", ">> mapping build id --> ", "mapping.BuildId", mapping.BuildId)
183+
level.Info(s.logger).Log("msg", ">> build id --> ", "buildID", buildID)
174184
buildID, err := sanitizeBuildID(buildID)
175185
if err != nil {
176186
status = StatusErrorInvalidID
177-
level.Error(s.logger).Log("msg", "Invalid buildID", buildID)
187+
level.Error(s.logger).Log("msg", "Invalid buildID", "buildID", buildID)
178188
continue
179189
}
180190

@@ -495,7 +505,17 @@ func (s *ProfileSymbolizer) symbolizeFromReader(ctx context.Context, r io.ReadCl
495505
// Get source lines for the address
496506
lines, err := liner.ResolveAddress(ctx, addr)
497507
if err != nil {
498-
level.Error(s.logger).Log("msg", "Failed to resolve address", "addr", fmt.Sprintf("0x%x", addr), "binary", req.BinaryName, "build_id", req.BuildID, "error", err)
508+
level.Error(s.logger).Log(
509+
"msg", "Failed to resolve address",
510+
"addr", fmt.Sprintf("0x%x", addr),
511+
"binary", req.BinaryName,
512+
"build_id", req.BuildID,
513+
"mapping_start", fmt.Sprintf("0x%x", loc.Mapping.Start),
514+
"mapping_limit", fmt.Sprintf("0x%x", loc.Mapping.Limit),
515+
"mapping_offset", fmt.Sprintf("0x%x", loc.Mapping.Offset),
516+
"normalized_addr", fmt.Sprintf("0x%x", addr),
517+
"error", err,
518+
)
499519
loc.Lines = s.createNotFoundSymbols(req.BinaryName, loc, addr)
500520
s.metrics.debugSymbolResolution.WithLabelValues(StatusErrorServerError).Observe(time.Since(resolveStart).Seconds())
501521
continue

pkg/frontend/read_path/query_frontend/query_frontend.go

+20-21
Original file line numberDiff line numberDiff line change
@@ -142,30 +142,29 @@ func (q *QueryFrontend) Query(
142142
continue
143143
}
144144

145-
// TODO: check if whether it comes from OTEL!
146-
isOTEL := isProfileFromOTEL(&prof)
147-
if isOTEL {
148-
if err := q.symbolizer.SymbolizePprof(ctx, &prof); err != nil {
149-
level.Error(q.logger).Log("msg", "symbolize pprof", "err", err)
150-
}
145+
//isOTEL := isProfileFromOTEL(&prof)
146+
//if isOTEL {
147+
if err := q.symbolizer.SymbolizePprof(ctx, &prof); err != nil {
148+
level.Error(q.logger).Log("msg", "symbolize pprof", "err", err)
149+
}
151150

152-
// Convert back to tree if originally a tree
153-
if i < len(req.Query) && req.Query[i].QueryType == queryv1.QueryType_QUERY_TREE {
154-
if len(prof.SampleType) > 1 {
155-
return nil, fmt.Errorf("multiple sample types not supported")
156-
}
157-
treeBytes := model.TreeFromBackendProfile(&prof, req.Query[i].Tree.MaxNodes)
158-
// Store the tree result
159-
r.Tree = &queryv1.TreeReport{Tree: treeBytes}
160-
r.ReportType = queryv1.ReportType_REPORT_TREE
161-
r.Pprof = nil
162-
} else {
163-
symbolizedBytes, err := pprof.Marshal(&prof, true)
164-
if err == nil {
165-
r.Pprof.Pprof = symbolizedBytes
166-
}
151+
// Convert back to tree if originally a tree
152+
if i < len(req.Query) && req.Query[i].QueryType == queryv1.QueryType_QUERY_TREE {
153+
if len(prof.SampleType) > 1 {
154+
return nil, fmt.Errorf("multiple sample types not supported")
155+
}
156+
treeBytes := model.TreeFromBackendProfile(&prof, req.Query[i].Tree.MaxNodes)
157+
// Store the tree result
158+
r.Tree = &queryv1.TreeReport{Tree: treeBytes}
159+
r.ReportType = queryv1.ReportType_REPORT_TREE
160+
r.Pprof = nil
161+
} else {
162+
symbolizedBytes, err := pprof.Marshal(&prof, true)
163+
if err == nil {
164+
r.Pprof.Pprof = symbolizedBytes
167165
}
168166
}
167+
//}
169168
}
170169
}
171170
}

0 commit comments

Comments
 (0)