# PerfLens

> Remote Linux perf profiling with a real-time web UI. Drop a dependency-free agent on any ARM or x86 device, point it at a PID, and watch flame graphs, function tables, and line-level annotated source update live in the browser.

URL: https://harshith.in/projects/perflens/
Author: Harshith Sunku (Staff Engineer) — https://harshith.in/about/
Source: https://github.com/harshithsunku/perflens
Live: https://harshithsunku.github.io/perflens/
Stack: C, Python, Linux, perf, SSE, zstd

The pipeline in one sentence: `perf record` → agent → TCP+zstd → server → parser →
source mapper → SSE → browser. The agent runs `perf record` and `perf stat` in ~8-second
rounds, flattens each round with `perf script`, compresses it 20–40× with zstd, and
streams it over a 5-byte framed TCP protocol. The server parses samples, maps them back
to source lines with `addr2line`, and pushes function tables, interactive SVG flame
graphs, and heat-colored source to the browser over Server-Sent Events — no polling.

The constraints were the interesting part. Embedded targets don't ship a modern Python,
so the agent is written for Python 3.5 — no f-strings, no dataclasses — and there's a
single static C binary (~1.8 MB, vendored zstd) for targets with no Python at all. The
server is pure stdlib, the UI is vanilla HTML/CSS/JS with hand-rolled flame graphs (no
d3, no bundler). The agent probes `perf_event_paranoid`, enumerates which events the
kernel actually supports, and tries call-graph modes (`fp`, `dwarf`, `lbr`) until one
produces non-empty stacks — because on real devices, half of them don't.

Cross-compilation is first-class: `--toolchain-prefix` derives the right `addr2line`
and `readelf`, `--sysroot` resolves shared libraries and source trees, and the same
agent code runs on aarch64, aarch64_be, armv7l, and x86_64. Sessions are saved as raw
chunks and can be replayed lazily from the UI.
