# ProfInfer: An eBPF-based Fine-Grained LLM Inference Profiler > [!info] Talk metadata > - **会議:** [[MLSys2026]] Day 4 (May 21 / Thu)、Grand Ballroom 1、Industry Track Oral: Benchmarks and Evaluation(16:30 - 18:00 PDT、第5発表、司会 Youjie Li) > - **登壇者:** Bohua Zou(Huawei Hilbert Research Center (Dresden) / Technical University of Munich。スライド表紙で発表者としてハイライト)。共著者: Debayan Roy(Huawei Hilbert Research Center, Dresden、Correspondence)、Dhimankumar Yogesh Airao(同)、Weihao Xu(TU Munich)、Binqi Sun(TU Munich)、Yutao Liu(Huawei Hilbert Research Center, Dresden)、Haibo Chen(Huawei Central Software Institute / Shanghai Jiao Tong University) > - **URL:** https://mlsys.org/virtual/2026/session/3717 > - **関連研究:** ソースコード公開 https://gitcode.com/openharmony-robot/oh-llama.cpp/tree/main/profinfer > [!warning] 文字起こしは存在しないため Q&A は扱わない。数値・固有名詞・式の権威はスライド PDF(数値が論文と食い違う場合はスライド優先)であり、本ノートはスライドと論文 PDF に明記された内容のみを記す。 > [!abstract] 概要(論文 PDF アブストラクト) > 大規模言語モデル(LLM)が研究から本番運用へ移行するなか、推論エンジンがリアルタイムにどう振る舞うかを理解することは、本質的でありながら捉えにくいものになっている。ONNX Runtime のような汎用エンジンと異なり、今日の LLM 推論システムは演算子レベルの可視性をほとんど提供せず、開発者は時間とリソースがどこに費やされるかを把握できないままである。「このワークロードはメモリバウンドか、それとも計算バウンドか」という基本的な問いすら、しばしば未解答のまま残される。このギャップを埋めるため、我々は現代の LLM 推論エンジン向けに、きめ細かく非侵襲的なプロファイリングフレームワークを開発する。とくにリソース制約のあるエッジデバイスに焦点を当て、llama.cpp を題材としつつ、類似のランタイムアーキテクチャにも適用可能とする。拡張 Berkeley Packet Filter(eBPF)技術の上に構築された我々のシステムは、ソースを改変・再コンパイルすることなく、複数のレイヤーにまたがってランタイム関数へプローブを動的にアタッチする。収集したトレースを演算子・グラフ・タイムライン・ハードウェアカウンタ傾向の豊かな可視化へと変換し、密推論・Mixture-of-Experts ルーティング・演算子オフロードが実際にどう振る舞うかを露わにする。5% 未満のランタイムオーバーヘッドと高いプロファイリング忠実度により、本フレームワークは LLM 推論を透明かつ診断可能にし、性能プロファイリングを最適化・スケジューリング・リソースアウェアな展開のための実用的ツールへと変える。 ## 背景と問題設定 - LLM 推論はクラウドからモバイル・エッジデバイスへ移行中。on-device 化の動機はプライバシー・コスト・安定性・エネルギー消費(スライド "LLM inference: From cloud to mobile and edge devices")。 - on-device 推論エンジン(IE = LLM runtime + ML framework)は、Prefill / Decode フェーズを持ち TTFT(Time to the first token)と TPOT(Time per output token)で評価される。しかしメトリクスと可観測性が限定的(スライド "On-device LLM inference: limited metrics and observability")。 - 既存プロファイリングツールの限界(スライド "Existing profiling tools"): - **Netron:** *Static*(静的)なモデル構造解析のみ。 - **llama-bench:** *Coarse-grained*(粗粒度)メトリクス(TTFT, TPOT)のみ。 - **ONNX Runtime profiler:** 事前定義された *intrusive*(侵襲的)トレーシング。 - ProfInfer はこれらに対し **Dynamic(動的)・Fine-grained(細粒度)・Non-intrusive(非侵襲)** を狙う。 - 設計の 3 つの柱(論文 §1): ① fine-grained observability(forward pass・演算子呼び出しごと、テンソル次元・演算子種別・動的構築される DAG を捕捉)、② non-intrusive instrumentation(eBPF プローブでソース改変不要)、③ hardware-counter integration(PMC データ: キャッシュミス・メモリアクセス・スレッド実行などをタイムライン/DAG/演算子別プロットで提示)。 ## eBPF の背景 スライド "Background: extended Berkeley Package Filter (eBPF)"。 - **Flexibility:** 非侵襲・プログラマブル、カーネル改変やカーネルモジュールロード不要。 - **Safety:** OS カーネル内でサンドボックス実行されるプログラム。 - 利用するフック: **uprobe / uretprobe**(ユーザ空間関数の入口/出口)、**tracepoint**(カーネルイベント)。eBPF kernel program は Clang でコンパイルし libbpf 経由で load、bpf syscall → verifier → JIT compiler → eBPF handlers(eBPF maps 経由でデータ交換)。 - 実装フレームワークは2つ: Ubuntu 上では **BCC**(Python バインディングで rapid prototyping 向き)、OpenHarmony は標準で Python 非対応のため C ライブラリ **libbpf** を使用(論文 §2.3)。 ## ProfInfer の全体設計 スライド "Overview design of ProfInfer"・図1。 - 2 コンポーネント構成: **Tracer**(Online、eBPF user + eBPF kernel)と **Analyzer**(Offline、ProfDAG / ProfTime / ProfStat)。 - スタック: IE (llama.cpp) + GGML が OS(Ubuntu / OpenHarmony)上で動作し、Backends(CPU/GPU/NPU)へ。Tracer はランタイムライブラリへプローブをアタッチして双方向にデータ交換。 - llama.cpp 推論エンジンの上に実装。実装は公開済み(gitcode の oh-llama.cpp/profinfer)。 ## 軽量 eBPF トレーシング(Online) スライド "Lightweight eBPF-based tracing (online)"・論文 §3・図2・Table 2。 - ユーザ空間アプリがコンパイルフラグ(PMC types / operator type / buffer type)を設定し、プローブ(uprobe, uretprobe, tracepoint)をアタッチ。kernel 側 handler が submit したバッファをポーリングし、非同期に処理。QoS 違反(例: 5 tokens/s)検出時に一部プローブを切って速度回復。 - **Multi-granularity tracing(Table 2 のプローブ)**: - **Token-level:** `llama_decode`(u(ret)probe、batch size を取得)。uprobe/uretprobe のタイムスタンプ差から Prefill 時の TTFT、Decode 時の TPOT を得る。 - **Graph-level:** `ggml_backend_graph_compute_async`(u(ret)probe、backend type を取得)。複数バックエンド利用時に複数の計算グラフが構築され、`guid`(16 桁の backend 識別子)を引数から抽出。 - **Operator-level(OP):** `ggml_compute_forward`(CPU)、`ggml_cl_compute_forward`(GPU)、`ggml_rk_compute_forward`(NPU)。tensor info と PMC を取得。CPU と OpenCL バックエンド、加えて自作の Rockchip NPU バックエンドをサポート。 - **Scheduler-level:** `sched_switch` / `sched_wakeup`(tracepoint、thread IDs を取得)。推論スレッド関連イベントにフィルタして干渉ワークロードを特定。 - **演算子引数からの構造抽出**(スライド "E.g.: Operator-level function" の `void ggml_compute_forward(…, struct ggml_tensor * tensor)`): `ggml_tensor` 構造体(`ne[4]` @0x0010, `nb[4]` @0x0030, `enum ggml_op` @0x0050, `src[10]` @0x0098, `name[64]` @0x0100)を `bpf_probe_read_user` で辿り、演算子名・型(例: `ffn_out-0`, `GGML_OP_MUL_MAT`)と source/target テンソルのアドレス・次元を抽出。 - **BPF Helpers**(スライド表): `bpf_ktime_get_ns`(Timestamp)、`bpf_get_current_pid_tgid`(PID/TID)、`bpf_get_smp_processor_id`(CPU ID)、`map.perf_read`(PMC)、`bpf_probe_read_user`(ユーザ空間アドレス読み出し)。 - **MoE 専用トレース(論文 §3.5):** `ggml_compute_forward_mul_mat_id` に uprobe をアタッチし、第3 source テンソル(`ggml_tensor`)を two-level pointer dereferencing で辿り、活性化された top-k エキスパートの ID を読む。DRAM に載らないエキスパートはストレージから fetch されるため演算子実行時間が増える。 ## PMC(ハードウェアカウンタ) 論文 §3.4・Table 3。 - 例として DRAM から fetch されたデータ量を求める: `l3d_cache_refill`(per-core、A76 では1 refill = 64 B)を `open_perf_event` で各スレッドに開き、`ggml_compute_forward` の uprobe/uretprobe 間で `perf_read` の差分を取り、全推論スレッド分を合算。 - トレース対象 PMC(Table 3): `l3d_cache_refill`(Read from memory, A76, 64B/refill)、`mem_access_wr`(Write into memory, A76, 16B)、`major-faults`(Major page faults, 1 Page)、`cycles`(CPU cycles)、`idle-backend-cycles`(stalled CPU cycles at backend)。 ## LLM トレース解析器(Offline) 論文 §4。 - **ProfDAG view(論文 §4.1, Algorithm 1):** llama.cpp は GGUF 形式でモデルを圧縮し構造情報を省くため、トレースデータから推論ワークロードのトポロジを DAG として復元。raw データを thread ID でグループ化 → 対象 decoding iteration を抽出 → operator-start/function-call イベント(step 2)ごとに差分メトリクスを計算しノードへ割当。演算子実行時間 = 初回呼び出しと最後の return の差分、PMC 差分は全スレッドで合算。`src` テンソルアドレスを反復的にクエリして依存エッジを構築(定数テンソル=重み行列はどの演算子の出力でもないためエッジ無し)。networkx で可視化。 - **ProfTime view(タイムライン、論文 §4.2):** token / graph / operator レベルの活動とスレッド間スケジューリングを可視化。`sched_switch` / `sched_wakeup` から next state(idle / runnable / running)を導出。raw データを **Chrome Trace Event Format** に変換し **Perfetto** でタイムライン表示。 - **ProfStat view(統計、論文 §4.3):** ① Across tokens(プロンプト/生成トークン数を変え TTFT・TPOT の変化を分析)、② Per operator type(例: MatMul を固定し入出力次元依存を分析、PMC で性能ボトルネック特定)、③ Across experts(MoE で活性化エキスパートを decoding iteration 横断でプロット、reuse を分析)。 ## 評価: システムセットアップ スライド "Evaluations: System setup"・論文 Table 4/5。 - デバイス: **Orange Pi 5 Pro/Ultra/Plus**(SoC RK3588/RK3588s、CPU Cortex-A76×4 + Cortex-A55×4、GPU ARM Mali-G610、NPU Rockchip NPU 6 TOPS、Memory LPDDR4/4X/5 8/16GB、OS Ubuntu 22.04 / OpenHarmony 5.1.0)、**Rubik Pi 3**(SoC QCS6490、CPU Cortex-A78×4 + Cortex-A55×4、GPU Adreno GPU 643、NPU 12 TOPS、Memory LPDDR4 8GB、OS Ubuntu 24.04)。 - llama.cpp バージョン(Table 5): CPU b4743、OpenCL (Adreno GPU) b6362、CLBlast (ARM Mali GPU) b3065、Rockchip NPU は b4984 から fork。 - オーバーヘッド計測モデル: LLaMA3.2-1B / Qwen2.5-1.5B / Gemma2-2B(FP16)。生成長 50/100/200 トークン、各構成5回実行。電力・温度は内蔵温度センサと FNB58 USB power meter(FNIRSI)で計測、コスト計測に `bpftime` を使用。 ## 評価: Profile-driven insights 論文 §5.3・スライド "Profile-driven insights" 群。 - **ProfDAG:** LLM ファミリ(LLaMA / Qwen / Gemma)で self-attention のトポロジが異なる。Qwen2.5-1.5B は LLaMA3.2-1B に対し MUL_MAT 後に ADD を持ち、Gemma2-2B は 6 演算子多い(SOFT_MAX・UNARY・RMS_NORM・MUL を各1)。3 モデルとも 2 つの MatMul(LLaMA は MUL_MAT 4/28、Gemma は MUL_MAT 4/28)が self-attention で最重。色=実行時間(10⁻²〜10⁰ ms)。演算子別にメモリ帯域も可視化(PMC: `l3d_cache_refill`, `mem_access_wr`)。 - **ProfTime:** ① **Selective operator offloading**(CPU/NPU 等のバックエンド間で MUL_MAT-ffn_up/ffn_gate/ffn_out を分散)、② **Unbalanced operators across threads**(活性化関数 UNARY-ffn_silu は片方のスレッドにほぼ集中、MatMul はほぼ均等。論文では活性化計算の約80%が片スレッドに偏る)、③ **Interfering task detection**(CPU6/7 に固定した推論スレッドが、干渉タスクで CPU6 占有時に CPU7 を共有して遅延する様子を可視化)。論文では TTFT/TPOT の97%超が MatMul に費やされると報告。 - **ProfStat(4 つの insight):** - **Across tokens:** KV cache 成長が dynamic operators(**KQ / KQV**)の実行時間に影響(iteration ごとに階段状に増加、論文 Figure 9)。 - **Per-operator:** static な行列乗算の実行時間は計算複雑度 O(M×N×K×H) に比例(論文 Figure 10、Qwen2.5-1.5B は hidden dimension 1536 が小さく切片が低い)。 - **PMC-driven:** matrix-vector 乗算性能はメモリアクセスと相関、**CPU サイクルの 50% 超(4 スレッドでは80%超)が stall**(論文 Figure 11、メモリ帯域ボトルネック)。 - **Across backends:** GPU/NPU は特定の演算子次元でのみ CPU を上回る("GPU vs CPU Execution Time Comparison Across All Models"、LM Head のような大行列で GPU が有利、Rubik Pi 上)。 - **MoE トレース(論文 §5.3.3 / Figure 13、Qwen1.5-MoE-A2.7B-Q4、計60 experts・各回4活性化):** エキスパートの平均「距離」(前回活性化からのトークン距離)が演算子時間とほぼ比例。long-distance なエキスパートはメインメモリから evict されやすく、major page faults・メモリアクセスから **MoE のボトルネックはメモリ帯域ではなくディスク I/O** と結論。Qwen1.5-MoE-A2.7B-Q4 は 4-bit でも 8.9 GB を要し Orange Pi 5 Ultra のメモリに載らず mmap でのみ実行可能。 ## 評価: 低オーバーヘッド online trace スライド "Evaluations: Low-overhead online trace"・論文 Table 6/7。 - **Overhead analysis(Orange Pi、2/4 Cortex-A76 コア、FP16 3モデル):** - BCC・全機能 ON(Str.+PMC+Perf buffer): Relative decoding speed decrease **3.67±1.21%**、CPU load 0.70±0.01%、Power +0.06±0.29 W、Temp +1.22±0.62℃。 - BCC・全 OFF: decode decrease 1.63±0.66%。 - **libbpf・全 OFF: decode decrease 1.19±0.18%**(最小、Power +0.03±0.09 W、Temp +0.31±0.90℃)。libbpf・Str. のみ: 1.46±0.30%。 - 論文本文: BCC の decode 速度低下は 1.63〜3.67%、libbpf は最小 1.19%、token/graph レベルのみなら 0.1%。プローブの CPU 負荷はほぼ無視可能、温度上昇は常に 2℃ 以内。peak RSS は 102〜172 MB、trace throughput は 0.784〜2.16 MB/s、BPF maps は 9〜11 個(各 4KB)。 - **ProfInfer vs ONNX Runtime profiler(4-bit 量子化、Str./PMC を OFF にして公平比較、論文 Table 7):** Prefill decrease ProfInfer **0.25±0.62%** vs ONNX 0.46±0.70%、Decode decrease ProfInfer **3.60±0.80%** vs ONNX **8.91±1.94%**。ProfInfer は全推論スレッドをトレースできる(ONNX は main thread の operator-level のみ)。 - **Fidelity(論文 §5.2):** uprobe/uretprobe のユーザ⇔カーネル遷移レイテンシは μs スケールで operator-level トレースへの影響は限定的。Str. 有効時は約 0.4〜0.6% のイベントが失われ得る(構造情報は決定的なので少スレッド+perf buffer でアイドル環境を繰り返し実行して回収)。 - 既存 ML プロファイラのオーバーヘッド(論文 §5.1): llama.cpp 内蔵 `ggml_graph_dump_dot` は forward pass1回が必要でその pass が **13% 長く**なる(性能データ無し)。BLIS を4コアで使うと prefill が default CPU backend 比2倍、`l3d_cache_refill`/`mem_access_wr` 解析で BLIS がメモリアクセスを 75% 削減と確認。 ## まとめと議論 スライド "Summary and discussions"・論文 §7。 - **Summary:** ProfInfer は eBPF ベースの fine-grained LLM 推論プロファイラ。Fine-grained / Non-intrusive / Low-overhead。 - **Potential use cases:** Profile-guided optimization、Lightweight runtime monitor(SCHED-EXT 等のオンラインチューニング・干渉分析・スケジューリングへ)。 - **Future work:** より低オーバーヘッド化(libbpf・bpftime への移行)、Performance adaptation(タイミング要件に応じた推論へのリソース割当調整)。inter-tensor 並列・heterogeneous backends 最適化、メモリ帯域ベンチマークによるハードウェア性能限界の把握も将来課題。 - **他 IE への移植性(論文 §7):** `perf --callgraph` や `pahole` で類似関数・データ構造を特定すれば移植は moderate effort。MNN-LLM(C++ ベース IE)の `Llm::forwardVec`, `CPUAttention::onExecute`, `AttentionExecution::onExecute` に u(ret)probe をアタッチ可能で、`MNN::Tensor` は `ggml_tensor` 類似の情報を持つ。トレーススクリプトの更新は要するが解析スクリプトは再利用可能。