hapi_memory_daemon: EOF path spins at 1 kHz for the life of the run; EINTR path spins unthrottled
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 42/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- cmake, cpp, linux
調査の方向性
Start in src/arch/cuda/hybridAPI/hapi_memory_daemon.cpp at the FIFO open (O_RDONLY | O_NONBLOCK then blocking) and the main read() loop: the bytes_read == 0 branch with usleep(1000) and the EINTR continue. Cross-check launch and device init in hapi_impl.cpp (hapiStartMemoryDaemon, hapiSetDevice) and the SHRINKEXPAND / CMakeLists.txt build of the standalone daemon. Done means the idle path blocks instead of spinning, EINTR is throttled or handled via poll/epoll, and placement/pinning is documented for the external launcher.
索引モデルが issue の本文から書いたものです。
説明
Summary
src/arch/cuda/hybridAPI/hapi_memory_daemon.cpp (the shrink/expand GPU-memory daemon, built as a standalone executable when SHRINKEXPAND is on — CMakeLists.txt:819) has a main loop that spins at ~1000 wakeups/second whenever no client is attached, which is most of a run. A second path spins unthrottled. Found by inspection while investigating core interference in GPU runs; not yet measured, so the severity claim below is analytical rather than empirical.
The 1 kHz path
The server FIFO is opened O_RDONLY | O_NONBLOCK (hapi_memory_daemon.cpp:144) and then switched to blocking (:151-152). With a FIFO in that state, read() returns 0 immediately when no writer is attached rather than blocking. The loop's response is:
else if (bytes_read == 0)
{
// A writer closed the connection. The FIFO is still open.
// The next read() will block until a new writer connects.
// A small sleep prevents a potential tight spin-loop on misconfiguration.
usleep(1000);
}
The comment's premise does not hold: the next read() does not block, it returns 0 again. So the usleep(1000) does not prevent a spin loop, it throttles one to 1 kHz — permanently, from before the first client ever connects, and again after every client disconnects.
The unthrottled path
else // bytes_read < 0
{
if (errno == EINTR) {
continue; // no sleep
}
...
}
If signals arrive repeatedly (profilers, the GPU runtime, job-control), this is a bare spin with no throttle at all.
Why it matters beyond the wasted cycles
The daemon's placement is not controlled by Charm. hapiStartMemoryDaemon() in hapi_impl.cpp:236 only creates FIFOs and blocks waiting on /tmp/daemon_ready_<device> — the daemon process itself is launched externally by the job script, so it inherits the launcher's affinity mask, not a PE's. On a node where that mask overlaps the worker cores, a 1 kHz wakeup source lands on a busy-polling PE's core. One daemon exists per device (four on a typical 4-GPU node).
The daemon also calls hapiSetDevice (hapi_memory_daemon.cpp:134) and so holds its own GPU context, which brings its own runtime helper threads, inheriting the daemon's mask. See charmplusplus/charm#3972 for why that thread class matters.
Note also that under CMK_SHRINK_EXPAND this call replaces the normal device-init path (hapi_impl.cpp:210-215), so shrink/expand builds take a different hapiSetDevice route from everyone else.
Suggested fixes
- Block properly instead of polling: either keep a write descriptor open on the FIFO in the daemon so
read()blocks rather than seeing EOF, or usepoll()/epollon the read end and only thenread(). - Give the
EINTRpath the same throttle as the EOF path, or handle it viapoll()above. - Document the daemon's expected placement (and pin it in the launcher), since Charm cannot control it from inside.
How to confirm
On a shrink/expand run: grep Cpus_allowed_list /proc/<daemon_pid>/status for overlap with worker cores, and check the daemon's nonvoluntary_ctxt_switches / a PE's runqueue wait in /proc/<tid>/schedstat on any shared core.
- 主要言語
- C++
- スター
- 241
- フォーク
- 62
- 平均マージ
- 1日 1時間
- マージ済み PR(30日)
- 121
環境構築
このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
charmplusplus/charm のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
charmplusplus/charm#4210 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
charmplusplus/charm#4160 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
charmplusplus/charm#3619 · コメント 4 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 3/5 1〜2日 初心者へのやさしさ 52/100
charmplusplus/charm#4204 ·
メンテナーはふだん 1 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 49/100
charmplusplus/charm#4200 ·
メンテナーはふだん 1 日以内に返信
charmplusplus/charm の issue をすべて見る
似ている issue
-
help wanted new command
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
tldr-pages/tldr#25111 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
メンテナーはふだん 1 日以内に返信
-
bug test
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
OpenAssetIO/OpenAssetIO#1527 ·
-
iOS Fabric pointer-handler reset leaves the next lone touch non-primary対応中かも @alleneubank が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
react/react-native#59919 ·
メンテナーはふだん 2 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 66/100
ROCm/rocm-systems#15475 ·
メンテナーはふだん 2 日以内に返信