Files
bpf-developer-tutorial/src/32-wallclock-profiler/oncputime.bpf.c
云微 70451702f0 Add wall clock analysis (#184)
* Add combined on-CPU and off-CPU profiler script

- Implemented a new profiling tool that captures both on-CPU and off-CPU activity for a specified process.
- The script runs 'oncputime' and 'offcputime' tools simultaneously and combines their results into a unified flamegraph.
- Added functionality to discover threads and profile them individually if the application is multi-threaded.
- Included error handling for tool execution and output processing.
- Created methods for generating flamegraph data and SVG visualizations.
- Added command-line argument parsing for user-defined profiling parameters.
- Implemented detailed analysis reports for both individual threads and overall profiling results.

* feat: integrate blazesym v0.2.0 for improved symbol resolution and add test program for memory leak detection

* docs: update README to enhance wall clock profiling tutorial with detailed explanations and examples

* feat: add wallclock-profiler tests to CI workflow for tool validation

* fix: rename combined_profiler.py to wallclock_profiler.py in test scripts and usage examples
2025-09-30 22:11:52 -07:00

129 lines
3.2 KiB
C

// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
/*
* Copyright (c) 2022 LG Electronics
*
* Based on profile from BCC by Brendan Gregg and others.
* 28-Dec-2021 Eunseon Lee Created this.
*/
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_core_read.h>
#include <bpf/bpf_tracing.h>
#include "oncputime.h"
#define EEXIST 17
const volatile bool kernel_stacks_only = false;
const volatile bool user_stacks_only = false;
const volatile bool include_idle = false;
const volatile bool filter_by_pid = false;
const volatile bool filter_by_tid = false;
const volatile bool use_pidns = false;
struct {
__uint(type, BPF_MAP_TYPE_STACK_TRACE);
__type(key, u32);
} stackmap SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, struct key_t);
__type(value, u64);
__uint(max_entries, MAX_ENTRIES);
} counts SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, u32);
__type(value, u8);
__uint(max_entries, MAX_PID_NR);
} pids SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, u32);
__type(value, u8);
__uint(max_entries, MAX_TID_NR);
} tids SEC(".maps");
static __always_inline void *
bpf_map_lookup_or_try_init(void *map, const void *key, const void *init)
{
void *val;
/* bpf helper functions like bpf_map_update_elem() below normally return
* long, but using int instead of long to store the result is a workaround
* to avoid incorrectly evaluating err in cases where the following criteria
* is met:
* the architecture is 64-bit
* the helper function return type is long
* the helper function returns the value of a call to a bpf_map_ops func
* the bpf_map_ops function return type is int
* the compiler inlines the helper function
* the compiler does not sign extend the result of the bpf_map_ops func
*
* if this criteria is met, at best an error can only be checked as zero or
* non-zero. it will not be possible to check for a negative value or a
* specific error value. this is because the sign bit would have been stuck
* at the 32nd bit of a 64-bit long int.
*/
int err;
val = bpf_map_lookup_elem(map, key);
if (val)
return val;
err = bpf_map_update_elem(map, key, init, BPF_NOEXIST);
if (err && err != -EEXIST)
return 0;
return bpf_map_lookup_elem(map, key);
}
SEC("perf_event")
int do_perf_event(struct bpf_perf_event_data *ctx)
{
u64 *valp;
static const u64 zero;
struct key_t key = {};
u64 id;
u32 pid;
u32 tid;
struct bpf_pidns_info ns = {};
id = bpf_get_current_pid_tgid();
pid = id >> 32;
tid = id;
if (!include_idle && tid == 0)
return 0;
if (filter_by_pid && !bpf_map_lookup_elem(&pids, &pid))
return 0;
if (filter_by_tid && !bpf_map_lookup_elem(&tids, &tid))
return 0;
key.pid = pid;
bpf_get_current_comm(&key.name, sizeof(key.name));
if (user_stacks_only)
key.kern_stack_id = -1;
else
key.kern_stack_id = bpf_get_stackid(&ctx->regs, &stackmap, 0);
if (kernel_stacks_only)
key.user_stack_id = -1;
else
key.user_stack_id = bpf_get_stackid(&ctx->regs, &stackmap,
BPF_F_USER_STACK);
valp = bpf_map_lookup_or_try_init(&counts, &key, &zero);
if (valp)
__sync_fetch_and_add(valp, 1);
return 0;
}
char LICENSE[] SEC("license") = "GPL";