// Copyright (c) 2026 Advanced Micro Devices, Inc. // SPDX-License-Identifier: MIT /// @file rocminfo_test.cpp /// @brief Verifies that rocminfo runs successfully against the simulated GPU /// via the rocjitsu CLI launcher and reports expected topology. #include #include #include #include #include #include #include namespace { struct ProcessResult { std::string output; int exit_code; }; struct TestPaths { std::string rocjitsu_bin = ROCJITSU_BIN; std::string config_path = RJ_CONFIG_PATH; }; std::filesystem::path resolve_relative_to_exe(const std::filesystem::path &exe_dir, const char *path) { std::filesystem::path candidate(path); if (!candidate.is_absolute()) candidate = exe_dir / candidate; return candidate.lexically_normal(); } std::filesystem::path current_exe_dir() { std::error_code ec; std::filesystem::path exe = std::filesystem::read_symlink("/proc/self/exe", ec); if (ec) return {}; return exe.parent_path(); } bool installed_paths_exist(const TestPaths &paths) { return std::filesystem::exists(paths.rocjitsu_bin) && std::filesystem::exists(paths.config_path); } TestPaths installed_paths(const std::filesystem::path &exe_dir) { return { resolve_relative_to_exe(exe_dir, RJ_INSTALLED_ROCJITSU_BIN).string(), resolve_relative_to_exe(exe_dir, RJ_INSTALLED_CONFIG_PATH).string(), }; } const TestPaths &test_paths() { static TestPaths paths = [] { std::filesystem::path exe_dir = current_exe_dir(); if (!exe_dir.empty()) { TestPaths installed = installed_paths(exe_dir); if (installed_paths_exist(installed)) return installed; } return TestPaths{}; }(); return paths; } ProcessResult run_command(const std::string &cmd) { ProcessResult result; std::array buf; std::string full_cmd = cmd + " 2>&1"; FILE *pipe = popen(full_cmd.c_str(), "r"); if (!pipe) { result.exit_code = -1; return result; } while (fgets(buf.data(), buf.size(), pipe) != nullptr) result.output += buf.data(); int status = pclose(pipe); result.exit_code = WIFEXITED(status) ? WEXITSTATUS(status) : -1; return result; } const ProcessResult &rocminfo_output() { const TestPaths &paths = test_paths(); const char *rocminfo_path = std::getenv("ROCMINFO_PATH"); static const ProcessResult result = run_command(paths.rocjitsu_bin + " --config " + paths.config_path + " -- " + (rocminfo_path ? rocminfo_path : ROCMINFO_PATH)); return result; } TEST(RocminfoTest, ExitsSuccessfully) { EXPECT_EQ(rocminfo_output().exit_code, 0) << "rocminfo failed with exit code " << rocminfo_output().exit_code << "\nOutput:\n" << rocminfo_output().output; } TEST(RocminfoTest, InterposerActive) { EXPECT_NE(rocminfo_output().output.find("gfx950"), std::string::npos) << "Interposer does not appear to be active (no gfx950 agent).\nOutput:\n" << rocminfo_output().output; } TEST(RocminfoTest, HsaSystemAttributes) { ASSERT_EQ(rocminfo_output().exit_code, 0) << rocminfo_output().output; EXPECT_NE(rocminfo_output().output.find("HSA System Attributes"), std::string::npos) << "rocminfo did not report HSA System Attributes.\nOutput:\n" << rocminfo_output().output; } TEST(RocminfoTest, DetectsGpuAgent) { ASSERT_EQ(rocminfo_output().exit_code, 0) << rocminfo_output().output; EXPECT_NE(rocminfo_output().output.find("Device Type: GPU"), std::string::npos) << "rocminfo did not detect a GPU agent.\nOutput:\n" << rocminfo_output().output; } TEST(RocminfoTest, ReportsGfx950) { ASSERT_EQ(rocminfo_output().exit_code, 0) << rocminfo_output().output; EXPECT_NE(rocminfo_output().output.find("gfx950"), std::string::npos) << "rocminfo did not report gfx950 target.\nOutput:\n" << rocminfo_output().output; } TEST(RocminfoTest, ReportsWavefrontSize) { ASSERT_EQ(rocminfo_output().exit_code, 0) << rocminfo_output().output; EXPECT_NE(rocminfo_output().output.find("Wavefront Size:"), std::string::npos) << "rocminfo did not report Wavefront Size.\nOutput:\n" << rocminfo_output().output; } } // namespace