From 0c58efd41280bce80cca9804896c76874d383b35 Mon Sep 17 00:00:00 2001 From: umanwizard Date: Tue, 5 Nov 2024 11:16:47 -0500 Subject: [PATCH 1/5] Fix unwinding at syscall on aarch64 (#218) --- support/ebpf/dotnet_tracer.ebpf.c | 2 +- support/ebpf/hotspot_tracer.ebpf.c | 4 ++-- support/ebpf/native_stack_trace.ebpf.c | 12 +++++++++--- support/ebpf/tracemgmt.h | 20 ++++++++++++++++++++ support/ebpf/tracer.ebpf.release.arm64 | Bin 289904 -> 289704 bytes support/ebpf/types.h | 13 ++++++++++++- support/ebpf/v8_tracer.ebpf.c | 2 +- 7 files changed, 45 insertions(+), 8 deletions(-) diff --git a/support/ebpf/dotnet_tracer.ebpf.c b/support/ebpf/dotnet_tracer.ebpf.c index c36dd294..7ebac864 100644 --- a/support/ebpf/dotnet_tracer.ebpf.c +++ b/support/ebpf/dotnet_tracer.ebpf.c @@ -170,7 +170,7 @@ ErrorCode unwind_one_dotnet_frame(PerCPURecord *record, DotnetProcInfo *vi, bool u64 code_start = state->text_section_bias; u64 code_header_ptr = pc; - state->return_address = true; + unwinder_mark_nonleaf_frame(state); if (type < 0x100 && (type & DOTNET_CODE_FLAG_LEAF)) { // Stub frame that does not do calls. diff --git a/support/ebpf/hotspot_tracer.ebpf.c b/support/ebpf/hotspot_tracer.ebpf.c index c63f14d6..9ae1fdc7 100644 --- a/support/ebpf/hotspot_tracer.ebpf.c +++ b/support/ebpf/hotspot_tracer.ebpf.c @@ -719,7 +719,7 @@ ErrorCode hotspot_execute_unwind_action(CodeBlobInfo *cbi, HotspotUnwindAction a return ERR_UNREACHABLE; #if defined(__aarch64__) case UA_UNWIND_AARCH64_LR: - if (state->return_address) { + if (state->lr_invalid) { increment_metric(metricID_UnwindHotspotErrLrUnwindingMidTrace); return ERR_HOTSPOT_LR_UNWINDING_MID_TRACE; } @@ -761,7 +761,7 @@ ErrorCode hotspot_execute_unwind_action(CodeBlobInfo *cbi, HotspotUnwindAction a state->pc = ui->pc; state->sp = ui->sp; state->fp = ui->fp; - state->return_address = true; + unwinder_mark_nonleaf_frame(state); increment_metric(metricID_UnwindHotspotFrames); } } diff --git a/support/ebpf/native_stack_trace.ebpf.c b/support/ebpf/native_stack_trace.ebpf.c index d9c56f3b..0012e30e 100644 --- a/support/ebpf/native_stack_trace.ebpf.c +++ b/support/ebpf/native_stack_trace.ebpf.c @@ -472,7 +472,7 @@ static ErrorCode unwind_one_frame(u64 pid, u32 frame_idx, UnwindState *state, bo return ERR_NATIVE_PC_READ; } state->sp = cfa; - state->return_address = true; + unwinder_mark_nonleaf_frame(state); frame_ok: increment_metric(metricID_UnwindNativeFrames); return ERR_OK; @@ -512,6 +512,7 @@ static ErrorCode unwind_one_frame(u64 pid, u32 frame_idx, struct UnwindState *st state->lr = normalize_pac_ptr(rt_regs[30]); state->r22 = rt_regs[22]; state->return_address = false; + state->lr_invalid = false; DEBUG_PRINT("signal frame"); goto frame_ok; case UNWIND_COMMAND_STOP: @@ -548,7 +549,7 @@ static ErrorCode unwind_one_frame(u64 pid, u32 frame_idx, struct UnwindState *st if (info->fpOpcode == UNWIND_OPCODE_BASE_LR) { // Allow LR unwinding only if it's known to be valid: either because // it's the topmost user-mode frame, or recovered by signal trampoline. - if (state->return_address) { + if (state->lr_invalid) { increment_metric(metricID_UnwindNativeErrLrUnwindingMidTrace); return ERR_NATIVE_LR_UNWINDING_MID_TRACE; } @@ -593,7 +594,7 @@ static ErrorCode unwind_one_frame(u64 pid, u32 frame_idx, struct UnwindState *st } state->sp = cfa; - state->return_address = true; + unwinder_mark_nonleaf_frame(state); frame_ok: increment_metric(metricID_UnwindNativeFrames); return ERR_OK; @@ -642,7 +643,12 @@ static inline ErrorCode copy_state_regs(UnwindState *state, // Treat syscalls as return addresses, but not IRQ handling, page faults, etc.. // https://github.com/torvalds/linux/blob/2ef5971ff3/arch/arm64/include/asm/ptrace.h#L118 // https://github.com/torvalds/linux/blob/2ef5971ff3/arch/arm64/include/asm/ptrace.h#L206-L209 + // + // Note: We do not use `unwinder_mark_nonleaf_frame` here, + // because the frame is a leaf frame from the perspective of the user stack, + // regardless of whether we are in a syscall. state->return_address = interrupted_kernelmode && regs->syscallno != -1; + state->lr_invalid = false; #endif return ERR_OK; diff --git a/support/ebpf/tracemgmt.h b/support/ebpf/tracemgmt.h index d2c58d53..c0e08a45 100644 --- a/support/ebpf/tracemgmt.h +++ b/support/ebpf/tracemgmt.h @@ -200,6 +200,7 @@ static inline PerCPURecord *get_pristine_per_cpu_record() #elif defined(__aarch64__) record->state.lr = 0; record->state.r22 = 0; + record->state.lr_invalid = false; #endif record->state.return_address = false; record->state.error_metric = -1; @@ -242,6 +243,25 @@ void unwinder_mark_done(PerCPURecord *record, int unwinder) { record->unwindersDone |= 1U << unwinder; } +// unwinder_mark_nonleaf_frame marks the current frame as a non-leaf +// frame from the perspective of the user-mode stack. +// That is, frames that are making a syscall (thus the leaf for the user-mode +// stack, though not the leaf for the entire logical stack) *are* +// considered leaf frames in this sense. +// +// On both x86 and aarch64, this means we need to subtract 1 from +// the address during later processing. +// +// Additionally, on aarch64, this means that we will not trust the current value of +// `lr` to be the return address for this frame. +static inline __attribute__((__always_inline__)) +void unwinder_mark_nonleaf_frame(UnwindState *state) { + state->return_address = true; +#if defined(__aarch64__) + state->lr_invalid = true; +#endif +} + // Push the file ID, line number and frame type into FrameList with a user-defined // maximum stack size. // diff --git a/support/ebpf/tracer.ebpf.release.arm64 b/support/ebpf/tracer.ebpf.release.arm64 index dca6175efa4bfbd3b607d3ae65e11b9102373b59..41971640d7664cca53633309bf93414234383b35 100644 GIT binary patch delta 19406 zcmds74Rlr2mA>bm_wvhwB#@9F0`DO|5d;!Y2_TR_g#ao+`H3QsfP@GLNfAhZl28>M zAR0>TPSt8qkyN1#P3uc-9m2FT#i~=FohjN{L+xmkssXVCL7BbxIWPC!6LGrMIJ0Kv zt_An({q4Qax%=;&d-K{)CN}&&u{O(YSbS(mhV2oSwW4X7-AC|f cWrfclHBYtk_fW$#(Hl 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 O>B$m)n6}b0_&)&dQ4Lf8 delta 19458 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 diff --git a/support/ebpf/types.h b/support/ebpf/types.h index f161a284..bbf6882d 100644 --- a/support/ebpf/types.h +++ b/support/ebpf/types.h @@ -571,8 +571,19 @@ typedef struct UnwindState { // Set if the PC is a return address. That is, it points to the next instruction // after a CALL instruction, and requires to be adjusted during symbolization. - // On aarch64, this additionally means that LR register can not be used. + // + // Consider calling unwinder_mark_nonleaf_frame rather than setting this directly. bool return_address; + +#if defined(__aarch64__) + // On aarch64, whether to forbid LR-based unwinding. + // LR unwinding is only allowed for leaf user-mode frames. Frames making a syscall + // are also considered leaf frames for this purpose, because LR is preserved across + // syscalls. + // + // Consider calling unwinder_mark_nonleaf_frame rather than setting this directly. + bool lr_invalid; +#endif } UnwindState; // Container for unwinding state needed by the Perl unwinder. Keeping track of diff --git a/support/ebpf/v8_tracer.ebpf.c b/support/ebpf/v8_tracer.ebpf.c index 9928b51c..d6da2a71 100644 --- a/support/ebpf/v8_tracer.ebpf.c +++ b/support/ebpf/v8_tracer.ebpf.c @@ -271,7 +271,7 @@ ErrorCode unwind_one_v8_frame(PerCPURecord *record, V8ProcInfo *vi, bool top) { state->sp = fp + sizeof(regs); state->fp = regs[0]; state->pc = regs[1]; - state->return_address = true; + unwinder_mark_nonleaf_frame(state); DEBUG_PRINT("v8: pc: %lx, sp: %lx, fp: %lx", (unsigned long) state->pc, (unsigned long) state->sp, From 8ea42ea719dfc765b93f7aa38e79e2a8ef1a9870 Mon Sep 17 00:00:00 2001 From: Bhavna Jindal Date: Wed, 6 Nov 2024 06:03:03 -0500 Subject: [PATCH 2/5] Add PID as an attribute in each sample (#212) --- reporter/otlp_reporter.go | 39 ++++++++++++------ reporter/otlp_reporter_test.go | 73 +++++++++++++++++++++++++++++----- 2 files changed, 90 insertions(+), 22 deletions(-) diff --git a/reporter/otlp_reporter.go b/reporter/otlp_reporter.go index 35d6b056..1cf6201c 100644 --- a/reporter/otlp_reporter.go +++ b/reporter/otlp_reporter.go @@ -70,6 +70,7 @@ type traceAndMetaKey struct { apmServiceName string // containerID is annotated based on PID information containerID string + pid int64 } // traceEvents holds known information about a trace. @@ -84,9 +85,9 @@ type traceEvents struct { } // attrKeyValue is a helper to populate Profile.attribute_table. -type attrKeyValue struct { +type attrKeyValue[T string | int64] struct { key string - value string + value T } // OTLPReporter receives and transforms information to be OTLP/profiles compliant. @@ -224,6 +225,7 @@ func (r *OTLPReporter) ReportTraceEvent(trace *libpf.Trace, meta *TraceEventMeta comm: meta.Comm, apmServiceName: meta.APMServiceName, containerID: containerID, + pid: int64(meta.PID), } if events, exists := (*traceEventsMap)[key]; exists { @@ -566,7 +568,7 @@ func (r *OTLPReporter) getProfile() (profile *profiles.Profile, startTS, endTS u // Walk every frame of the trace. for i := range traceInfo.frameTypes { - frameAttributes := addProfileAttributes(profile, []attrKeyValue{ + frameAttributes := addProfileAttributes(profile, []attrKeyValue[string]{ {key: "profile.frame.type", value: traceInfo.frameTypes[i].String()}, }, attributeMap) @@ -599,7 +601,7 @@ func (r *OTLPReporter) getProfile() (profile *profiles.Profile, startTS, endTS u fileName = execInfo.fileName } - mappingAttributes := addProfileAttributes(profile, []attrKeyValue{ + mappingAttributes := addProfileAttributes(profile, []attrKeyValue[string]{ // Once SemConv and its Go package is released with the new // semantic convention for build_id, replace these hard coded // strings. @@ -664,11 +666,13 @@ func (r *OTLPReporter) getProfile() (profile *profiles.Profile, startTS, endTS u profile.Location = append(profile.Location, loc) } - sample.Attributes = addProfileAttributes(profile, []attrKeyValue{ + sample.Attributes = append(addProfileAttributes(profile, []attrKeyValue[string]{ {key: string(semconv.ContainerIDKey), value: traceKey.containerID}, {key: string(semconv.ThreadNameKey), value: traceKey.comm}, {key: string(semconv.ServiceNameKey), value: traceKey.apmServiceName}, - }, attributeMap) + }, attributeMap), addProfileAttributes(profile, []attrKeyValue[int64]{ + {key: string(semconv.ProcessPIDKey), value: traceKey.pid}, + }, attributeMap)...) sample.LocationsLength = uint64(len(traceInfo.frameTypes)) locationIndex += sample.LocationsLength @@ -739,15 +743,26 @@ func createFunctionEntry(funcMap map[funcInfo]uint64, // addProfileAttributes adds attributes to Profile.attribute_table and returns // the indices to these attributes. -func addProfileAttributes(profile *profiles.Profile, - attributes []attrKeyValue, attributeMap map[string]uint64) []uint64 { +func addProfileAttributes[T string | int64](profile *profiles.Profile, + attributes []attrKeyValue[T], attributeMap map[string]uint64) []uint64 { indices := make([]uint64, 0, len(attributes)) - addAttr := func(attr attrKeyValue) { - if attr.value == "" { + addAttr := func(attr attrKeyValue[T]) { + var attributeCompositeKey string + var attributeValue common.AnyValue + + switch val := any(attr.value).(type) { + case string: + attributeCompositeKey = attr.key + "_" + val + attributeValue = common.AnyValue{Value: &common.AnyValue_StringValue{StringValue: val}} + case int64: + attributeCompositeKey = attr.key + "_" + strconv.Itoa(int(val)) + attributeValue = common.AnyValue{Value: &common.AnyValue_IntValue{IntValue: val}} + default: + log.Error("Unsupported attribute value type. Only string and int64 are supported.") return } - attributeCompositeKey := attr.key + "_" + attr.value + if attributeIndex, exists := attributeMap[attributeCompositeKey]; exists { indices = append(indices, attributeIndex) return @@ -756,7 +771,7 @@ func addProfileAttributes(profile *profiles.Profile, indices = append(indices, newIndex) profile.AttributeTable = append(profile.AttributeTable, &common.KeyValue{ Key: attr.key, - Value: &common.AnyValue{Value: &common.AnyValue_StringValue{StringValue: attr.value}}, + Value: &attributeValue, }) attributeMap[attributeCompositeKey] = newIndex } diff --git a/reporter/otlp_reporter_test.go b/reporter/otlp_reporter_test.go index d9c2844f..bdfc22ed 100644 --- a/reporter/otlp_reporter_test.go +++ b/reporter/otlp_reporter_test.go @@ -26,11 +26,37 @@ func TestGetSampleAttributes(t *testing.T) { comm: "", apmServiceName: "", containerID: "", + pid: 0, + }, + }, + attributeMap: make(map[string]uint64), + expectedIndices: [][]uint64{{0, 1, 2, 3}}, + expectedAttributeTable: []*common.KeyValue{ + { + Key: "container.id", + Value: &common.AnyValue{ + Value: &common.AnyValue_StringValue{StringValue: ""}, + }, + }, + { + Key: "thread.name", + Value: &common.AnyValue{ + Value: &common.AnyValue_StringValue{StringValue: ""}, + }, + }, + { + Key: "service.name", + Value: &common.AnyValue{ + Value: &common.AnyValue_StringValue{StringValue: ""}, + }, + }, + { + Key: "process.pid", + Value: &common.AnyValue{ + Value: &common.AnyValue_IntValue{IntValue: 0}, + }, }, }, - attributeMap: make(map[string]uint64), - expectedIndices: [][]uint64{make([]uint64, 0, 4)}, - expectedAttributeTable: nil, }, "duplicate": { profile: &profiles.Profile{}, @@ -40,16 +66,18 @@ func TestGetSampleAttributes(t *testing.T) { comm: "comm1", apmServiceName: "apmServiceName1", containerID: "containerID1", + pid: 1234, }, { hash: libpf.TraceHash{}, comm: "comm1", apmServiceName: "apmServiceName1", containerID: "containerID1", + pid: 1234, }, }, attributeMap: make(map[string]uint64), - expectedIndices: [][]uint64{{0, 1, 2}, {0, 1, 2}}, + expectedIndices: [][]uint64{{0, 1, 2, 3}, {0, 1, 2, 3}}, expectedAttributeTable: []*common.KeyValue{ { Key: "container.id", @@ -69,6 +97,12 @@ func TestGetSampleAttributes(t *testing.T) { Value: &common.AnyValue_StringValue{StringValue: "apmServiceName1"}, }, }, + { + Key: "process.pid", + Value: &common.AnyValue{ + Value: &common.AnyValue_IntValue{IntValue: 1234}, + }, + }, }, }, "different": { @@ -79,16 +113,18 @@ func TestGetSampleAttributes(t *testing.T) { comm: "comm1", apmServiceName: "apmServiceName1", containerID: "containerID1", + pid: 1234, }, { hash: libpf.TraceHash{}, comm: "comm2", apmServiceName: "apmServiceName2", containerID: "containerID2", + pid: 6789, }, }, attributeMap: make(map[string]uint64), - expectedIndices: [][]uint64{{0, 1, 2}, {3, 4, 5}}, + expectedIndices: [][]uint64{{0, 1, 2, 3}, {4, 5, 6, 7}}, expectedAttributeTable: []*common.KeyValue{ { Key: "container.id", @@ -108,6 +144,12 @@ func TestGetSampleAttributes(t *testing.T) { Value: &common.AnyValue_StringValue{StringValue: "apmServiceName1"}, }, }, + { + Key: "process.pid", + Value: &common.AnyValue{ + Value: &common.AnyValue_IntValue{IntValue: 1234}, + }, + }, { Key: "container.id", Value: &common.AnyValue{ @@ -126,6 +168,12 @@ func TestGetSampleAttributes(t *testing.T) { Value: &common.AnyValue_StringValue{StringValue: "apmServiceName2"}, }, }, + { + Key: "process.pid", + Value: &common.AnyValue{ + Value: &common.AnyValue_IntValue{IntValue: 6789}, + }, + }, }, }, } @@ -136,11 +184,16 @@ func TestGetSampleAttributes(t *testing.T) { t.Run(name, func(t *testing.T) { indices := make([][]uint64, 0) for _, k := range tc.k { - indices = append(indices, addProfileAttributes(tc.profile, []attrKeyValue{ - {key: string(semconv.ContainerIDKey), value: k.containerID}, - {key: string(semconv.ThreadNameKey), value: k.comm}, - {key: string(semconv.ServiceNameKey), value: k.apmServiceName}, - }, tc.attributeMap)) + indices = append(indices, append(addProfileAttributes(tc.profile, + []attrKeyValue[string]{ + {key: string(semconv.ContainerIDKey), value: k.containerID}, + {key: string(semconv.ThreadNameKey), value: k.comm}, + {key: string(semconv.ServiceNameKey), value: k.apmServiceName}, + }, tc.attributeMap), + addProfileAttributes(tc.profile, + []attrKeyValue[int64]{ + {key: string(semconv.ProcessPIDKey), value: k.pid}, + }, tc.attributeMap)...)) } require.Equal(t, tc.expectedIndices, indices) require.Equal(t, tc.expectedAttributeTable, tc.profile.AttributeTable) From 47e8410f9a1516a03c79a1f390c0c0bdd316921b Mon Sep 17 00:00:00 2001 From: Florian Lehner Date: Tue, 12 Nov 2024 13:57:27 +0100 Subject: [PATCH 3/5] ebpf: increase number of stack delta buckets (#231) Signed-off-by: Florian Lehner --- processmanager/ebpf/ebpf.go | 2 ++ processmanager/ebpf/ebpf_test.go | 11 +++++------ support/ebpf/extmaps.h | 2 ++ support/ebpf/native_stack_trace.ebpf.c | 4 ++++ support/ebpf/tracer.ebpf.release.amd64 | Bin 297824 -> 299160 bytes support/ebpf/tracer.ebpf.release.arm64 | Bin 289704 -> 291032 bytes support/ebpf/types.h | 4 ++-- tools/coredump/ebpfhelpers.go | 3 ++- 8 files changed, 17 insertions(+), 9 deletions(-) diff --git a/processmanager/ebpf/ebpf.go b/processmanager/ebpf/ebpf.go index 9f9dc90b..bb07da91 100644 --- a/processmanager/ebpf/ebpf.go +++ b/processmanager/ebpf/ebpf.go @@ -135,6 +135,8 @@ var outerMapsName = [...]string{ "exe_id_to_19_stack_deltas", "exe_id_to_20_stack_deltas", "exe_id_to_21_stack_deltas", + "exe_id_to_22_stack_deltas", + "exe_id_to_23_stack_deltas", } // Compile time check to make sure ebpfMapsImpl satisfies the interface . diff --git a/processmanager/ebpf/ebpf_test.go b/processmanager/ebpf/ebpf_test.go index d80a78fd..fec5bf5d 100644 --- a/processmanager/ebpf/ebpf_test.go +++ b/processmanager/ebpf/ebpf_test.go @@ -1,6 +1,3 @@ -//go:build !integration -// +build !integration - // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 @@ -12,6 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.opentelemetry.io/ebpf-profiler/support" ) func TestMapID(t *testing.T) { @@ -26,6 +24,7 @@ func TestMapID(t *testing.T) { 0x3FF: 10, // 1023 0x400: 11, // 1024 0xFFFFF: 20, // 1048575 (2^20 - 1) + (1 << support.StackDeltaBucketLargest) - 1: support.StackDeltaBucketLargest, } for numStackDeltas, expectedShift := range testCases { numStackDeltas := numStackDeltas @@ -33,11 +32,11 @@ func TestMapID(t *testing.T) { t.Run(fmt.Sprintf("deltas %d", numStackDeltas), func(t *testing.T) { shift, err := getMapID(numStackDeltas) require.NoError(t, err) - assert.Equal(t, expectedShift, shift, - fmt.Sprintf("wrong map name for %d deltas", numStackDeltas)) + assert.Equal(t, expectedShift, shift, "wrong map name for %d deltas", + numStackDeltas) }) } - _, err := getMapID(1 << 22) + _, err := getMapID(1 << (support.StackDeltaBucketLargest + 1)) require.Error(t, err) } diff --git a/support/ebpf/extmaps.h b/support/ebpf/extmaps.h index 76a83f57..5922d9ed 100644 --- a/support/ebpf/extmaps.h +++ b/support/ebpf/extmaps.h @@ -38,6 +38,8 @@ extern bpf_map_def exe_id_to_18_stack_deltas; extern bpf_map_def exe_id_to_19_stack_deltas; extern bpf_map_def exe_id_to_20_stack_deltas; extern bpf_map_def exe_id_to_21_stack_deltas; +extern bpf_map_def exe_id_to_22_stack_deltas; +extern bpf_map_def exe_id_to_23_stack_deltas; extern bpf_map_def hotspot_procs; extern bpf_map_def kernel_stackmap; extern bpf_map_def dotnet_procs; diff --git a/support/ebpf/native_stack_trace.ebpf.c b/support/ebpf/native_stack_trace.ebpf.c index 0012e30e..959099cb 100644 --- a/support/ebpf/native_stack_trace.ebpf.c +++ b/support/ebpf/native_stack_trace.ebpf.c @@ -37,6 +37,8 @@ STACK_DELTA_BUCKET(18); STACK_DELTA_BUCKET(19); STACK_DELTA_BUCKET(20); STACK_DELTA_BUCKET(21); +STACK_DELTA_BUCKET(22); +STACK_DELTA_BUCKET(23); // Unwind info value for invalid stack delta #define STACK_DELTA_INVALID (STACK_DELTA_COMMAND_FLAG | UNWIND_COMMAND_INVALID) @@ -154,6 +156,8 @@ void *get_stack_delta_map(int mapID) { case 19: return &exe_id_to_19_stack_deltas; case 20: return &exe_id_to_20_stack_deltas; case 21: return &exe_id_to_21_stack_deltas; + case 22: return &exe_id_to_22_stack_deltas; + case 23: return &exe_id_to_23_stack_deltas; default: return NULL; } } diff --git a/support/ebpf/tracer.ebpf.release.amd64 b/support/ebpf/tracer.ebpf.release.amd64 index 9ff3eabbddde8008f5a5035270ed32adf489caac..2a8cbb2fd2bc85674a9b2d3c2c6223fb9f4f06b1 100644 GIT binary patch delta 48904 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 H=WG8D(zgaC delta 48028 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 JuE~}A{{iTtH!}bL diff --git a/support/ebpf/tracer.ebpf.release.arm64 b/support/ebpf/tracer.ebpf.release.arm64 index 41971640d7664cca53633309bf93414234383b35..ecac9895a53d1f5bcafec570197a20e0625dade4 100644 GIT binary patch delta 47156 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 delta 46079 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 Date: Wed, 13 Nov 2024 07:51:42 +0100 Subject: [PATCH 4/5] reporter: use htlhash attribute for profiling specific hash (#236) Signed-off-by: Florian Lehner --- README.md | 4 ++-- reporter/otlp_reporter.go | 37 ++++++++++++++++++------------------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 5f3c1bd1..3922aa8a 100644 --- a/README.md +++ b/README.md @@ -91,9 +91,9 @@ devfiler spins up a local server that listens on `0.0.0.0:11000`. To run it, simply download and unpack the archive from the following URL: -https://upload.elastic.co/d/87e7697991940ec37f0c6e39ac38d213f65e8dc1ef9dbedff6aab9cba0adfaba +https://upload.elastic.co/d/f8aa0c386baa808a616ca29f86b34c726edb5af36f8840a4cf28468ad534a4b5 -Authentication token: `c74dfc4db2212015` +Authentication token: `2635c0750bf8ea69` The archive contains a build for each of the following platforms: diff --git a/reporter/otlp_reporter.go b/reporter/otlp_reporter.go index 1cf6201c..0a5163b6 100644 --- a/reporter/otlp_reporter.go +++ b/reporter/otlp_reporter.go @@ -606,7 +606,7 @@ func (r *OTLPReporter) getProfile() (profile *profiles.Profile, startTS, endTS u // semantic convention for build_id, replace these hard coded // strings. {key: "process.executable.build_id.gnu", value: execInfo.gnuBuildID}, - {key: "process.executable.build_id.profiling", + {key: "process.executable.build_id.htlhash", value: traceInfo.files[i].StringNoQuotes()}, }, attributeMap) @@ -660,8 +660,8 @@ func (r *OTLPReporter) getProfile() (profile *profiles.Profile, startTS, endTS u loc.Line = append(loc.Line, line) // To be compliant with the protocol, generate a dummy mapping entry. - loc.MappingIndex = getDummyMappingIndex(fileIDtoMapping, stringMap, - profile, traceInfo.files[i]) + loc.MappingIndex = getDummyMappingIndex(fileIDtoMapping, + stringMap, attributeMap, profile, traceInfo.files[i]) } profile.Location = append(profile.Location, loc) } @@ -785,24 +785,23 @@ func addProfileAttributes[T string | int64](profile *profiles.Profile, // getDummyMappingIndex inserts or looks up an entry for interpreted FileIDs. func getDummyMappingIndex(fileIDtoMapping map[libpf.FileID]uint64, - stringMap map[string]uint32, profile *profiles.Profile, - fileID libpf.FileID) uint64 { - var locationMappingIndex uint64 + stringMap map[string]uint32, attributeMap map[string]uint64, + profile *profiles.Profile, fileID libpf.FileID) uint64 { if tmpMappingIndex, exists := fileIDtoMapping[fileID]; exists { - locationMappingIndex = tmpMappingIndex - } else { - idx := uint64(len(fileIDtoMapping)) - fileIDtoMapping[fileID] = idx - locationMappingIndex = idx - - profile.Mapping = append(profile.Mapping, &profiles.Mapping{ - Filename: int64(getStringMapIndex(stringMap, "")), - BuildId: int64(getStringMapIndex(stringMap, - fileID.StringNoQuotes())), - BuildIdKind: *profiles.BuildIdKind_BUILD_ID_BINARY_HASH.Enum(), - }) + return tmpMappingIndex } - return locationMappingIndex + idx := uint64(len(fileIDtoMapping)) + fileIDtoMapping[fileID] = idx + + mappingAttributes := addProfileAttributes(profile, []attrKeyValue[string]{ + {key: "process.executable.build_id.htlhash", + value: fileID.StringNoQuotes()}}, attributeMap) + + profile.Mapping = append(profile.Mapping, &profiles.Mapping{ + Filename: int64(getStringMapIndex(stringMap, "")), + Attributes: mappingAttributes, + }) + return idx } // waitGrpcEndpoint waits until the gRPC connection is established. From 235350590a3824f01f1bed596ce78bcb8ea1a5dd Mon Sep 17 00:00:00 2001 From: Florian Lehner Date: Wed, 13 Nov 2024 16:15:22 +0100 Subject: [PATCH 5/5] reporter: drop fifo (#239) Signed-off-by: Florian Lehner --- reporter/fifo.go | 122 ------------------------------------------ reporter/fifo_test.go | 118 ---------------------------------------- 2 files changed, 240 deletions(-) delete mode 100644 reporter/fifo.go delete mode 100644 reporter/fifo_test.go diff --git a/reporter/fifo.go b/reporter/fifo.go deleted file mode 100644 index e6c871b7..00000000 --- a/reporter/fifo.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package reporter // import "go.opentelemetry.io/ebpf-profiler/reporter" - -import ( - "fmt" - "sync" - - log "github.com/sirupsen/logrus" -) - -// FifoRingBuffer implements a first-in-first-out ring buffer that is safe for concurrent access. -type FifoRingBuffer[T any] struct { //nolint:gocritic - sync.Mutex - - // data holds the actual data. - data []T - - // emptyT is variable of type T used for nullifying entries in data[]. - emptyT T - - // name holds a string to uniquely identify the ring buffer in log messages. - name string - - // size is the maximum number of entries in the ring buffer. - size uint32 - - // readPos holds the position of the first element to be read in the data array. - readPos uint32 - - // writePos holds the position where the next element should be - // placed in the data array. - writePos uint32 - - // count holds a count of how many entries are in the array. - count uint32 - - // overwriteCount holds a count of the number of overwritten entries since the last metric - // report interval. - overwriteCount uint32 -} - -func (q *FifoRingBuffer[T]) InitFifo(size uint32, name string) error { - if size == 0 { - return fmt.Errorf("unsupported size of fifo: %d", size) - } - q.Lock() - defer q.Unlock() - q.size = size - q.data = make([]T, size) - q.readPos = 0 - q.writePos = 0 - q.count = 0 - q.overwriteCount = 0 - q.name = name - return nil -} - -// zeroFifo re-initializes the ring buffer and clears the data array, making previously -// stored elements available for GC. -func (q *FifoRingBuffer[T]) zeroFifo() { - if err := q.InitFifo(q.size, q.name); err != nil { - // Should never happen - panic(err) - } -} - -// Append adds element v to the FifoRingBuffer. it overwrites existing elements if there is no -// space left. -func (q *FifoRingBuffer[T]) Append(v T) { - q.Lock() - defer q.Unlock() - - q.data[q.writePos] = v - q.writePos++ - - if q.writePos == q.size { - q.writePos = 0 - } - - if q.count < q.size { - q.count++ - if q.count == q.size { - log.Warnf("About to start overwriting elements in buffer for %s", - q.name) - } - } else { - q.overwriteCount++ - q.readPos = q.writePos - } -} - -// ReadAll returns all elements from the FifoRingBuffer. -func (q *FifoRingBuffer[T]) ReadAll() []T { - q.Lock() - defer q.Unlock() - - data := make([]T, q.count) - readPos := q.readPos - - for i := uint32(0); i < q.count; i++ { - pos := (i + readPos) % q.size - data[i] = q.data[pos] - // Allow for element to be GCed - q.data[pos] = q.emptyT - } - - q.readPos = q.writePos - q.count = 0 - - return data -} - -func (q *FifoRingBuffer[T]) GetOverwriteCount() uint32 { - q.Lock() - defer q.Unlock() - - count := q.overwriteCount - q.overwriteCount = 0 - return count -} diff --git a/reporter/fifo_test.go b/reporter/fifo_test.go deleted file mode 100644 index 7a4c7a80..00000000 --- a/reporter/fifo_test.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package reporter - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestFifo(t *testing.T) { - var integers []int - integers = append(integers, 1, 2, 3, 4, 5) - - var integersShared []int - integersShared = append(integersShared, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) - - var retIntegers []int - retIntegers = append(retIntegers, 3, 4, 5) - - var retIntegersShared []int - retIntegersShared = append(retIntegersShared, 8, 9, 10, 11, 12) - - sharedFifo := &FifoRingBuffer[int]{} - err := sharedFifo.InitFifo(5, t.Name()) - require.NoError(t, err) - - //nolint:lll - tests := map[string]struct { - // size defines the size of the fifo. - size uint32 - // data will be written to and extracted from the fifo. - data []int - // returned reflects the data that is expected from the fifo - // after writing to it. - returned []int - // the number of overwrites that occurred - overwriteCount uint32 - // err indicates if an error is expected for this testcase. - err bool - // sharedFifo indicates if a shared fifo should be used. - // If false, a new fifo is used, specific to the testcase. - sharedFifo bool - // parallel indicates if parallelism should be enabled for this testcase. - parallel bool - }{ - // This testcase simulates a fifo with an invalid size of 0. - "Invalid size": {size: 0, err: true, parallel: true}, - // This testcase simulates a case where the numbers of elements - // written to the fifo represents the size of the fifo. - "Full Fifo": {size: 5, data: integers, returned: integers, overwriteCount: 0, parallel: true}, - // This testcase simulates a case where the number of elements - // written to the fifo exceed the size of the fifo. - "Fifo overflow": {size: 3, data: integers, returned: retIntegers, overwriteCount: 2, parallel: true}, - // This testcase simulates a case where only a few elements are - // written to the fifo and don't exceed the size of the fifo. - "Partial full": {size: 15, data: integers, returned: integers, overwriteCount: 0, parallel: true}, - - // The following test cases share the same fifo - - // This testcase simulates a case where the numbers of elements - // written to the fifo represents the size of the fifo. - "Shared Full Fifo": {data: integers, returned: integers, overwriteCount: 0, sharedFifo: true}, - // This testcase simulates a case where the number of elements - // written to the fifo exceed the size of the fifo. - "Shared Fifo overflow": {data: integersShared, returned: retIntegersShared, overwriteCount: 7, sharedFifo: true}, - } - - for name, testcase := range tests { - name := name - testcase := testcase - var fifo *FifoRingBuffer[int] - - t.Run(name, func(t *testing.T) { - if testcase.parallel { - t.Parallel() - } - - if testcase.sharedFifo { - fifo = sharedFifo - } else { - fifo = &FifoRingBuffer[int]{} - err := fifo.InitFifo(testcase.size, t.Name()) - if testcase.err { - require.Error(t, err) - return - } - require.NoError(t, err) - } - - empty := fifo.ReadAll() - require.Empty(t, empty) - - for _, v := range testcase.data { - fifo.Append(v) - } - - data := fifo.ReadAll() - for i := uint32(0); i < fifo.size; i++ { - assert.Equalf(t, 0, fifo.data[i], "fifo not empty after ReadAll(), idx: %d", i) - } - assert.Equal(t, testcase.returned, data) - assert.Equal(t, testcase.overwriteCount, fifo.GetOverwriteCount(), "overwrite count") - assert.Zero(t, fifo.GetOverwriteCount(), "overwrite count not reset") - }) - } -} - -func TestFifo_isWritableWhenZeroed(t *testing.T) { - fifo := &FifoRingBuffer[int]{} - require.NoError(t, fifo.InitFifo(1, t.Name())) - fifo.zeroFifo() - assert.NotPanics(t, func() { - fifo.Append(123) - }) -}