CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
1015 lines
39 KiB
C++
1015 lines
39 KiB
C++
// Copyright (c) 2025-2026 Advanced Micro Devices, Inc.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#include "aql_queue.h"
|
|
#include "halt_snapshot_plugin.h"
|
|
#include "scoped_temp.h"
|
|
|
|
#include "embedded_schema.h"
|
|
#include "rocjitsu/config/checkpoint.h"
|
|
#include "rocjitsu/config/config_loader.h"
|
|
#include "rocjitsu/config/dbt_guest_config.h"
|
|
#include "rocjitsu/isa/arch/amdgpu/cdna3/isa.h"
|
|
#include "rocjitsu/isa/arch/amdgpu/shared/accvgpr_layout.h"
|
|
#include "rocjitsu/kmd/linux/amdgpu_properties.h"
|
|
#include "rocjitsu/vm/rj_vm.h"
|
|
#include "rocjitsu/vm/soc.h"
|
|
#include "rocjitsu/vm/virtual_machine.h"
|
|
|
|
#include "simdojo/sim/simulation.h"
|
|
|
|
#include "rocjitsu/base/rj_compiler.h"
|
|
RJ_DIAGNOSTIC_PUSH
|
|
RJ_DIAGNOSTIC_IGNORE_PEDANTIC
|
|
#include "hsa/AMDHSAKernelDescriptor.h"
|
|
RJ_DIAGNOSTIC_POP
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <iterator>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <string_view>
|
|
namespace {
|
|
|
|
const std::string CONFIG_DIR_PATH = CONFIG_DIR;
|
|
|
|
// \NPI new GPU: add a config-load test for its configs/<gpu>.json here.
|
|
using namespace rocjitsu;
|
|
|
|
test::ScopedTempFile write_temp_config(std::string_view json) {
|
|
test::ScopedTempFile file("rocjitsu-config-");
|
|
file.write(json);
|
|
return file;
|
|
}
|
|
|
|
TEST(ConfigLoaderTest, LoadCdna4Config) {
|
|
std::string json = CONFIG_DIR_PATH + "/gfx950_cdna4.json";
|
|
auto loaded = config::load_config(json, rocjitsu::kEmbeddedSchema);
|
|
auto *soc = loaded.soc();
|
|
|
|
// CDNA4 config: 8 XCDs, 4 SEs per XCD, 8 CUs per SE, 2 IODs.
|
|
EXPECT_EQ(soc->num_xcds(), 8u);
|
|
EXPECT_EQ(soc->num_iods(), 2u);
|
|
auto *xcd = soc->xcd(0);
|
|
EXPECT_EQ(xcd->num_shader_engines(), 4u);
|
|
EXPECT_EQ(xcd->shader_engine(0)->num_compute_units(), 8u);
|
|
}
|
|
|
|
TEST(ConfigLoaderTest, LoadRdnaKmdConfigs) {
|
|
auto rdna4 =
|
|
config::load_config(CONFIG_DIR_PATH + "/gfx1201_r9700.json", rocjitsu::kEmbeddedSchema);
|
|
EXPECT_EQ(rdna4.soc()->arch(), ROCJITSU_CODE_ARCH_RDNA4);
|
|
EXPECT_EQ(rdna4.device.gpu_id, 8716u);
|
|
EXPECT_EQ(rdna4.device.device_id, 0x7551u);
|
|
EXPECT_EQ(rdna4.device.family_id, 0x98u);
|
|
EXPECT_EQ(rdna4.device.gfx_target_version, 120001u);
|
|
EXPECT_EQ(rdna4.device.revision_id, 1u);
|
|
EXPECT_EQ(rdna4.device.pci_revision_id, 192u);
|
|
EXPECT_EQ(rdna4.device.simd_count, 128u);
|
|
EXPECT_EQ(rdna4.device.num_shader_engines, 8u);
|
|
EXPECT_EQ(rdna4.device.num_shader_arrays_per_engine, 2u);
|
|
EXPECT_EQ(rdna4.device.num_cu_per_sh, 8u);
|
|
EXPECT_EQ(rdna4.device.simd_per_cu, 2u);
|
|
EXPECT_EQ(rdna4.device.vram_type, kmd::kAmdgpuVramTypeGddr6);
|
|
EXPECT_EQ(rdna4.device.simd_count, rdna4.device.num_shader_engines * rdna4.device.num_cu_per_sh *
|
|
rdna4.device.simd_per_cu);
|
|
EXPECT_EQ(kmd::drm_shader_engine_count(rdna4.device.num_shader_engines,
|
|
rdna4.device.num_shader_arrays_per_engine),
|
|
4u);
|
|
EXPECT_EQ(kmd::drm_cu_active_number(rdna4.device.num_shader_engines, rdna4.device.num_cu_per_sh),
|
|
64u);
|
|
EXPECT_EQ(kmd::external_rev_id_for_gfx_target_version(rdna4.device.gfx_target_version,
|
|
rdna4.device.revision_id),
|
|
0x51u);
|
|
EXPECT_EQ(kmd::gfx_target_name(rdna4.device.gfx_target_version), "gfx1201");
|
|
EXPECT_EQ(kmd::gfx_target_version_from_name("gfx1201"), rdna4.device.gfx_target_version);
|
|
EXPECT_EQ(kmd::gfx_target_name(90010), "gfx90a");
|
|
EXPECT_EQ(kmd::gfx_target_version_from_name("gfx90a"), 90010u);
|
|
EXPECT_FALSE(kmd::gfx_target_version_from_name("cdna4"));
|
|
EXPECT_EQ(kmd::gb_addr_config_for_arch(ROCJITSU_CODE_ARCH_RDNA3_5), 0u);
|
|
EXPECT_EQ(kmd::gb_addr_config_for_gfx_target_version(110500), 0u);
|
|
EXPECT_EQ(kmd::gb_addr_config_for_gfx_target_version(120500), 0u);
|
|
EXPECT_EQ(kmd::drm_shader_engine_count(0, 2), 0u);
|
|
EXPECT_EQ(kmd::drm_shader_engine_count(1, 2), 1u);
|
|
EXPECT_EQ(kmd::drm_shader_engine_count(3, 2), 2u);
|
|
EXPECT_EQ(kmd::drm_shader_engine_count(3, 0), 3u);
|
|
EXPECT_EQ(kmd::num_hw_gfx_contexts_for_gfx_target_version(rdna4.device.gfx_target_version), 8u);
|
|
EXPECT_EQ(rdna4.soc()->num_xcds(), 1u);
|
|
EXPECT_EQ(rdna4.soc()->xcd(0)->num_shader_engines(), 4u);
|
|
EXPECT_EQ(rdna4.soc()->xcd(0)->shader_engine(0)->num_compute_units(), 16u);
|
|
EXPECT_TRUE(rdna4.soc()->xcd(0)->command_processor()->packed_tid());
|
|
EXPECT_EQ(rdna4.soc()->xcd(0)->command_processor()->sdma_packet_dialect(),
|
|
amdgpu::SdmaPacketDialect::Gfx11Plus);
|
|
|
|
auto rdna3 =
|
|
config::load_config(CONFIG_DIR_PATH + "/gfx1100_w7900.json", rocjitsu::kEmbeddedSchema);
|
|
EXPECT_EQ(rdna3.soc()->arch(), ROCJITSU_CODE_ARCH_RDNA3);
|
|
EXPECT_EQ(rdna3.device.gpu_id, 7019u);
|
|
EXPECT_EQ(rdna3.device.device_id, 0x7448u);
|
|
EXPECT_EQ(rdna3.device.family_id, 0x91u);
|
|
EXPECT_EQ(rdna3.device.gfx_target_version, 110000u);
|
|
EXPECT_EQ(rdna3.device.revision_id, 0u);
|
|
EXPECT_EQ(rdna3.device.pci_revision_id, 0u);
|
|
EXPECT_EQ(rdna3.device.simd_count, 192u);
|
|
EXPECT_EQ(rdna3.device.num_shader_engines, 12u);
|
|
EXPECT_EQ(rdna3.device.num_shader_arrays_per_engine, 2u);
|
|
EXPECT_EQ(rdna3.device.num_cu_per_sh, 8u);
|
|
EXPECT_EQ(rdna3.device.simd_per_cu, 2u);
|
|
EXPECT_EQ(rdna3.device.vram_type, kmd::kAmdgpuVramTypeGddr6);
|
|
EXPECT_EQ(rdna3.device.simd_count, rdna3.device.num_shader_engines * rdna3.device.num_cu_per_sh *
|
|
rdna3.device.simd_per_cu);
|
|
EXPECT_EQ(kmd::drm_shader_engine_count(rdna3.device.num_shader_engines,
|
|
rdna3.device.num_shader_arrays_per_engine),
|
|
6u);
|
|
EXPECT_EQ(kmd::drm_cu_active_number(rdna3.device.num_shader_engines, rdna3.device.num_cu_per_sh),
|
|
96u);
|
|
EXPECT_EQ(kmd::external_rev_id_for_gfx_target_version(rdna3.device.gfx_target_version,
|
|
rdna3.device.revision_id),
|
|
0x1u);
|
|
EXPECT_EQ(kmd::gfx_target_name(rdna3.device.gfx_target_version), "gfx1100");
|
|
EXPECT_EQ(kmd::num_hw_gfx_contexts_for_gfx_target_version(rdna3.device.gfx_target_version), 8u);
|
|
EXPECT_EQ(rdna3.soc()->num_xcds(), 1u);
|
|
EXPECT_EQ(rdna3.soc()->xcd(0)->num_shader_engines(), 6u);
|
|
EXPECT_EQ(rdna3.soc()->xcd(0)->shader_engine(0)->num_compute_units(), 16u);
|
|
EXPECT_TRUE(rdna3.soc()->xcd(0)->command_processor()->packed_tid());
|
|
EXPECT_EQ(rdna3.soc()->xcd(0)->command_processor()->sdma_packet_dialect(),
|
|
amdgpu::SdmaPacketDialect::Gfx11Plus);
|
|
|
|
auto rdna35 = config::load_config(CONFIG_DIR_PATH + "/gfx1151.json", rocjitsu::kEmbeddedSchema);
|
|
EXPECT_EQ(rdna35.soc()->arch(), ROCJITSU_CODE_ARCH_RDNA3_5);
|
|
EXPECT_EQ(rdna35.device.gpu_id, 5510u);
|
|
EXPECT_EQ(rdna35.device.device_id, 0x1586u);
|
|
EXPECT_EQ(rdna35.device.family_id, 0x91u);
|
|
EXPECT_EQ(rdna35.device.gfx_target_version, 110501u);
|
|
EXPECT_EQ(rdna35.device.revision_id, 0u);
|
|
EXPECT_EQ(rdna35.device.pci_revision_id, 0u);
|
|
EXPECT_EQ(rdna35.device.simd_count, 64u);
|
|
EXPECT_EQ(rdna35.device.num_shader_engines, 4u);
|
|
EXPECT_EQ(rdna35.device.num_shader_arrays_per_engine, 2u);
|
|
EXPECT_EQ(rdna35.device.num_cu_per_sh, 8u);
|
|
EXPECT_EQ(rdna35.device.simd_per_cu, 2u);
|
|
EXPECT_EQ(rdna35.device.vram_type, kmd::kAmdgpuVramTypeGddr6);
|
|
EXPECT_EQ(rdna35.device.simd_count, rdna35.device.num_shader_engines *
|
|
rdna35.device.num_cu_per_sh * rdna35.device.simd_per_cu);
|
|
EXPECT_EQ(kmd::drm_shader_engine_count(rdna35.device.num_shader_engines,
|
|
rdna35.device.num_shader_arrays_per_engine),
|
|
2u);
|
|
EXPECT_EQ(
|
|
kmd::drm_cu_active_number(rdna35.device.num_shader_engines, rdna35.device.num_cu_per_sh),
|
|
32u);
|
|
EXPECT_EQ(kmd::external_rev_id_for_gfx_target_version(rdna35.device.gfx_target_version,
|
|
rdna35.device.revision_id),
|
|
0xc1u);
|
|
EXPECT_EQ(kmd::gfx_target_name(rdna35.device.gfx_target_version), "gfx1151");
|
|
EXPECT_EQ(kmd::num_hw_gfx_contexts_for_gfx_target_version(rdna35.device.gfx_target_version), 8u);
|
|
EXPECT_EQ(rdna35.soc()->num_xcds(), 1u);
|
|
EXPECT_EQ(rdna35.soc()->xcd(0)->num_shader_engines(), 2u);
|
|
EXPECT_EQ(rdna35.soc()->xcd(0)->shader_engine(0)->num_compute_units(), 16u);
|
|
EXPECT_TRUE(rdna35.soc()->xcd(0)->command_processor()->packed_tid());
|
|
EXPECT_EQ(rdna35.soc()->xcd(0)->command_processor()->sdma_packet_dialect(),
|
|
amdgpu::SdmaPacketDialect::Gfx11Plus);
|
|
}
|
|
|
|
TEST(ConfigLoaderTest, BuildFromJsonString) {
|
|
const char *json = R"({
|
|
"max_ticks": 5000,
|
|
"num_threads": 1,
|
|
"vm": { "arch": "cdna3" },
|
|
"topology": {
|
|
"root": {
|
|
"name": "soc", "type": "soc",
|
|
"children": [
|
|
{ "name": "vram", "type": "gpu_memory" },
|
|
{
|
|
"name": "xcd0", "type": "xcd",
|
|
"children": [
|
|
{ "name": "l2", "type": "l2_cache" },
|
|
{ "name": "cp", "type": "command_processor" },
|
|
{
|
|
"name": "se0", "type": "shader_engine",
|
|
"children": [{
|
|
"name": "cu[0:3]", "type": "compute_unit",
|
|
"config": [
|
|
{ "key": "num_wf_slots", "value": "20" },
|
|
{ "key": "sgprs_per_wf", "value": "104" },
|
|
{ "key": "vgprs_per_wf", "value": "256" },
|
|
{ "key": "lds_size_kb", "value": "64" }
|
|
]
|
|
}]
|
|
},
|
|
{
|
|
"name": "se1", "type": "shader_engine",
|
|
"children": [{
|
|
"name": "cu[0:3]", "type": "compute_unit",
|
|
"config": [
|
|
{ "key": "num_wf_slots", "value": "20" },
|
|
{ "key": "sgprs_per_wf", "value": "104" },
|
|
{ "key": "vgprs_per_wf", "value": "256" },
|
|
{ "key": "lds_size_kb", "value": "64" }
|
|
]
|
|
}]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"links": [
|
|
{ "src": "xcd0.cp.req_0", "dst": "xcd0.se0.cu0.cpl", "latency": 1, "weight": 2 },
|
|
{ "src": "xcd0.cp.req_1", "dst": "xcd0.se0.cu1.cpl", "latency": 1, "weight": 2 },
|
|
{ "src": "xcd0.cp.req_2", "dst": "xcd0.se0.cu2.cpl", "latency": 1, "weight": 2 },
|
|
{ "src": "xcd0.cp.req_3", "dst": "xcd0.se1.cu0.cpl", "latency": 1, "weight": 2 },
|
|
{ "src": "xcd0.cp.req_4", "dst": "xcd0.se1.cu1.cpl", "latency": 1, "weight": 2 },
|
|
{ "src": "xcd0.cp.req_5", "dst": "xcd0.se1.cu2.cpl", "latency": 1, "weight": 2 },
|
|
{ "src": "xcd0.se0.cu0.req", "dst": "xcd0.l2.cpl_0", "latency": 1, "weight": 10 },
|
|
{ "src": "xcd0.se0.cu1.req", "dst": "xcd0.l2.cpl_1", "latency": 1, "weight": 10 },
|
|
{ "src": "xcd0.se0.cu2.req", "dst": "xcd0.l2.cpl_2", "latency": 1, "weight": 10 },
|
|
{ "src": "xcd0.se1.cu0.req", "dst": "xcd0.l2.cpl_3", "latency": 1, "weight": 10 },
|
|
{ "src": "xcd0.se1.cu1.req", "dst": "xcd0.l2.cpl_4", "latency": 1, "weight": 10 },
|
|
{ "src": "xcd0.se1.cu2.req", "dst": "xcd0.l2.cpl_5", "latency": 1, "weight": 10 }
|
|
]
|
|
}
|
|
})";
|
|
|
|
auto loaded = config::load_config_from_string(json, rocjitsu::kEmbeddedSchema);
|
|
auto *soc = loaded.soc();
|
|
|
|
// 1 XCD, 2 SEs, each with 3 CUs.
|
|
auto *xcd = soc->xcd(0);
|
|
EXPECT_EQ(xcd->num_shader_engines(), 2u);
|
|
EXPECT_EQ(xcd->shader_engine(0)->num_compute_units(), 3u);
|
|
EXPECT_EQ(xcd->shader_engine(1)->num_compute_units(), 3u);
|
|
}
|
|
|
|
TEST(ConfigLoaderTest, DeviceCapabilityFieldsDefaultToAutoCompute) {
|
|
const char *json = R"({
|
|
"max_ticks": 5000,
|
|
"num_threads": 1,
|
|
"vm": {
|
|
"arch": "cdna3",
|
|
"gpu": { "device": { "gfx_target_version": 90500 } }
|
|
},
|
|
"topology": {
|
|
"root": {
|
|
"name": "soc", "type": "soc",
|
|
"children": [
|
|
{ "name": "vram", "type": "gpu_memory" },
|
|
{
|
|
"name": "xcd0", "type": "xcd",
|
|
"children": [
|
|
{ "name": "l2", "type": "l2_cache" },
|
|
{ "name": "cp", "type": "command_processor" },
|
|
{ "name": "se0", "type": "shader_engine",
|
|
"children": [{ "name": "cu0", "type": "compute_unit" }] }
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"links": []
|
|
}
|
|
})";
|
|
|
|
auto loaded = config::load_config_from_string(json, rocjitsu::kEmbeddedSchema);
|
|
|
|
// Not specified in JSON: 0 means "auto-compute" (see
|
|
// rocjitsu::default_non_debug_capability()/debug_topology_for()).
|
|
EXPECT_EQ(loaded.device.capability, 0u);
|
|
EXPECT_EQ(loaded.device.capability2, 0u);
|
|
EXPECT_EQ(loaded.device.debug_prop, 0u);
|
|
}
|
|
|
|
TEST(ConfigLoaderTest, DeviceCapabilityFieldsRoundTripFromJson) {
|
|
const char *json = R"({
|
|
"max_ticks": 5000,
|
|
"num_threads": 1,
|
|
"vm": {
|
|
"arch": "cdna3",
|
|
"gpu": { "device": {
|
|
"gfx_target_version": 90500,
|
|
"capability": 268468354,
|
|
"capability2": 3,
|
|
"debug_prop": 3119
|
|
} }
|
|
},
|
|
"topology": {
|
|
"root": {
|
|
"name": "soc", "type": "soc",
|
|
"children": [
|
|
{ "name": "vram", "type": "gpu_memory" },
|
|
{
|
|
"name": "xcd0", "type": "xcd",
|
|
"children": [
|
|
{ "name": "l2", "type": "l2_cache" },
|
|
{ "name": "cp", "type": "command_processor" },
|
|
{ "name": "se0", "type": "shader_engine",
|
|
"children": [{ "name": "cu0", "type": "compute_unit" }] }
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"links": []
|
|
}
|
|
})";
|
|
|
|
auto loaded = config::load_config_from_string(json, rocjitsu::kEmbeddedSchema);
|
|
|
|
EXPECT_EQ(loaded.device.capability, 268468354u);
|
|
EXPECT_EQ(loaded.device.capability2, 3u);
|
|
EXPECT_EQ(loaded.device.debug_prop, 3119u);
|
|
}
|
|
|
|
TEST(ConfigLoaderTest, LoadsDbtOnlyConfigWithoutVmOrTopology) {
|
|
const auto file = write_temp_config(R"({
|
|
"dbt_guest": {
|
|
"enabled": true,
|
|
"guest_isa": "gfx950",
|
|
"host_isa": "gfx1201",
|
|
"host_gpu_id": 8716,
|
|
"log_level": 2,
|
|
"signal_backtrace": true,
|
|
"guest_device": {
|
|
"gpu_id": 38144,
|
|
"gfx_target_version": 90500,
|
|
"vendor_id": 4098,
|
|
"device_id": 30112,
|
|
"family_id": 160,
|
|
"unique_id": 5929628898254127105,
|
|
"marketing_name": "AMD Instinct MI350X",
|
|
"drm_render_minor": 191,
|
|
"simd_count": 64,
|
|
"num_shader_engines": 4,
|
|
"num_shader_arrays_per_engine": 2,
|
|
"num_cu_per_sh": 4,
|
|
"local_mem_size": 309237645312
|
|
}
|
|
}
|
|
})");
|
|
|
|
auto dbt = config::load_dbt_guest_config_from_file(file.path());
|
|
|
|
EXPECT_TRUE(dbt.enabled);
|
|
EXPECT_EQ(dbt.guest_isa, "gfx950");
|
|
EXPECT_EQ(dbt.host.isa, "gfx1201");
|
|
EXPECT_EQ(dbt.host.gpu_id, 8716u);
|
|
EXPECT_EQ(dbt.host.backend, config::DbtExecutionBackend::Hardware);
|
|
EXPECT_EQ(dbt.log_level, 2);
|
|
EXPECT_TRUE(dbt.signal_backtrace);
|
|
ASSERT_TRUE(dbt.guest_device.present);
|
|
EXPECT_EQ(dbt.guest_device.gpu_id, 38144u);
|
|
EXPECT_EQ(dbt.guest_device.gfx_target_version, 90500u);
|
|
EXPECT_EQ(dbt.guest_device.marketing_name, "AMD Instinct MI350X");
|
|
EXPECT_EQ(dbt.guest_device.drm_render_minor, 191u);
|
|
EXPECT_EQ(dbt.guest_device.simd_count, dbt.guest_device.num_shader_engines *
|
|
dbt.guest_device.num_cu_per_sh *
|
|
dbt.guest_device.simd_per_cu);
|
|
EXPECT_EQ(dbt.guest_device.num_shader_arrays_per_engine, 2u);
|
|
EXPECT_EQ(dbt.guest_device.local_mem_size, 309237645312ULL);
|
|
// Revisions default to Unspecified when the config omits them.
|
|
EXPECT_EQ(dbt.guest_revision, config::DbtSiliconRevision::Unspecified);
|
|
EXPECT_EQ(dbt.host_revision, config::DbtSiliconRevision::Unspecified);
|
|
}
|
|
|
|
TEST(ConfigLoaderTest, LoadsDbtGuestSiliconRevisions) {
|
|
// gfx1250 A0 and B0 share an ELF machine ID, so the configured revisions
|
|
// select the B0-to-A0 translation profile.
|
|
const auto file = write_temp_config(R"({
|
|
"dbt_guest": {
|
|
"enabled": true,
|
|
"guest_isa": "gfx1250",
|
|
"host_isa": "gfx1250",
|
|
"guest_revision": "gfx1250_b0",
|
|
"host_revision": "gfx1250_a0"
|
|
}
|
|
})");
|
|
|
|
auto dbt = config::load_dbt_guest_config_from_file(file.path());
|
|
|
|
EXPECT_EQ(dbt.guest_revision, config::DbtSiliconRevision::Gfx1250B0);
|
|
EXPECT_EQ(dbt.host_revision, config::DbtSiliconRevision::Gfx1250A0);
|
|
}
|
|
|
|
TEST(ConfigLoaderTest, RejectsDbtGuestDeviceWithInconsistentSimdCount) {
|
|
const auto file = write_temp_config(R"({
|
|
"dbt_guest": {
|
|
"enabled": true,
|
|
"guest_isa": "gfx950",
|
|
"host_isa": "gfx1201",
|
|
"guest_device": {
|
|
"gpu_id": 38144,
|
|
"gfx_target_version": 90500,
|
|
"simd_count": 1024,
|
|
"num_shader_engines": 4,
|
|
"num_cu_per_sh": 4,
|
|
"simd_per_cu": 4
|
|
}
|
|
}
|
|
})");
|
|
|
|
EXPECT_THROW(config::load_dbt_guest_config_from_file(file.path()), std::runtime_error);
|
|
}
|
|
|
|
TEST(ConfigLoaderTest, LoadsDbtGuestThroughFullConfigLoader) {
|
|
std::ifstream base(CONFIG_DIR_PATH + "/gfx1201_r9700.json");
|
|
ASSERT_TRUE(base.is_open());
|
|
std::string json((std::istreambuf_iterator<char>(base)), std::istreambuf_iterator<char>());
|
|
const size_t insert_pos = json.find('{');
|
|
ASSERT_NE(insert_pos, std::string::npos);
|
|
json.insert(insert_pos + 1, R"(
|
|
"dbt_guest": {
|
|
"enabled": true,
|
|
"guest_isa": "gfx950",
|
|
"host_isa": "gfx1201",
|
|
"host_gpu_id": 8716,
|
|
"log_level": 2,
|
|
"signal_backtrace": true,
|
|
"guest_device": {
|
|
"gpu_id": 38144,
|
|
"gfx_target_version": 90500,
|
|
"vendor_id": 4098,
|
|
"device_id": 30112,
|
|
"family_id": 160,
|
|
"unique_id": 5929628898254127105,
|
|
"marketing_name": "AMD Instinct MI350X",
|
|
"drm_render_minor": 191,
|
|
"simd_count": 64,
|
|
"num_shader_engines": 4,
|
|
"num_shader_arrays_per_engine": 2,
|
|
"num_cu_per_sh": 4,
|
|
"local_mem_size": 309237645312
|
|
}
|
|
},
|
|
)");
|
|
|
|
const auto file = write_temp_config(json);
|
|
auto loaded = config::load_config(file.path(), rocjitsu::kEmbeddedSchema);
|
|
|
|
EXPECT_TRUE(loaded.dbt_guest.enabled);
|
|
EXPECT_EQ(loaded.dbt_guest.guest_isa, "gfx950");
|
|
EXPECT_EQ(loaded.dbt_guest.host.isa, "gfx1201");
|
|
EXPECT_EQ(loaded.dbt_guest.host.gpu_id, 8716u);
|
|
EXPECT_EQ(loaded.dbt_guest.host.backend, config::DbtExecutionBackend::Hardware);
|
|
EXPECT_EQ(loaded.dbt_guest.log_level, 2);
|
|
EXPECT_TRUE(loaded.dbt_guest.signal_backtrace);
|
|
ASSERT_TRUE(loaded.dbt_guest.guest_device.present);
|
|
EXPECT_EQ(loaded.dbt_guest.guest_device.gpu_id, 38144u);
|
|
EXPECT_EQ(loaded.dbt_guest.guest_device.gfx_target_version, 90500u);
|
|
EXPECT_EQ(loaded.dbt_guest.guest_device.marketing_name, "AMD Instinct MI350X");
|
|
}
|
|
|
|
TEST(ConfigLoaderTest, MissingDbtGuestConfigReturnsDefaults) {
|
|
const auto file = write_temp_config("{}");
|
|
|
|
auto dbt = config::load_dbt_guest_config_from_file(file.path());
|
|
|
|
EXPECT_FALSE(dbt.enabled);
|
|
EXPECT_TRUE(dbt.guest_isa.empty());
|
|
EXPECT_TRUE(dbt.host.isa.empty());
|
|
EXPECT_EQ(dbt.host.gpu_id, 0u);
|
|
EXPECT_EQ(dbt.host.backend, config::DbtExecutionBackend::Hardware);
|
|
EXPECT_EQ(dbt.log_level, 0);
|
|
EXPECT_FALSE(dbt.signal_backtrace);
|
|
EXPECT_FALSE(dbt.guest_device.present);
|
|
}
|
|
|
|
TEST(ConfigLoaderTest, MissingDbtGuestDeviceLeavesDeviceAbsent) {
|
|
const auto file = write_temp_config(R"({
|
|
"dbt_guest": {
|
|
"enabled": true,
|
|
"guest_isa": "gfx950",
|
|
"host_isa": "gfx1201"
|
|
}
|
|
})");
|
|
|
|
auto dbt = config::load_dbt_guest_config_from_file(file.path());
|
|
|
|
EXPECT_TRUE(dbt.enabled);
|
|
EXPECT_EQ(dbt.guest_isa, "gfx950");
|
|
EXPECT_EQ(dbt.host.isa, "gfx1201");
|
|
EXPECT_FALSE(dbt.guest_device.present);
|
|
}
|
|
|
|
TEST(ConfigLoaderTest, MalformedDbtGuestConfigThrows) {
|
|
const auto file = write_temp_config(R"({ "dbt_guest": )");
|
|
|
|
EXPECT_THROW(config::load_dbt_guest_config_from_file(file.path()), std::runtime_error);
|
|
}
|
|
|
|
TEST(ConfigLoaderTest, LoadsSimulatorDbtBackendConfig) {
|
|
const auto external_file = write_temp_config(R"({
|
|
"dbt_guest": {
|
|
"enabled": true,
|
|
"guest_isa": "gfx950",
|
|
"host_isa": "gfx942",
|
|
"execution_backend": "simulator",
|
|
"simulator_config": "gfx942_cdna3_kmd.json"
|
|
}
|
|
})");
|
|
const auto self_contained_file = write_temp_config(R"({
|
|
"dbt_guest": {
|
|
"enabled": true,
|
|
"guest_isa": "gfx950",
|
|
"host_isa": "gfx942",
|
|
"execution_backend": "simulator"
|
|
}
|
|
})");
|
|
|
|
auto external = config::load_dbt_guest_config_from_file(external_file.path());
|
|
auto self_contained = config::load_dbt_guest_config_from_file(self_contained_file.path());
|
|
|
|
EXPECT_EQ(external.host.isa, "gfx942");
|
|
EXPECT_EQ(external.host.backend, config::DbtExecutionBackend::Simulator);
|
|
EXPECT_EQ(external.host.simulator_config_path, "gfx942_cdna3_kmd.json");
|
|
EXPECT_EQ(self_contained.host.backend, config::DbtExecutionBackend::Simulator);
|
|
EXPECT_TRUE(self_contained.host.simulator_config_path.empty());
|
|
}
|
|
|
|
TEST(ConfigLoaderTest, LoadsExplicitHardwareDbtBackendConfig) {
|
|
const auto file = write_temp_config(R"({
|
|
"dbt_guest": {
|
|
"enabled": true,
|
|
"execution_backend": "hardware"
|
|
}
|
|
})");
|
|
|
|
auto dbt = config::load_dbt_guest_config_from_file(file.path());
|
|
|
|
EXPECT_EQ(dbt.host.backend, config::DbtExecutionBackend::Hardware);
|
|
}
|
|
|
|
TEST(ConfigLoaderTest, RejectsEmptyDbtExecutionBackend) {
|
|
const auto file = write_temp_config(R"({
|
|
"dbt_guest": {
|
|
"enabled": true,
|
|
"execution_backend": ""
|
|
}
|
|
})");
|
|
|
|
EXPECT_THROW(config::load_dbt_guest_config_from_file(file.path()), std::runtime_error);
|
|
}
|
|
|
|
TEST(ConfigLoaderTest, RejectsMisspelledDbtExecutionBackend) {
|
|
const auto file = write_temp_config(R"({
|
|
"dbt_guest": {
|
|
"enabled": true,
|
|
"execution_backed": "simulator"
|
|
}
|
|
})");
|
|
|
|
EXPECT_THROW(config::load_dbt_guest_config_from_file(file.path()), std::runtime_error);
|
|
}
|
|
|
|
TEST(ConfigLoaderTest, ValidatesSimulatorDbtGuestDeviceLimits) {
|
|
config::DbtGuestConfig guest;
|
|
guest.enabled = true;
|
|
guest.host.backend = config::DbtExecutionBackend::Simulator;
|
|
guest.guest_device.present = true;
|
|
guest.guest_device.lds_size_kb = 64;
|
|
guest.guest_device.max_slots_scratch_cu = 32;
|
|
guest.guest_device.max_waves_per_simd = 8;
|
|
guest.guest_device.wave_front_size = 64;
|
|
|
|
config::KfdDeviceConfig simulator;
|
|
simulator.present = true;
|
|
simulator.lds_size_kb = 64;
|
|
simulator.max_slots_scratch_cu = 32;
|
|
simulator.max_waves_per_simd = 8;
|
|
simulator.wave_front_size = 64;
|
|
|
|
EXPECT_NO_THROW(config::validate_dbt_simulator_device_limits(guest, simulator));
|
|
guest.guest_device.lds_size_kb = 65;
|
|
EXPECT_THROW(config::validate_dbt_simulator_device_limits(guest, simulator), std::runtime_error);
|
|
guest.guest_device.lds_size_kb = 64;
|
|
guest.guest_device.max_slots_scratch_cu = 33;
|
|
EXPECT_THROW(config::validate_dbt_simulator_device_limits(guest, simulator), std::runtime_error);
|
|
}
|
|
|
|
TEST(ConfigLoaderTest, DisabledDbtBackendSkipsBackendSpecificValidation) {
|
|
const auto simulator_file = write_temp_config(R"({
|
|
"dbt_guest": {
|
|
"enabled": false,
|
|
"execution_backend": "simulator"
|
|
}
|
|
})");
|
|
const auto hardware_file = write_temp_config(R"({
|
|
"dbt_guest": {
|
|
"enabled": false,
|
|
"execution_backend": "hardware",
|
|
"simulator_config": "ignored.json"
|
|
}
|
|
})");
|
|
|
|
EXPECT_NO_THROW(config::load_dbt_guest_config_from_file(simulator_file.path()));
|
|
EXPECT_NO_THROW(config::load_dbt_guest_config_from_file(hardware_file.path()));
|
|
}
|
|
|
|
TEST(ConfigLoaderTest, ResolvesDbtHostConfigPath) {
|
|
EXPECT_EQ(config::resolve_dbt_host_config_path("/a/b/dbt.json", ""), "/a/b/dbt.json");
|
|
EXPECT_EQ(config::resolve_dbt_host_config_path("/a/b/dbt.json", "sim.json"), "/a/b/sim.json");
|
|
EXPECT_EQ(config::resolve_dbt_host_config_path("/a/b/dbt.json", "/abs/sim.json"),
|
|
"/abs/sim.json");
|
|
EXPECT_EQ(config::resolve_dbt_host_config_path("/a/b/dbt.json", "../c/./sim.json"),
|
|
"/a/c/sim.json");
|
|
}
|
|
|
|
TEST(ConfigLoaderTest, RejectsUnknownDbtExecutionBackend) {
|
|
const auto file = write_temp_config(R"({
|
|
"dbt_guest": {
|
|
"enabled": true,
|
|
"execution_backend": "magic"
|
|
}
|
|
})");
|
|
|
|
EXPECT_THROW(config::load_dbt_guest_config_from_file(file.path()), std::runtime_error);
|
|
}
|
|
|
|
TEST(ConfigLoaderTest, RejectsSimulatorConfigForHardwareDbtBackend) {
|
|
const auto file = write_temp_config(R"({
|
|
"dbt_guest": {
|
|
"enabled": true,
|
|
"execution_backend": "hardware",
|
|
"simulator_config": "gfx942_cdna3_kmd.json"
|
|
}
|
|
})");
|
|
|
|
EXPECT_THROW(config::load_dbt_guest_config_from_file(file.path()), std::runtime_error);
|
|
}
|
|
|
|
TEST(ConfigLoaderTest, Gfx1250ComputeUnitDefaultsCoverTtmpAndHighVgprs) {
|
|
const char *json = R"({"max_ticks":1000,"num_threads":1,
|
|
"vm":{"arch":"gfx1250"},
|
|
"topology":{"root":{"name":"soc","type":"soc","children":[
|
|
{"name":"vram","type":"gpu_memory"},
|
|
{"name":"xcd0","type":"xcd","children":[
|
|
{"name":"l2","type":"l2_cache"},
|
|
{"name":"cp","type":"command_processor"},
|
|
{"name":"se0","type":"shader_engine","children":[
|
|
{"name":"cu[0:1]","type":"compute_unit","config":[
|
|
{"key":"num_wf_slots","value":"1"},
|
|
{"key":"lds_size_kb","value":"64"}
|
|
]}
|
|
]}
|
|
]}
|
|
]},"links":[
|
|
{"src":"xcd0.cp.req_0","dst":"xcd0.se0.cu0.cpl","latency":1,"weight":2},
|
|
{"src":"xcd0.se0.cu0.req","dst":"xcd0.l2.cpl_0","latency":1,"weight":10}
|
|
]}})";
|
|
|
|
auto loaded = config::load_config_from_string(json, rocjitsu::kEmbeddedSchema);
|
|
auto *cu = loaded.soc()->xcd(0)->shader_engine(0)->compute_unit(0);
|
|
ASSERT_NE(cu, nullptr);
|
|
EXPECT_EQ(cu->config().sgprs_per_wf, 128u);
|
|
EXPECT_EQ(cu->config().vgprs_per_wf, 1024u);
|
|
}
|
|
|
|
TEST(ConfigLoaderTest, DispatchDistributesAcrossCUs) {
|
|
const char *json = R"({"max_ticks":10000,"num_threads":1,
|
|
"vm":{"arch":"cdna3"},
|
|
"topology":{
|
|
"root":{
|
|
"name":"soc","type":"soc",
|
|
"children":[
|
|
{"name":"vram","type":"gpu_memory"},
|
|
{"name":"xcd0","type":"xcd","children":[
|
|
{"name":"l2","type":"l2_cache"},
|
|
{"name":"cp","type":"command_processor"},
|
|
{"name":"se0","type":"shader_engine","children":[
|
|
{"name":"cu[0:2]","type":"compute_unit","config":[
|
|
{"key":"num_wf_slots","value":"10"},
|
|
{"key":"sgprs_per_wf","value":"104"},
|
|
{"key":"vgprs_per_wf","value":"256"},
|
|
{"key":"lds_size_kb","value":"64"}
|
|
]}
|
|
]}
|
|
]}
|
|
]
|
|
},
|
|
"links":[
|
|
{"src":"xcd0.cp.req_0","dst":"xcd0.se0.cu0.cpl","latency":1,"weight":2},
|
|
{"src":"xcd0.cp.req_1","dst":"xcd0.se0.cu1.cpl","latency":1,"weight":2},
|
|
{"src":"xcd0.se0.cu0.req","dst":"xcd0.l2.cpl_0","latency":1,"weight":10},
|
|
{"src":"xcd0.se0.cu1.req","dst":"xcd0.l2.cpl_1","latency":1,"weight":10}
|
|
]
|
|
}
|
|
})";
|
|
|
|
auto loaded = config::load_config_from_string(json, rocjitsu::kEmbeddedSchema);
|
|
auto *soc = loaded.soc();
|
|
|
|
simdojo::SimulationEngine engine(loaded.engine_config);
|
|
engine.topology().set_root(loaded.take_root());
|
|
loaded.wire_links(engine.topology());
|
|
engine.create();
|
|
|
|
rocjitsu::test::DispatchCountPlugin *dispatch_count = nullptr;
|
|
auto plugin_group = rocjitsu::test::make_dispatch_count_group(&dispatch_count);
|
|
soc->set_plugin_group(plugin_group);
|
|
|
|
// Write a kernel descriptor + invalid instruction so wavefronts halt immediately.
|
|
using namespace rocr::llvm::amdhsa;
|
|
kernel_descriptor_t kd{};
|
|
kd.kernel_code_entry_byte_offset = sizeof(kernel_descriptor_t);
|
|
// CDNA3 (GFX940+) uses VGPR granularity 8 (not 4).
|
|
AMDHSA_BITS_SET(kd.compute_pgm_rsrc1, COMPUTE_PGM_RSRC1_GRANULATED_WORKITEM_VGPR_COUNT,
|
|
((256 / 8) - 1));
|
|
AMDHSA_BITS_SET(kd.compute_pgm_rsrc1, COMPUTE_PGM_RSRC1_GRANULATED_WAVEFRONT_SGPR_COUNT,
|
|
((104 / 8) - 1));
|
|
AMDHSA_BITS_SET(kd.compute_pgm_rsrc2, COMPUTE_PGM_RSRC2_USER_SGPR_COUNT, 2);
|
|
|
|
constexpr uint64_t KD_ADDR = 0x1000;
|
|
soc->memory()->load_image(reinterpret_cast<const uint8_t *>(&kd), sizeof(kd), KD_ADDR);
|
|
soc->memory()->write32(KD_ADDR + sizeof(kernel_descriptor_t), 0xFFFFFFFF); // invalid instruction
|
|
|
|
auto *xcd = soc->xcd(0);
|
|
test::AqlQueue queue(soc->memory(), xcd->command_processor());
|
|
queue.dispatch(KD_ADDR, 128, 64); // grid_size=128 = 2 workgroups of 64
|
|
|
|
engine.step();
|
|
|
|
// After one step, the doorbell event dispatched wavefronts to CUs. Count them
|
|
// via the dispatch hook (fired at placement) so the check is independent of when
|
|
// waves execute and free themselves. Verify round-robin distribution.
|
|
EXPECT_EQ(xcd->command_processor()->dispatched_count(), 1u);
|
|
auto *se = soc->xcd(0)->shader_engine(0);
|
|
EXPECT_EQ(dispatch_count->for_cu(se->compute_unit(0)), 1u);
|
|
EXPECT_EQ(dispatch_count->for_cu(se->compute_unit(1)), 1u);
|
|
}
|
|
|
|
TEST(CheckpointTest, SaveAndRestoreMemory) {
|
|
const char *json = R"({"max_ticks":10000,"num_threads":1,
|
|
"vm":{"arch":"cdna3"},
|
|
"topology":{
|
|
"root":{
|
|
"name":"soc","type":"soc",
|
|
"children":[
|
|
{"name":"vram","type":"gpu_memory"},
|
|
{"name":"xcd0","type":"xcd","children":[
|
|
{"name":"l2","type":"l2_cache"},
|
|
{"name":"cp","type":"command_processor"},
|
|
{"name":"se0","type":"shader_engine","children":[
|
|
{"name":"cu[0:1]","type":"compute_unit","config":[
|
|
{"key":"num_wf_slots","value":"10"},
|
|
{"key":"sgprs_per_wf","value":"104"},
|
|
{"key":"vgprs_per_wf","value":"256"},
|
|
{"key":"lds_size_kb","value":"64"}
|
|
]}
|
|
]}
|
|
]}
|
|
]
|
|
},
|
|
"links":[
|
|
{"src":"xcd0.cp.req_0","dst":"xcd0.se0.cu0.cpl","latency":1,"weight":2},
|
|
{"src":"xcd0.se0.cu0.req","dst":"xcd0.l2.cpl_0","latency":1,"weight":10}
|
|
]
|
|
}
|
|
})";
|
|
|
|
auto loaded = config::load_config_from_string(json, rocjitsu::kEmbeddedSchema);
|
|
auto *soc = loaded.soc();
|
|
|
|
soc->memory()->write32(0x1000, 0xDEADBEEF);
|
|
soc->memory()->write64(0x2000, 0x0123456789ABCDEFULL);
|
|
|
|
test::ScopedTempFile checkpoint("rocjitsu-checkpoint-");
|
|
config::save_checkpoint(checkpoint.path(), *soc, 42, loaded.engine_config);
|
|
ASSERT_TRUE(std::filesystem::exists(checkpoint.path()));
|
|
|
|
auto restored = config::restore_checkpoint(checkpoint.path());
|
|
EXPECT_EQ(restored.memory()->read32(0x1000), 0xDEADBEEFu);
|
|
EXPECT_EQ(restored.memory()->read64(0x2000), 0x0123456789ABCDEFULL);
|
|
}
|
|
|
|
TEST(CheckpointTest, SaveAndRestoreAccVgprs) {
|
|
const char *json = R"({"max_ticks":10000,"num_threads":1,
|
|
"vm":{"arch":"cdna3"},
|
|
"topology":{
|
|
"root":{
|
|
"name":"soc","type":"soc",
|
|
"children":[
|
|
{"name":"vram","type":"gpu_memory"},
|
|
{"name":"xcd0","type":"xcd","children":[
|
|
{"name":"l2","type":"l2_cache"},
|
|
{"name":"cp","type":"command_processor"},
|
|
{"name":"se0","type":"shader_engine","children":[
|
|
{"name":"cu[0:1]","type":"compute_unit","config":[
|
|
{"key":"num_wf_slots","value":"1"},
|
|
{"key":"sgprs_per_wf","value":"104"},
|
|
{"key":"vgprs_per_wf","value":"256"},
|
|
{"key":"lds_size_kb","value":"64"}
|
|
]}
|
|
]}
|
|
]}
|
|
]
|
|
},
|
|
"links":[
|
|
{"src":"xcd0.cp.req_0","dst":"xcd0.se0.cu0.cpl","latency":1,"weight":2},
|
|
{"src":"xcd0.se0.cu0.req","dst":"xcd0.l2.cpl_0","latency":1,"weight":10}
|
|
]
|
|
}
|
|
})";
|
|
|
|
auto loaded = config::load_config_from_string(json, rocjitsu::kEmbeddedSchema);
|
|
auto *cu = loaded.soc()->xcd(0)->shader_engine(0)->compute_unit(0);
|
|
ASSERT_NE(cu, nullptr);
|
|
|
|
auto *wf = cu->dispatch_wf(0, 0, cu->config().sgprs_per_wf, cu->config().vgprs_per_wf);
|
|
ASSERT_NE(wf, nullptr);
|
|
const uint32_t acc0 = wf->vgpr_alloc().base + amdgpu::ACC_VGPR_OFFSET;
|
|
const uint32_t acc_last = acc0 + cdna3::Isa::MAX_ACC_VGPRS_PER_WF - 1;
|
|
cu->write_vgpr(acc0, 0, 0xA55A0001u);
|
|
cu->write_vgpr(acc_last, 0, 0xDEADBEEFu);
|
|
|
|
test::ScopedTempFile checkpoint("rocjitsu-checkpoint-");
|
|
config::save_checkpoint(checkpoint.path(), *loaded.soc(), 42, loaded.engine_config);
|
|
ASSERT_TRUE(std::filesystem::exists(checkpoint.path()));
|
|
|
|
auto restored = config::restore_checkpoint(checkpoint.path());
|
|
auto *restored_vm = dynamic_cast<VirtualMachine *>(restored.build_result.root.get());
|
|
ASSERT_NE(restored_vm, nullptr);
|
|
auto *restored_cu = restored_vm->soc()->xcd(0)->shader_engine(0)->compute_unit(0);
|
|
ASSERT_NE(restored_cu, nullptr);
|
|
auto *restored_wf = restored_cu->wf(0);
|
|
ASSERT_NE(restored_wf, nullptr);
|
|
EXPECT_EQ(restored_cu->read_vgpr(restored_wf->vgpr_alloc().base + amdgpu::ACC_VGPR_OFFSET, 0),
|
|
0xA55A0001u);
|
|
EXPECT_EQ(restored_cu->read_vgpr(restored_wf->vgpr_alloc().base + amdgpu::ACC_VGPR_OFFSET +
|
|
cdna3::Isa::MAX_ACC_VGPRS_PER_WF - 1,
|
|
0),
|
|
0xDEADBEEFu);
|
|
}
|
|
|
|
TEST(CheckpointTest, SaveAndRestoreWave32ExecScratch) {
|
|
const char *json = R"({"max_ticks":10000,"num_threads":1,
|
|
"vm":{"arch":"rdna4"},
|
|
"topology":{
|
|
"root":{
|
|
"name":"soc","type":"soc",
|
|
"children":[
|
|
{"name":"vram","type":"gpu_memory"},
|
|
{"name":"xcd0","type":"xcd","children":[
|
|
{"name":"l2","type":"l2_cache"},
|
|
{"name":"cp","type":"command_processor"},
|
|
{"name":"se0","type":"shader_engine","children":[
|
|
{"name":"cu[0:1]","type":"compute_unit","config":[
|
|
{"key":"num_wf_slots","value":"1"},
|
|
{"key":"sgprs_per_wf","value":"128"},
|
|
{"key":"vgprs_per_wf","value":"256"},
|
|
{"key":"lds_size_kb","value":"64"}
|
|
]}
|
|
]}
|
|
]}
|
|
]
|
|
},
|
|
"links":[
|
|
{"src":"xcd0.cp.req_0","dst":"xcd0.se0.cu0.cpl","latency":1,"weight":2},
|
|
{"src":"xcd0.se0.cu0.req","dst":"xcd0.l2.cpl_0","latency":1,"weight":10}
|
|
]
|
|
}
|
|
})";
|
|
|
|
auto loaded = config::load_config_from_string(json, rocjitsu::kEmbeddedSchema);
|
|
auto *cu = loaded.soc()->xcd(0)->shader_engine(0)->compute_unit(0);
|
|
ASSERT_NE(cu, nullptr);
|
|
|
|
auto *wf = cu->dispatch_wf(0, 0, cu->config().sgprs_per_wf, cu->config().vgprs_per_wf);
|
|
ASSERT_NE(wf, nullptr);
|
|
ASSERT_EQ(wf->wf_size(), 32u);
|
|
wf->set_exec_raw(0xDEADBEEF0000000FULL);
|
|
|
|
test::ScopedTempFile checkpoint("rocjitsu-checkpoint-");
|
|
config::save_checkpoint(checkpoint.path(), *loaded.soc(), 42, loaded.engine_config);
|
|
ASSERT_TRUE(std::filesystem::exists(checkpoint.path()));
|
|
|
|
auto restored = config::restore_checkpoint(checkpoint.path());
|
|
auto *restored_vm = dynamic_cast<VirtualMachine *>(restored.build_result.root.get());
|
|
ASSERT_NE(restored_vm, nullptr);
|
|
auto *restored_wf = restored_vm->soc()->xcd(0)->shader_engine(0)->compute_unit(0)->wf(0);
|
|
ASSERT_NE(restored_wf, nullptr);
|
|
EXPECT_EQ(restored_wf->exec(), 0xFULL);
|
|
EXPECT_EQ(restored_wf->exec_raw(), 0xDEADBEEF0000000FULL);
|
|
}
|
|
|
|
TEST(CheckpointTest, SaveAndRestoreHwregState) {
|
|
const char *json = R"({"max_ticks":10000,"num_threads":1,
|
|
"vm":{"arch":"gfx1250"},
|
|
"topology":{
|
|
"root":{
|
|
"name":"soc","type":"soc",
|
|
"children":[
|
|
{"name":"vram","type":"gpu_memory"},
|
|
{"name":"xcd0","type":"xcd","children":[
|
|
{"name":"l2","type":"l2_cache"},
|
|
{"name":"cp","type":"command_processor"},
|
|
{"name":"se0","type":"shader_engine","children":[
|
|
{"name":"cu[0:1]","type":"compute_unit","config":[
|
|
{"key":"num_wf_slots","value":"1"},
|
|
{"key":"sgprs_per_wf","value":"104"},
|
|
{"key":"vgprs_per_wf","value":"256"},
|
|
{"key":"lds_size_kb","value":"64"}
|
|
]}
|
|
]}
|
|
]}
|
|
]
|
|
},
|
|
"links":[
|
|
{"src":"xcd0.cp.req_0","dst":"xcd0.se0.cu0.cpl","latency":1,"weight":2},
|
|
{"src":"xcd0.se0.cu0.req","dst":"xcd0.l2.cpl_0","latency":1,"weight":10}
|
|
]
|
|
}
|
|
})";
|
|
|
|
auto loaded = config::load_config_from_string(json, rocjitsu::kEmbeddedSchema);
|
|
auto *cu = loaded.soc()->xcd(0)->shader_engine(0)->compute_unit(0);
|
|
ASSERT_NE(cu, nullptr);
|
|
|
|
auto *wf = cu->dispatch_wf(0, 0, cu->config().sgprs_per_wf, cu->config().vgprs_per_wf);
|
|
ASSERT_NE(wf, nullptr);
|
|
constexpr uint32_t kStatus = 0xA5A55A5Au;
|
|
constexpr uint32_t kWaveSchedMode = 0x5A5AA5A5u;
|
|
wf->set_status_raw(kStatus);
|
|
wf->set_mode_raw(amdgpu::Wavefront::FP16_OVFL_BIT);
|
|
wf->set_wave_sched_mode_raw(kWaveSchedMode);
|
|
ASSERT_TRUE(wf->fp16_ovfl());
|
|
|
|
test::ScopedTempFile checkpoint("rocjitsu-checkpoint-");
|
|
config::save_checkpoint(checkpoint.path(), *loaded.soc(), 42, loaded.engine_config);
|
|
ASSERT_TRUE(std::filesystem::exists(checkpoint.path()));
|
|
|
|
auto restored = config::restore_checkpoint(checkpoint.path());
|
|
auto *restored_vm = dynamic_cast<VirtualMachine *>(restored.build_result.root.get());
|
|
ASSERT_NE(restored_vm, nullptr);
|
|
auto *restored_wf = restored_vm->soc()->xcd(0)->shader_engine(0)->compute_unit(0)->wf(0);
|
|
ASSERT_NE(restored_wf, nullptr);
|
|
EXPECT_EQ(restored_wf->status_raw(), kStatus);
|
|
EXPECT_EQ(restored_wf->mode_raw(), amdgpu::Wavefront::FP16_OVFL_BIT);
|
|
EXPECT_EQ(restored_wf->wave_sched_mode_raw(), kWaveSchedMode);
|
|
EXPECT_TRUE(restored_wf->fp16_ovfl());
|
|
}
|
|
|
|
TEST(CApiTest, CreateAndDestroyFromString) {
|
|
const char *json = R"({"max_ticks":10000,"num_threads":1,
|
|
"vm":{"arch":"cdna3"},
|
|
"topology":{
|
|
"root":{
|
|
"name":"soc","type":"soc",
|
|
"children":[
|
|
{"name":"vram","type":"gpu_memory"},
|
|
{"name":"xcd0","type":"xcd","children":[
|
|
{"name":"l2","type":"l2_cache"},
|
|
{"name":"cp","type":"command_processor"},
|
|
{"name":"se0","type":"shader_engine","children":[
|
|
{"name":"cu[0:1]","type":"compute_unit","config":[
|
|
{"key":"num_wf_slots","value":"10"},
|
|
{"key":"sgprs_per_wf","value":"104"},
|
|
{"key":"vgprs_per_wf","value":"256"},
|
|
{"key":"lds_size_kb","value":"64"}
|
|
]}
|
|
]}
|
|
]}
|
|
]
|
|
},
|
|
"links":[
|
|
{"src":"xcd0.cp.req_0","dst":"xcd0.se0.cu0.cpl","latency":1,"weight":2},
|
|
{"src":"xcd0.se0.cu0.req","dst":"xcd0.l2.cpl_0","latency":1,"weight":10}
|
|
]
|
|
}
|
|
})";
|
|
rj_vm_t *handle = nullptr;
|
|
EXPECT_EQ(rj_vm_create_from_string(json, RJ_VM_MODE_DEFAULT, &handle), ROCJITSU_STATUS_SUCCESS);
|
|
ASSERT_NE(handle, nullptr);
|
|
rj_vm_destroy(handle);
|
|
}
|
|
|
|
TEST(CApiTest, PluginLifecycleDispatchesProfiledShutdownThroughBaseGroup) {
|
|
test::ScopedTempDirectory sink_dir("rocjitsu-plugin-lifecycle-");
|
|
const std::filesystem::path sink_path(sink_dir.path());
|
|
|
|
rj_vm_t *handle = nullptr;
|
|
ASSERT_EQ(
|
|
rj_vm_create((CONFIG_DIR_PATH + "/gfx950_cdna4.json").c_str(), RJ_VM_MODE_DEFAULT, &handle),
|
|
ROCJITSU_STATUS_SUCCESS);
|
|
ASSERT_NE(handle, nullptr);
|
|
|
|
const std::string plugin_config = std::format(
|
|
R"({{"profiled":true,"sinks":{{"types":["file"],"dir":"{}"}}}})", sink_path.string());
|
|
ASSERT_EQ(rj_vm_load_plugins(handle, plugin_config.c_str(), nullptr), ROCJITSU_STATUS_SUCCESS);
|
|
rj_vm_destroy(handle);
|
|
|
|
std::ifstream profile(sink_path / "profile.log");
|
|
const std::string output{std::istreambuf_iterator<char>(profile),
|
|
std::istreambuf_iterator<char>()};
|
|
EXPECT_NE(output.find("total emulation time"), std::string::npos) << output;
|
|
}
|
|
|
|
TEST(CApiTest, InvalidArguments) {
|
|
rj_vm_t *handle = nullptr;
|
|
EXPECT_EQ(rj_vm_create_from_string(nullptr, RJ_VM_MODE_DEFAULT, &handle),
|
|
ROCJITSU_STATUS_INVALID_ARGUMENT);
|
|
EXPECT_EQ(rj_vm_step(nullptr, nullptr), ROCJITSU_STATUS_INVALID_ARGUMENT);
|
|
}
|
|
|
|
} // namespace
|