Skip to content

fix(rocjitsu): DBT host selection on multi-GPU systems - #9213

Merged
amd-arosa merged 34 commits into
developfrom
users/arosa/rj/fix-dbt-tests-multigpu
Aug 4, 2026
Merged

amd-arosa merged 34 commits into
developfrom
users/arosa/rj/fix-dbt-tests-multigpu

Conversation

@amd-arosa

Copy link
Copy Markdown
Contributor

Motivation

Rocjitsu DBT tests fail before entering their test bodies when multiple GPUs share the configured host ISA. Automatic host_gpu_id: 0 selection was rejected as ambiguous, and simulator-backed DBT was incorrectly checked against physical KFD topology.

This change makes one synthetic DBT guest select one host consistently while respecting standard ROCm device visibility.

Technical Details

  • Resolve automatic host selection from the backend topology after applying ROCR_VISIBLE_DEVICES, then HIP_VISIBLE_DEVICES or its CUDA_VISIBLE_DEVICES fallback.
  • Preserve ROCr numeric/UUID and CLR client-selector semantics in a focused, testable visibility helper.
  • Validate explicit GPU pins for visibility and ISA compatibility.
  • Atomically publish the config path and resolved KFD GPU ID through the existing per-invocation runtime handoff so the launcher, KFD interposer, and HSA hook share one selection.
  • Support both physical and simulator execution topologies without a private application-facing environment variable.
  • Add unit and integration coverage for selector ordering, UUIDs, malformed handoffs, explicit pins, simulator topology, and multi-GPU execution.

Issue Tracking

Fixes #9212

Test Plan

  • Build rocjitsu_bin, rocjitsu_shared, rocjitsu_hooks, rocjitsu_tests, and launch_preload_test.
  • Run all ConfigLoaderTest, LaunchPreloadTest, and RocmVisibilityTest tests.
  • Run all affected simulator- and hardware-backed DBT integration tests.
  • Exercise combined ROCR_VISIBLE_DEVICES and HIP_VISIBLE_DEVICES ordering on an eight-GPU gfx942 system.

Test Result

  • 52/52 config, launcher, and visibility tests passed; two sanitizer-runtime-specific tests were skipped as expected.
  • 25/25 affected DBT integration tests passed on an eight-GPU gfx942 host.
  • Representative simulator and combined ROCR/HIP selector probes passed.
  • Pre-commit whitespace, EOF, clang-format, and gersemi hooks passed.

Submission Checklist

Resolve automatic DBT host selection against the effective ROCm-visible topology and publish the selected KFD GPU ID through the atomic runtime config handoff.\n\nAdd selector, handoff, and selection edge-case coverage.\n\nRefs #9212
@amd-arosa
amd-arosa requested review from a team and atgutier as code owners July 24, 2026 16:31
@github-actions github-actions Bot added documentation Improvements or additions to documentation project: rocjitsu labels Jul 24, 2026
@therock-pr-bot

therock-pr-bot Bot commented Jul 24, 2026 •

Copy link
Copy Markdown

✅ All Checks Passed — Ready for Review

Check Status Details
📝 PR Description ✅ Pass —
⛔ Forbidden Files ✅ Pass —
🧪 Unit Test ✅ Pass —
🔎 pre-commit ✅ Pass —
🚫 Draft PR 🔜 To Be Enabled —
🚩 Feature Flag 🔜 To Be Enabled —
📊 Code Coverage 🔜 To Be Enabled —
🤖 therock-pr-bot ✅ Pass —

🎉 All checks passed! This PR is ready for review.

📖 Need help? See the Policy FAQ for details on every check and how to fix failures.

🙋 Wish to Override Policy?

@amd-arosa amd-arosa changed the title Fix rocjitsu DBT host selection on multi-GPU systems fix(rocjitsu): DBT host selection on multi-GPU systems Jul 24, 2026
@therock-pr-bot

Copy link
Copy Markdown

🎉 All checks passed! This PR is ready for review.

@amd-arosa

Copy link
Copy Markdown
Contributor Author

fixing merge conflicts

@amd-arosa
amd-arosa force-pushed the users/arosa/rj/fix-dbt-tests-multigpu branch from 6a5bdb9 to 9378a5e Compare July 24, 2026 16:45
…-dbt-tests-multigpu

# Conflicts:
#	emulation/rocjitsu/tests/launch_preload_test.cpp

@atgutier atgutier left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple agent items:

MAJOR

  1. tools/rocjitsu/rocm_visibility.cpp:61-69,111-119 — malformed selectors are converted into valid device selections.

    The parser is more permissive than the ROCr and CLR implementations it models:

    • ROCR_VISIBLE_DEVICES=GPU- is invalid in ROCr. On a one-GPU topology, rocjitsu accepts it as a unique UUID prefix and rewrites it to 0,1, exposing both host and guest.
    • CLR requires numeric HIP/CUDA tokens to use canonical decimal spelling. HIP_VISIBLE_DEVICES=01 should terminate selection, but rocjitsu accepts ordinal 1 and normalizes it to 1.

    This is not merely diagnostic drift: invalid isolation settings that should expose no device can instead select and execute on a GPU.

    Fix: enforce ROCr’s UUID-token length requirements and, after parsing a client ordinal, require token == std::to_string(index). Add coverage for GPU-, 01, 00, and valid-prefix-then-malformed sequences.

    Confidence: high.

  2. lib/rocjitsu/src/rocjitsu/kmd/linux/interposer.cpp:168-181 — the interposer can consume a different GPU ID than the HSA hook.

    The launcher writes:

    The HSA-hook loader reads the complete file, but the interposer performs one read() capped at 4095 bytes and treats any positive result as complete. A valid near-PATH_MAX config path can place only part
    of the GPU ID inside that buffer. For example, the interposer can parse 2 while the HSA hook parses 28851; if the newline falls outside the buffer, the interposer instead performs its own automatic
    selection.

    That directly violates the PR’s central invariant that GuestKfd and the HSA hook share one resolved host. KFD operations may then be rewritten to one GPU while queues and translated code objects use
    another.

    Fix: read to EOF into a dynamic buffer, retry EINTR, fail on other read errors, and apply a deliberate maximum handoff size. Add a handoff exceeding 4095 bytes and verify both consumers obtain the
    identical ID.

    Confidence: high.

MINOR

  1. tests/config_test.cpp:637-660 — the new runtime-handoff test uses the fixed shared directory /tmp/rocjitsu_runtime_config_handoff_test.

    Concurrent test processes can overwrite each other’s config_path or remove the directory while another process is reading it, producing flaky failures or cross-test configuration reads.

    Fix: use the existing test::ScopedTempDirectory helper and RAII cleanup.

    Confidence: high.

@kuhar kuhar left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments

@kuhar kuhar left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments

@amd-arosa
amd-arosa requested a review from kuhar July 24, 2026 22:22

@kuhar kuhar left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should mirror the malformed-UUID validation on the client path. In emulation/rocjitsu/tools/rocjitsu/rocm_visibility.cpp:114-117, filter_client_visible_gpus still treats any token containing GPU- as a substring match; against the current source, bare GPU- selects gpu_id 100 and 1,GPU-,2 exposes all three GPUs, while the ROCR path rejects it. Please require a valid GPU-... prefix and length, use prefix matching, and cover both inputs in MalformedSelectorsTerminateSelection.

@amd-arosa

Copy link
Copy Markdown
Contributor Author

emulation/rocjitsu/tools/rocjitsu/rocm_visibility.cpp:114-117, filter_client_visible_gpus still treats any token containing GPU- as a substring match; against the current source, bare GPU- selects gpu_id 100 and 1,GPU-,2 exposes all three GPUs, while the ROCR path rejects it. Please require a valid GPU-... prefix and length, use prefix matching, and cover both inputs in MalformedSelectorsTerminateSelection.

are you sure?

if (token.size() >= 5 && token.size() <= 20 && token.starts_with("GPU-") && token != "GPU-XX") {

and the test

[TEST(RocmVisibilityTest, MalformedSelectorsTerminateSelection) {
EXPECT_TRUE(rocjitsu::cli::filter_rocr_visible_gpus(test_gpus(), "GPU-").empty());
EXPECT_TRUE(rocjitsu::cli::filter_client_visible_gpus(test_gpus(), "01").empty());
EXPECT_TRUE(rocjitsu::cli::filter_client_visible_gpus(test_gpus(), "00").empty());

const auto rocr_prefix = rocjitsu::cli::filter_rocr_visible_gpus(test_gpus(), "0,GPU-,1");
ASSERT_EQ(1u, rocr_prefix.size());
EXPECT_EQ(100u, rocr_prefix[0].gpu_id);

const auto client_prefix = rocjitsu::cli::filter_client_visible_gpus(test_gpus(), "1,00,2");
ASSERT_EQ(1u, client_prefix.size());
EXPECT_EQ(101u, client_prefix[0].gpu_id);
}](

TEST(RocmVisibilityTest, MalformedSelectorsTerminateSelection) {
EXPECT_TRUE(rocjitsu::cli::filter_rocr_visible_gpus(test_gpus(), "GPU-").empty());
EXPECT_TRUE(rocjitsu::cli::filter_client_visible_gpus(test_gpus(), "01").empty());
EXPECT_TRUE(rocjitsu::cli::filter_client_visible_gpus(test_gpus(), "00").empty());
const auto rocr_prefix = rocjitsu::cli::filter_rocr_visible_gpus(test_gpus(), "0,GPU-,1");
ASSERT_EQ(1u, rocr_prefix.size());
EXPECT_EQ(100u, rocr_prefix[0].gpu_id);
const auto client_prefix = rocjitsu::cli::filter_client_visible_gpus(test_gpus(), "1,00,2");
ASSERT_EQ(1u, client_prefix.size());
EXPECT_EQ(101u, client_prefix[0].gpu_id);
}
)

Compile the hook sources once into rocjitsu_hooks_objects and link them
into two shared libraries: the installed rocjitsu_hooks, which exports
only OnLoad and OnUnload, and the test-only rocjitsu_hooks_testing,
which adds rj_hsa_dbt_set_topology_nodes_root_for_test.

Both shared libraries must name RJ_HOOKS_LINK_LIBS themselves: CMake
propagates an object library's usage requirements transitively but not
its object files, so attaching the ISA and VM dependencies only to
rocjitsu_hooks_objects leaves them out of the linked libraries.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@amd-arosa
amd-arosa requested a review from kuhar July 31, 2026 18:49

@kuhar kuhar left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should apply the UUID spelling checks to filter_client_visible_gpus as well. The size and starts_with guard quoted in the existing discussion is only in the ROCR branch; emulation/rocjitsu/tools/rocjitsu/rocm_visibility.cpp:114-117 still uses substring matching, so bare GPU- selects gpu_id 100 and 1,GPU-,2 produces 101,100,102 at 7010b4e. Please require a valid GPU- prefix and length there and add both cases to MalformedSelectorsTerminateSelection.

amd-arosa and others added 5 commits August 3, 2026 17:32
relocate_active_config_to_long_path() grew the parent directory greedily in
201-byte steps, then subtracted a separator from whatever remained. When the
handoff directory's length was congruent to the 4081-byte target modulo 201
(61 bytes, for one), the loop landed exactly on the target and the remainder
underflowed to SIZE_MAX. std::string then threw std::length_error, which the
filesystem_error handler does not catch, so the helper terminated the test
process instead of failing it. One byte short of the target left no room for a
separator plus a component and fell through to a bare false.

Plan the padding from the byte budget instead: split it across the fewest
components that stay within the per-component limit and spread the characters
evenly, so every intermediate length stays in range. Return an
AssertionResult naming the size invariant that failed for the two budgets no
component can spend, and for the I/O and filesystem failures that previously
also returned a bare false.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
GuestKfd rejects a host gpu_id it cannot match with ENODEV, but the HSA hook
did not. When node_id_for_kfd_gpu_id() found no topology node for the
configured host, AgentMapper recorded no mapping and rj_iterate_agents() fell
through to the original iterator, publishing both physical agents. An
application using the default device then ran untranslated on the real host,
bypassing the guest entirely.

Public enumeration is the replacement boundary, so fail closed there. Track
whether the config demanded a mapping so the passthrough stays available when
there is nothing to map, and return HSA_STATUS_ERROR when a required mapping
was never resolved. MissingResolvedHostKeepsPhysicalAgentOrder pinned the old
passthrough; it now expects the failure and is renamed accordingly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
rocm_visibility.{h,cpp} arrived with all 24 of its tests wedged into
launch_preload_test.cpp, between that file's own cases. The file was
advertising eight preload tests and carrying thirty-two.

tests/ mirrors the source structure and this directory already follows
one-file-per-unit, so give the visibility helpers their own test file.
The only coupling was that rocm_visibility.cpp links into the existing
rocjitsu_cli_launch_preload target, which is a build detail rather than
a reason to share a test file.

Pure move: no test was added, removed, or changed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
filter_client_visible_gpus() gated its UUID branch on a bare substring
search, so any token merely containing "GPU-" was resolved against the
first agent whose UUID also contained it. A bare "GPU-" selected gpu_id
100, and "1,GPU-,2" produced 101,100,102 -- an invalid isolation setting
silently selecting devices instead of terminating selection.

Apply the same spelling guard the ROCR path already used, factored into
is_gpu_uuid_selector(): "GPU-" plus 1..16 hex digits of the 64-bit id,
rejecting the "GPU-XX" sentinel ROCR reports for agents without UUID
support. The comparison becomes a prefix match rather than a substring
search.

This makes rocjitsu deliberately stricter than the runtime it models --
CLR gates on the same bare find() with no length or prefix check
(projects/clr/rocclr/device/rocm/rocdevice.cpp:431-444), so CLR resolves
"GPU-" to agent 0 too. The divergence is safe only because CLR never
sees a token rocjitsu rejected: this filter runs in DBT guest mode,
where main.cpp unconditionally rewrites the client selector to
normalized_client_visible_devices()'s canonical numeric list before
execvp. Both the guard and the rewrite carry comments saying so.

Everything below the guard stays CLR-shaped, preserving the intentional
ROCR-vs-CLR split that DuplicateAndReorderedSelectorsMatchRuntimeBehavior
documents: first match wins rather than terminating on ambiguity, and
the comparison stays case-sensitive.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…coped

Refusing to enumerate agents when the DBT host never resolved was right
in direction but wrong in three ways.

It latched. ensure_discovered() published discovered_ = true even when
discovery failed, and clear() only runs at OnUnload, so a single
transient miss -- sysfs EMFILE/EACCES, a topology tree not yet
populated, ROCR not yet enumerating -- poisoned agent enumeration for
the life of the process. Classify the failure instead: TopologyLookup
separates "read the whole tree, gpu_id is absent" from "could not read
the tree", and DiscoveryOutcome turns that into a retryable or final
verdict, retried a bounded number of times. Only snapshot() opts in;
map(), is_guest(), guest_agent() and host_for_guest() stay cached-only
and O(1), because they run once per copy and once per dispatch. The
settled-state check now precedes the condition-variable wait so those
callers cannot park behind another thread's retry.

It was too broad. Returning HSA_STATUS_ERROR suppressed CPU agents too,
breaking host fine-grained pools, hsa_amd_memory_lock and host-side
copies that were never a translation hazard, and handing HIP an opaque
init failure rather than an empty device list. Filter GPU agents on the
refusal path and let CPU agents through; anything that cannot be
positively classified counts as a GPU and is suppressed.

It was too narrow. The fail-closed property rested entirely on no agent
handle escaping enumeration. With no mapping, is_guest() returns false,
so rj_executable_load_agent_code_object took its pass-through branch and
would load untranslated guest code on the raw host. Guard the five
GPU-only execution entry points with mapping_unusable(); deliberately
leave the query and copy hooks unguarded, since they legitimately take
CPU agents.

Also refuse rather than guess when a config reaches the hook with no
resolved host gpu_id. The host predicate was only constrained by driver
node id when host_gpu_id != 0; at 0 it degraded to "any agent with the
host ISA" -- the first-ISA-match selection this series exists to remove.
That was unreachable only because load_dbt_guest_config_from_handoff()
throws two files away, which is coincidental correctness in the
fail-open direction.

Resolve the host before the guest so a same-ISA config cannot let the
guest predicate claim the physical host, and report that collision
distinctly from "no agents found".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@amd-arosa
amd-arosa requested a review from kuhar August 3, 2026 21:44
amd-arosa and others added 4 commits August 3, 2026 21:48
GuestKfd::ensure_ready_locked() still derived its own host GPU by
scanning the topology for the first ISA match when host_gpu_id_ was 0.
This series added the arm that verifies a supplied gpu_id but left the
arm that invents one, so a working implementation of the per-layer
divergence bug remained -- the KFD interposer and the HSA hook could
each pick a different physical GPU on a box with identical devices.

It was dead in practice, but only because load_dbt_guest_config_from_
handoff() rejects an enabled DBT config carrying gpu_id 0, an invariant
enforced in a different file with nothing here stating it. Refuse
instead, matching the hook-side refusal, and delete the two helpers that
had no other caller.

The interposer reported the same invariant through Logger::debug_print,
which is `if constexpr` compiled out unless debug logging is configured
on, so the KFD half of the fail-closed contract was silent in every
shipped build while the HSA half printed. Use Logger::warn per the
logging rule this series documents.

Drop apply_resolved_dbt_host_gpu_id()'s `source` parameter, which had a
single production caller and one fixed test string.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
relocate_active_config_to_long_path() returns testing::AssertionResult,
so every precondition failure was a red test -- including ones that say
nothing about the code under test. A CI runner whose
$ROCJITSU_INVOCATION_DIR is already deeper than the >4095-byte handoff
being constructed would fail ReadsRuntimeHandoffLargerThan4095Bytes
while the reader it exercises is fine.

GTEST_SKIP expands to a bare return and cannot be issued from a function
returning AssertionResult, which is why this stayed as it was. Return a
tri-state instead and let the test body issue the verdict: environmental
preconditions skip with a reason, genuine defects -- write failures, a
built path that misses its target length -- stay red. Nothing is
silently swallowed.

Register the new case with SKIP_REGULAR_EXPRESSION so a skip cannot be
reported as a pass.

Also hoist config_test.cpp's local ScopedEnvironmentVariable into
scoped_temp.h beside ScopedTempDirectory, and use it from guest_kfd_test
rather than hand-rolling save/restore a third time.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
any_agent_could_be_a0() folded "an A0 part was found" and "agent
enumeration failed" into one bool. Both correctly refuse the load, so
the behaviour was already fail-safe -- but when a co-loaded HSA tool
fails enumeration, the refusal is reported as an A0 incompatibility and
the real cause is invisible.

Split the verdict into kNone / kPossible / kUnenumerable so the last can
log what actually happened. Both refusal branches still return
HSA_STATUS_ERROR_INCOMPATIBLE_ARGUMENTS, so no caller observes a change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
CONTRIBUTING.md and docs/style.md both stated a blanket ban on fprintf,
printf and std::cerr that the tree has never followed: the hook layer
has ~30 tagged stderr diagnostics on hard-error paths, tools/ writes
user-facing errors to std::cerr, and the signal backtrace handler uses
raw ::write because it must stay async-signal-safe.

The ban was also unactionable as written. Logger::print<>() and the
group helpers compile to nothing unless RJ_LOG_GROUPS names the group at
configure time, which defaults to OFF, so routing a fatal diagnostic
through them silences it in every shipped build. Logger::warn() is the
always-on channel and the docs never said so.

State the actual rule -- group helpers for tracing, Logger::warn() for
anything audible by default -- and name the two carve-outs with their
reasons rather than pretending they do not exist.

Also record that the DBT hook and the gfx1250 hotswap hook are mutually
exclusive in HSA_TOOLS_LIB: both patch the same four code-object entries,
nothing enforces load order, and neither exports HSA_AMD_TOOL_PRIORITY.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The runtime config handoff has two consumers with two independently
written readers: the KFD interposer's raw read loop, and the HSA hook's
load_dbt_guest_config_from_runtime_config(). Only the interposer ever
had the fixed 4096-byte read that truncated a handoff whose config path
approaches PATH_MAX, and only the interposer got a regression test for
it -- GuestKfdConfigTest.ReadsRuntimeHandoffLargerThan4095Bytes.

That leaves the actual invariant untested. What matters is not that one
reader survives a long handoff but that both resolve the same host GPU
from it: the two layers picking different physical GPUs on a multi-GPU
host is the failure this series has been closing off, and nothing
compared the two readers' answers. The hook side reads through an
unbounded std::ifstream, so this is coverage rather than a fix -- but
coverage that fails loudly if either reader is ever rewritten.

Add ConfigLoaderTest.ReadsRuntimeHandoffLargerThan4095Bytes, named to
match its KFD counterpart, driving the same >4095-byte handoff through
the hook consumer end to end and asserting the resolved gpu_id.

Hoist the long-path construction into tests/long_path_handoff.h rather
than writing it a second time. The padding arithmetic is delicate --
each component costs a separator plus a character, so a greedy loop can
strand a remainder it cannot spend -- and a divergent copy could quietly
stop being oversized on one side while both tests still passed. Sharing
it also carries the tri-state verdict across, so the new test skips with
a reason on a workspace already too deep for the path instead of going
red for a reason that says nothing about the reader.

Both halves now assert test::kOversizedHandoffHostGpuId, and the helper
self-checks that the payload it built really does exceed 4095 bytes.
On the KFD side the id is proven by bring-up: ensure_ready_locked()
refuses a gpu_id that matches no host-ISA GPU in the topology, so a
visible overlay means the interposer read that exact value. A static
assert pins the constant to the launcher config supplying that topology,
so changing one without the other fails at compile time rather than
turning the overlay check into a tautology.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@amd-arosa
amd-arosa force-pushed the users/arosa/rj/fix-dbt-tests-multigpu branch from 2be8f4c to 150db09 Compare August 3, 2026 23:43
@therock-pr-bot

therock-pr-bot Bot commented Aug 4, 2026

Copy link
Copy Markdown

Pre-commit check failed

⛔ pre-commit failed

Please run locally:

  • python -m pip install pre-commit
  • pre-commit install
  • pre-commit run --all-files --show-diff-on-failure

This repo uses .pre-commit-config.yaml.

@kuhar kuhar left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@amd-arosa
amd-arosa merged commit ba3d97d into develop Aug 4, 2026
22 of 23 checks passed
@amd-arosa
amd-arosa deleted the users/arosa/rj/fix-dbt-tests-multigpu branch August 4, 2026 17:38
kuhar added a commit that referenced this pull request Aug 7, 2026
PR #9213 added physical topology validation while GuestKfd::mutex_ is held. Enumerating the real topology through std::filesystem re-enters the sysfs interposer, which attempts to acquire the same mutex and blocks subsequent /dev/kfd opens.

Enumerate and inspect topology nodes through libc_passthrough so host validation reaches the real sysfs directly. Add a focused lifecycle test covering close followed by reopen.

Tests:
- GuestKfd timeout cluster: 9/9 passed
- GuestKfd tests: 12/12 passed
- Full CTest: 2720 passed, 3 skipped, 2 unrelated failures
kuhar added a commit that referenced this pull request Aug 7, 2026
PR #9213 added physical topology validation while GuestKfd::mutex_ is
held. Enumerating the real topology through std::filesystem re-enters
the sysfs interposer, which attempts to acquire the same mutex and
blocks subsequent /dev/kfd opens.

Enumerate and inspect topology nodes through libc_passthrough so host
validation reaches the real sysfs directly. Add a focused lifecycle test
covering close followed by reopen.

Tests:
- GuestKfd timeout cluster: 9/9 passed
- GuestKfd tests: 12/12 passed
- Full CTest: 2720 passed, 3 skipped, 2 unrelated failures
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix rocjitsu DBT host selection on multi-GPU systems

3 participants