2394283_en-US

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

2394283_en-US

2394283_en-US

Monitor the CPU loading using ebpf to reduce system call overhead
A lightweight CPU utilization monitor built with eBPF + libbpf.  
It hooks into the kernel scheduler (sched_switch tracepoint) to measure per-CPU
active time with nanosecond precision — more accurate than polling-based tools like
top, and with lower overhead at high process counts.

How it works

 
Kernel (eBPF)                          User space (C + libbpf)
-----------------------                -------------------------
sched_switch tracepoint                poll BPF maps every 1 s
  -> record on-CPU time per core   ->  compute active % and idle %
  -> accumulate in BPF Array map       print per-core + average
 

The sched_switch tracepoint context structure is defined manually in
cpu_monitor_bpf.c.

Output


The monitor displays per-core active/idle percentages, with the idle column
matching top's id field for easy comparison:
 
CPU Core   | Active %   | Idle % (=top id)
-------------------------------------------
CPU 0      |     0.34%  |         99.66%
CPU 1      |    21.89%  |         78.11%
CPU 2      |     0.15%  |         99.85%
CPU 3      |     0.03%  |         99.97%
-------------------------------------------
TOTAL AVG  |     5.60%  |         94.40%
 
To compare with top, press 1 in top to show per-core stats, then compare
the id column with the Idle % column above.

Prerequisites

Host (build machine)

Package Purpose
clang + llvm version 21 Compile BPF C source to BPF ELF
bpftool Generate BFP skeleton headers
aarch64 Poky Toolchain Corss-compile the user-space binary
 

Install on Ubuntu/Debian:
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
./llvm.sh 21
apt update
apt install -y llvm-21 clang-21 lld-21 lldb-21
update-alternatives --install /usr/bin/llvm-link llvm-link /usr/bin/llvm-link-21 100
update-alternatives --install /usr/bin/clang clang /usr/bin/clang-21 100
update-alternatives --install /usr/bin/llc llc /usr/bin/llc-21 100
llvm-link --version
clang --version

# install bpftool
apt install linux-tools-$(uname -r)

Target board

  • Tested Linux kernel == 6.18.20-2.0.0
  • Tested image == imx-image-full
  • Most BPF configurations are enabled by default. In addition, you need CONFIG_FTRACE=y to enable tracepoint support (required for the sched_switch hook).

Build

Build the project on your host machine:
TOOLCHAIN_PATH=/opt/fsl-imx-internal-wayland/6.18-whinlatter/environment-setup-armv8a-poky-linux ./build_and_deploy.sh
 

The script will:
  1. Source the Poky toolchain environment
  2. Run make clean && make all (compiles BPF object, generates skeleton,
  3. cross-compiles user-space binary)
  4. Install the binary to ./board_deploy/cpu_monitor

Deploy and run

 
# Copy binary to the board
scp board_deploy/cpu_monitor root@<board-ip>:/usr/bin/

# Run on the board (root required for eBPF)
ssh root@<board-ip>

./cpu_monitor
 
Press Ctrl+C to exit.
 

Benchmarking: eBPF vs top


A scheduler stress test script is included to compare monitoring overhead
between cpu_monitor and top under high scheduling pressure.

Run the stress test


On the target board, open three terminals:

 
# Terminal 1: start scheduler pressure (200 threads, 30 seconds)
./stress_sched.sh -t 200 -d 30

# Terminal 2: measure eBPF monitoring overhead
perf stat -e cpu-clock,task-clock,context-switches,cpu-migrations,instructions timeout -s KILL 10 ./cpu_monitor

# Terminal 3: measure top monitoring overhead
perf stat -e cpu-clock,task-clock,context-switches,cpu-migrations,instructions top -b -d 1 -n 10

Compare task-clock, instructions, and context-switches from perf stat
output. Try different thread counts to observe scaling behavior:
 
./stress_sched.sh -t 50 -d 30     # low pressure
./stress_sched.sh -t 200 -d 30    # medium pressure
./stress_sched.sh -t 500 -d 30    # high pressure

Result

Test environment: i.MX943 (4x Cortex-A55), Linux 6.18.20, 10-second measurement window.

Comparison results in free system load:
Indicator eBPF cpu_monitor top delta
task-clock (CPU timing) 12.0 ms 263.9 ms 22x
CPU usage 0.1% 2.8% 28x
instructions 3.38M 197M 58x
context-switches 12 17  
sys time (kernel time) 5.0ms 199.5ms 40x
user time 0 62.1ms  
 

Comparison results in high scheduling pressure (200 threads):
Indicator eBPF cpu_monitor top delta
task-clock (CPU timing) 12.6ms 690ms 54x
CPU usage 0.1% 6.1% 61x
instructions 4.8M 538M 112x
context-switches 122 9019 75x
sys time (kernel time) 4ms 461ms 115x
user time 0 206ms  
 

Project structure

ebpf_cpu_usage/
├── cpu_monitor_bpf.c      # Kernel-side eBPF program (C, compiled to BPF)
├── cpu_monitor.c          # User-space program (C, cross-compiled to aarch64)
├── Makefile               # Build rules
├── build_and_deploy.sh    # One-shot build + package script
├── stress_sched.sh        # Scheduler stress test for benchmarking
└── README.md
 
A lightweight CPU utilization monitor built with eBPF + libbpf.  
It hooks into the kernel scheduler (sched_switch tracepoint) to measure per-CPU
active time with nanosecond precision — more accurate than polling-based tools like
top, and with lower overhead at high process counts.
i.MX Processors
Tags (1)
No ratings
Version history
Last update:
yesterday
Updated by: