# ProfInfer: An eBPF-based Fine-Grained LLM Inference Profiler
> [!abstract] 概要
> 大規模言語モデル(LLM)が研究から本番運用へ移るにつれ、推論エンジンがリアルタイムにどう振る舞うかを理解することは、本質的でありながら捉えにくいものになっている。ONNX Runtime のような汎用エンジンと異なり、今日の LLM 推論システムは演算子レベルの可視性をほとんど提供せず、開発者は時間とリソースがどこに費やされるかを把握できないままである。「このワークロードはメモリバウンドか計算バウンドか」という基本的な問いすら、しばしば未解答のまま残される。このギャップを埋めるため、現代の LLM 推論エンジン向けに、きめ細かく非侵入(non-intrusive)なプロファイリングフレームワークを開発する。題材は llama.cpp だが、類似のランタイムアーキテクチャにも適用できる。拡張 Berkeley Packet Filter(eBPF)技術の上に構築した本システムは、ソースを改変・再コンパイルすることなく、複数のレイヤーにまたがってランタイム関数へプローブを動的にアタッチする。収集したトレースを演算子・グラフ・タイムライン・ハードウェアカウンタ傾向の豊かな可視化へと変換し、密推論・Mixture-of-Experts ルーティング・演算子オフロードが実際にどう振る舞うかを露わにする。4% 未満のランタイムオーバーヘッドと高いプロファイリング忠実度により、本フレームワークは LLM 推論を透明かつ診断可能にし、性能プロファイリングを最適化・スケジューリング・リソースアウェアな展開のための実用的ツールへと変える。
関連: [[research/conferences/2026__MLSys2026__ProfInfer - An eBPF-based Fine-Grained LLM Inference Profiler|ProfInfer 聴講ノート]](スライド由来の詳細メモ。数値がスライドと論文で食い違う場合はスライドが権威) / 同系統の先行研究 [[@2025__eBPF__eInfer - Unlocking Fine-Grained Tracing for Distributed LLM Inference with eBPF]](本論文 §6 で引用)。
## 論文情報
- 著者: Bohua Zou, Debayan Roy(Correspondence), Dhimankumar Yogesh Airao, Weihao Xu, Binqi Sun, Yutao Liu, Haibo Chen(著者順は PDF 1ページ目)。
- 所属: [[Huawei Hilbert Research Center Dresden]](独 Dresden)、[[TU Munich]](独 Munich)、[[Huawei Central Software Institute]]、[[Shanghai Jiao Tong University]](中 Shanghai)。
- 公表: arXiv:2601.20755v2 [cs.SE](2026 年 1 月 29 日)。
- 査読状況: MLSys2026 に投稿中(under review)。本ページは arXiv PDF の本文・図表・abstract に遡れる内容のみを記す。
## 概要
ProfInfer は on-device LLM 推論向けのプロファイリングフレームワークで、設計は3つの柱に立つ(§1)。第一に細粒度の可観測性で、forward pass と演算子呼び出し(行列乗算・アテンション・softmax 等)ごとに、テンソル次元・演算子の種別・動的に構築される計算 DAG を捕捉する。第二に非侵入(non-intrusive)な計装で、eBPF プローブをソース改変なしにランタイム関数へアタッチし、Linux ベースのモバイル・エッジ OS へ容易に展開できる。第三にハードウェアカウンタの統合と可視化で、演算子ごとの PMC(キャッシュミス・メモリアクセス・スレッド実行など)を集め、タイムラインビュー・DAG 可視化・演算子別プロットで提示する。実装は llama.cpp 推論エンジンの上に置く(図1)。tracer がワークロード開始前にランタイムライブラリへプローブをアタッチして関連するシステムトレースイベントを有効化し、オンラインでカーネル空間の各 probe handler が submit したバッファを継続的に収集・ログし、不要なプローブを条件付きで切る。オフラインで analyzer が収集結果をパースし、計算・バックエンドの型を特定して、token / graph / operator レベルの構造・性能メトリクスを3種の表現で提示する。
## 問題設定
LLM 推論をクラウドに依存せずモバイル・エッジデバイスで行うと、オフライン動作・低レイテンシ・プライバシー向上・ネットワーク依存の低減という利点が得られる(§1)。一方でモバイルデバイスはプロセッサ電力・メモリ容量・キャッシュ挙動・熱・エネルギー予算に厳しい制約を課す。LLM 推論は prefill(典型的に計算バウンド)と decode(しばしばメモリ・帯域バウンド)の段階に分かれ、TTFT(time to the first token)と TPS/TPOT(time per output token)で評価される(§2.2.1)。
しかし LLM 推論エンジン、とくに on-device やエッジを狙うものには、細粒度で非侵入なプロファイリング支援が著しく欠けている(§1)。既存プロファイラはしばしば再コンパイルやランタイム計装を要し、スループットやトークンレートといった粗粒度のメトリクスしか出さず、動的な演算子グラフ・スレッド単位のスケジューリング・ハードウェアカウンタイベント・段階固有の挙動といった実行の重要な次元を露わにできない。さらに一部のハードウェアベースのプロファイラは下層ハードウェアの支援に依存し、無視できないオーバーヘッドを持ち込む。eBPF は深層学習の性能トレースに使われ始めているが(§1 で Chu+2025=[[@2025__eBPF__eInfer - Unlocking Fine-Grained Tracing for Distributed LLM Inference with eBPF]] ほかを引用)、LLM 実行のセマンティクスとは大きく切り離されたままで、低レベルのハードウェアメトリクスと高レベルの演算子セマンティクスを対応づける研究は乏しく、モバイル・エッジ環境にも適応されていない。
## 提案手法
### 全体構成(Tracer / Analyzer)
図1のとおり、ProfInfer は eBPF ベースの tracer と、その後段の trace analyzer から成る。スタックは IE(llama.cpp)+ GGML が OS(Ubuntu / OpenHarmony)上で動き、Backends(CPU/GPU/NPU)へ向かう。tracer はユーザ空間とカーネル空間にまたがる(図2)。実装フレームワークは2つで、Ubuntu 上では Python バインディングで rapid prototyping に向く [[BCC]](BPF Compiler Collection)を、OpenHarmony は既定で Python 非対応のため C ライブラリ [[libbpf]] を用いる(§2.3, 表1)。
ユーザ空間アプリは、ユーザ定義の設定ファイルに従って BPF プログラムのコンパイルフラグ(例: テンソル次元の取得可否)を指定し、不要情報を除いてトレースのオーバーヘッドを減らす。uprobe・uretprobe・tracepoint を対象関数へアタッチし、カーネル空間の probe handler が submit したバッファをポーリングして probe 型に応じ非同期に処理する。decode 速度が QoS 要件(例: 5 tokens/s)を下回る性能劣化を検知すると、一部のトレース機能を無効化して速度を回復する(§3.1)。カーネル空間の各 handler はスレッドの PID・実行 CPU・呼び出しタイムスタンプを記録し、引数(C 構造体または構造体ポインタ)をパースして演算子の型・入出力テンソル等の推論状態を推定する。ログには ring buffer か perf buffer を submit し、前者は効率が高いがイベント欠落が報告されない代わりとなる(§3.2)。
### eBPF プローブと多粒度トレース
§3.3・表2 のとおり、粒度ごとにプローブを設計する。
- Token-level: `llama_decode`(u(ret)probe、batch size を取得)。uprobe と uretprobe のタイムスタンプ差から prefill 時の TTFT、decode 時の TPOT を得る。この値を実行時に使い、decode 速度の QoS 要件に応じてプローブを切り替えトレースのオーバーヘッドを動的に調整する(§3.3.1)。
- Graph-level: `ggml_backend_graph_compute_async`(u(ret)probe、backend type を取得)。複数バックエンド利用時に複数の計算グラフが構築されるため、forward pass 中の各グラフの実行時間を測り、引数から `guid`(16 桁の backend 識別子)を抽出する(§3.3.2)。
- Operator-level: `ggml_compute_forward`(CPU)、`ggml_cl_compute_forward`(GPU)、`ggml_rk_compute_forward`(NPU)。tensor info と PMC を取得する。CPU と OpenCL バックエンドに加え、自作の Rockchip NPU バックエンドをサポートする。第2引数の `ggml_tensor`(C 構造体)を eBPF API で辿り、演算子の名前・型(例: `ffn_out-0`, `GGML_OP_MUL_MAT`)と source/target テンソルのアドレス・次元を抽出する(§3.3.3)。
- Scheduler-level: Linux スケジューラの `sched_switch` / `sched_wakeup`(tracepoint、thread IDs を取得)。推論スレッド関連のイベントだけにフィルタして干渉する並行ワークロードを特定する。フィルタしないとイベント数が膨大でオーバーヘッドが許容できなくなる(§3.3.4)。
[[動的インストルメンテーション]]の基盤として、表1 に BCC が提供する BPF API(`bpf_ktime_get_ns`=タイムスタンプ、`bpf_get_current_pid_tgid`=pid/tid、`bpf_get_smp_processor_id`=cpu id、`map.perf_read`=PMC 読み出し、`bpf_probe_read_user`=ユーザ/カーネル空間読み出し、`attach_u(ret)probe`、`attach_tracepoint`、`open_perf_event`、`perf(ring)_buffer_poll` など)をまとめる。libbpf にも同等の API がある。
### PMC(ハードウェアカウンタ)
PMC は CPU の計算・メモリアクセスに関する低レベルの知見を与えるため、ProfInfer は演算子レベルで PMC を開いて読む(§3.4)。例として演算子の DRAM 取得データ量を求めるには、per-core の `l3d_cache_refill`(A76 では 1 refill = 64 B)を `open_perf_event` で各スレッドに開き、`ggml_compute_forward` の uprobe/uretprobe 間で `perf_read` の差分を取り、全推論スレッド分を合算する。表3 のトレース対象 PMC は `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)。こうした [[ハードウェアカウンタ]] ベースの分析が、演算子ごとのリソース未活用やバウンド性、その他のボトルネックの特定を助ける。
### MoE モデルのエキスパート活性トレース
[[Mixture-of-Experts]] モデルでは decode iteration ごとに transformer 層の FFN で異なるエキスパートが活性化する(§3.5)。活性化は softmax/sigmoid に top-k 演算子が続く gating で決まり、結果は活性化された k 個のエキスパート ID を並べた長さ k のテンソルになる。ProfInfer は `ggml_compute_forward_mul_mat_id` に uprobe をアタッチし、第3 source の `ggml_tensor` を two-level pointer dereferencing で辿って k 個のエキスパート ID を読む。モバイルデバイスの DRAM は全エキスパートを載せきれないのが普通で、活性化されたエキスパートが DRAM に無いとストレージから fetch され演算子実行時間が増えるため、活性トレースが演算子レベルの正確な性能分析を可能にする。
### Analyzer の3ビュー
LLM とハードウェア構成を入力に raw トレースを生成し、3種のビューを作る(§4)。
- ProfDAG view(§4.1, Algorithm 1): llama.cpp は構造情報を持たない gguf 形式へモデルを圧縮するため、ProfDAG はトレースからワークロードのトポロジを DAG として復元し、演算子ごとのプロファイル結果を載せる。raw データを thread ID でグループ化し、対象 decoding iteration の演算子イベントのみを抽出、開始イベント(step 2)ごとに属性とメトリクスをノードへ割り当てる。実行時間は初回呼び出しと最後の return の差分、PMC 差分は各スレッドで取り合算する。`src` テンソルのアドレスを反復クエリして依存エッジを構築し、どの演算子の出力でもない source(典型的には重み行列=定数テンソル)はエッジを持たない。グラフは networkx で生成・描画する。図3 は LLaMA3.2-1B-F16 を Orange Pi 5 Ultra 上の 2 個の Cortex-A76 コアで動かした FFN の ProfDAG をメモリ帯域で示す。
- ProfTime view(タイムライン、§4.2): token/graph/operator レベルの活動とスレッド間スケジューリングを可視化する。`sched_switch` / `sched_wakeup` のコンテキストから次状態(running / runnable / idle)を導出し、`prev_state` でプリエンプト等を判別、CPU ID をイベント名に付す。raw を Chrome Trace Event Format に変換し [[Perfetto]] でタイムライン表示する。
- ProfStat view(統計、§4.3): 3次元で分析する。Across tokens(プロンプト/生成トークン数を変え prefill と各 decode iteration の時間変化と影響演算子を分析)、Per-operator type(例: MatMul を固定し入出力次元依存を分析、CPU の PMC と他バックエンドの結果でボトルネックを特定)、Across experts(MoE で活性化エキスパートを iteration 横断でプロットし reuse を分析)。
## 新規性
論文が掲げる主な貢献は3点(§1)。第一に、細粒度・非侵入・軽量で、モバイルとエッジの双方に適した eBPF ベースの LLM 推論プロファイリングフレームワークの提案。第二に、forward pass・計算グラフ・演算子実行・プロセッサスレッドまで推論パイプライン全体を可視化し、ハードウェアカウンタで豊富なメトリクスを集めること。第三に、モデル構造とハードウェア挙動を対応づけるタイムラインビュー・DAG 可視化・演算子別プロットという直感的な性能分析の提供。関連研究(§6)に照らすと、既存プロファイラは (i) ML ランタイム内への侵入的計装を要するか、(ii) サービングフレームワーク経由で粗粒度メトリクスしか出さないか、(iii) 演算子セマンティクスを統合せずモバイルハードウェアも支援しない eBPF トレースに留まる。ProfInfer は eBPF の動的プローブと演算子レベルの PMC 監視を組み合わせ、これらのギャップを埋める。とくに先行する [[@2025__eBPF__eInfer - Unlocking Fine-Grained Tracing for Distributed LLM Inference with eBPF]](Chu+2025、分散 LLM 推論向けの eBPF トレース)や eGPU(Yang+2025)が演算子と PMC のセマンティック対応やモバイル対応を欠く点に対し、本論文は on-device の制約下でその対応づけを実現する点を差別化として挙げる。
## 実験設定
表4 の3デバイスで評価する(§5)。Orange Pi 5 Plus(SoC RK3588、32G LPDDR4/4X、OS OpenHarmony 5.1.0)、Orange Pi 5 Ultra(SoC RK3588、8G LPDDR5、OS Ubuntu 22.04.5)、RUBIK Pi 3(SoC QCS6490、8G LPDDR4X、OS Ubuntu 24.04)。OpenHarmony の軽量設計のため Orange Pi 5 Plus では libbpf で開発し、より機能の多い他デバイスでは BCC を用いる。オーバーヘッド計測の対象モデルは LLaMA3.2-1B / Qwen2.5-1.5B / Gemma2-2B、MoE トレースは Qwen1.5-MoE-A2.7B-Q4(計60エキスパート・各回4活性化)。プロファイル駆動の分析では ARM Mali GPU 向け CLBlast、Adreno GPU 向け OpenCL、自作 Rockchip NPU バックエンドも用いる(§5.2)。
## 実験結果
### オーバーヘッド
ProfInfer のオンラインオーバーヘッドは `bpftool` で各プローブのコストを集め、decode 段のメッセージパッシングとロギングによる decode 速度低下を表5(Orange Pi 5 Pro=BCC、Orange Pi 5 Plus=libbpf、2 と 4 個の Cortex-A76 コア)にまとめる(§5.1)。プローブの平均 CPU 負荷はほぼ無視できる。BCC では decode 速度低下が 2.8% から 4.0% まで変動し、C ベースの libbpf は最小の 1.7% だが一部機能は未対応。いずれもどの演算子型も切らずに計測した値で、token・graph レベルのみのトレースなら速度低下は 0.1% にとどまる。abstract が掲げる「4% 未満のランタイムオーバーヘッド」と整合する。prefill 段には影響がない。
> [!note] 比較対象の既存 ML プロファイラ
> llama.cpp 内蔵の `ggml_graph_dump_dot` は forward pass を1回要し、その pass が使わない場合より 13% 長くなる(=13% のオーバーヘッド)が、性能データは出さず構造情報のみ(§5.1)。予備実験では ONNX Runtime のプロファイラの時間オーバーヘッドはモデル実行時間の約 8% だった。
> 聴講ノート(表7 相当)では ProfInfer vs ONNX Runtime profiler を 4-bit 量子化・Str./PMC を OFF にした公平比較で示し、prefill 低下 0.25% 対 0.46%、decode 低下 3.60% 対 8.91% で ProfInfer が有利、かつ ProfInfer は全推論スレッドをトレースできる(ONNX は main thread の演算子レベルのみ)。
### プロファイル駆動の知見
- ProfDAG(§5.2.1, 図4, 図3): LLaMA3.2-1B / Qwen2.5-1.5B / Gemma2-2B で self-attention のトポロジが異なる。Qwen2.5-1.5B は LLaMA3.2-1B に対し3つの MUL_MAT の後に ADD を持ち、Gemma2-2B は SOFT_MAX を3つ、UNARY・RMS_NORM・MUL を各1つ多く持つ(計6演算子多い)。3モデルとも self-attention で2つの MatMul(例: Gemma2-2B の MUL_MAT 4 と 28)が最重で、同一演算が LLaMA3.2-1B(MUL_MAT 3)と Gemma2-2B(MUL_MAT 4)では Qwen2.5-1.5B(MUL_MAT 3)より時間がかかる。図4 ではノード色が実行時間(10⁻²〜10⁰ ms)を、図3 では平均メモリ帯域を表す。
- ProfTime(§5.2.2, 図5〜図8): llama.cpp はテンソル演算を逐次実行するが、1つの演算(MatMul 等)は複数スレッドで走るため intra-operator 並列はあるが inter-operator 並列はない(図5)。TTFT/TPOT の 97% 超が MatMul に費やされる。計算負荷はスレッド間で一様でなく、活性化関数では片方のスレッドにほぼ計算が集中し他方は演算子実行時間の約 80% アイドルだが、MatMul はほぼ均等に分かれる(図6)。複数バックエンド(CPU/Rockchip NPU、CPU/OpenCL=Adreno GPU)へのグラフ分割をビュー上で示し、CLBlast 経由で MatMul を ARM Mali GPU へオフロードする様子も見える(図7)。さらに高優先度の干渉タスクで演算子が遅延する様子を特定でき、CPU6 を占有する干渉スレッドのため2つの推論スレッドが CPU7 を共有し、CPU6 が空くと両スレッドが2 CPU で同時実行する様子を可視化する(図8)。
- ProfStat(§5.2.3, 図9〜図12): Across tokens では KV-cache 機構が computation を減らし decode スループットは安定するが、KV cache の成長で各 iteration の経過時間は増え、KQ と KQV が劣化に最も寄与し context 長の増加とともに階段状に増える(図9)。Per-operator type では、KQ/KQV を除く MatMul の実行時間は計算複雑度 O(M×N×K×H) に比例し、Qwen2.5-1.5B は hidden dimension 1536 が小さく切片が低い=同次元の演算が速い(図10)。decode はメモリ集約で、メモリアクセスとスレッド数で速度が変わるがおおむね 2 スレッドまでしか伸びず、メモリ帯域ボトルネックに達する。4 スレッドでは stalled cycle が全 CPU サイクルの 80% を超え資源の浪費になる(図11)。dense モデルの decode 速度は MatMul の線形相関からハイパーパラメータで予測できる。prefill では BLIS を 4 個の Cortex-A76 コアで使うと既定より2倍速くなり、`l3d_cache_refill`/`mem_access_wr` の解析でメモリアクセスを 75% 削減すると確認した。Across backends では、Rubik Pi の Adreno GPU と CPU(4 スレッド peak)で 4-bit 量子化3モデルの static MatMul を比較し、GPU が CPU を上回るのは一定の次元範囲のみで、行列の大きい LM Head では GPU 性能が劇的に落ちる(図12)。よってテンソル次元に基づく selective operator offloading が推論を加速し得る。
- MoE トレース(§5.2.3, 図13): Qwen1.5-MoE-A2.7B-Q4 の `ffn_moe_up-0` 演算子で、活性化エキスパートの平均「距離」(前回活性化からの iteration 距離)が演算子時間とほぼ比例する。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 でのみ実行可能。
## 考察
ProfInfer は eBPF ベースの動的プローブと演算子レベルの PMC 監視を結合し、ランタイムイベントとハードウェア挙動を対応づけてモバイル上でモデル実行を可視化することで、非侵入・細粒度の可観測性を達成する(§6, §7)。想定用途は profile-guided optimization と軽量なランタイムモニタである。将来課題として、演算子レベルのプロファイル結果に基づき、decode 段で異種バックエンドにまたがる inter-tensor 並列を引き出すグラフ分割の実装、最大メモリアクセス能力を明らかにするメモリベンチマーク(Zuepke+2024, Pradhan+2025)によるハードウェア性能限界の把握を挙げる(§7)。聴講ノートには、より低オーバーヘッド化に向けた [[bpftime]] への移行や、他 IE(MNN-LLM 等)への moderate effort での移植可能性も記録されている。
## 強み
- ソース改変・再コンパイル不要の非侵入トレースで、本番に近い on-device 環境にそのまま展開できる(§1, §3)。
- token/graph/operator/scheduler の多粒度を1つのフレームワークで横断し、PMC で低レベルのハードウェア挙動を演算子セマンティクスへ対応づける(§3, 表2, 表3)。
- 4% 未満のオーバーヘッドで、ONNX Runtime profiler(decode 約 8.91% / 予備実験で約 8%)より軽量、かつ全推論スレッドをトレースできる(§5.1, abstract)。
- MoE のディスク I/O ボトルネック、selective operator offloading、スレッド間の負荷不均衡など、実機での具体的な最適化知見を引き出す(§5.2)。
## 弱点・課題
- サポートするバックエンドは CPU・OpenCL・自作 Rockchip NPU に限られ、他バックエンドへの拡張は将来課題(§3.3.3)。
- ring buffer 利用時はイベント欠落が報告されず、Str.(構造抽出)有効時には一部イベントが失われ得る(§3.2、聴講ノート §5.2 の fidelity 議論)。
- 評価は Orange Pi / Rubik Pi クラスのエッジデバイスと小〜中規模モデル(1B〜2.7B)に限られ、サーバ級ハードウェアや大規模モデルは対象外(§5, §6)。
- inter-tensor 並列を引き出すグラフ分割や他 IE への移植は未実装の将来課題(§7)。