diff --git a/CMake/native.cmake b/CMake/native.cmake index d5c8a71bf..e29fa9a77 100644 --- a/CMake/native.cmake +++ b/CMake/native.cmake @@ -10,6 +10,11 @@ # as amdxdna_legacy.ko. option(PACKAGE_LEGACY_DRIVER "Package legacy driver source" OFF) +# The VE2 shim test (test/shim_test) is not part of the normal VE2 runtime +# build. It is opt-in (e.g. built on demand by a dedicated packaging recipe) +# so the default xrt/amdxdna build does not compile or install test artifacts. +option(XDNA_BUILD_SHIM_TEST "Build test/shim_test for the VE2 edge build" OFF) + # By default, build/build.sh downloads binaries to build/amdxdna_bins/ # Absolute path, cannot be used in install command as destination. set(AMDXDNA_BINS_DIR ${CMAKE_BINARY_DIR}/../amdxdna_bins) @@ -19,6 +24,16 @@ if(XDNA_VE2) include(${CMAKE_CURRENT_SOURCE_DIR}/CMake/xrt_ve2.cmake) add_subdirectory(src) +# Build the shim tests (test/shim_test) only when explicitly requested. The +# shim_test include dirs reference XRT_SUBMOD_SOURCE_DIR/BINARY_DIR, which are +# only set on the non-VE2 path above; point them at the same xrt submodule the +# VE2 build uses so the test target resolves its headers/generated sources. +if(XDNA_BUILD_SHIM_TEST) + set(XRT_SUBMOD_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/xrt) + set(XRT_SUBMOD_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/xrt) + add_subdirectory(test) +endif() + else(XDNA_VE2) # Bring in xrt git submodule before include any local directories diff --git a/src/shim_ve2/xdna_device.cpp b/src/shim_ve2/xdna_device.cpp index 6b496e394..bd6f4d86f 100644 --- a/src/shim_ve2/xdna_device.cpp +++ b/src/shim_ve2/xdna_device.cpp @@ -107,11 +107,42 @@ struct pcie_id std::ifstream rev_f(base + "/revision"); unsigned int dev_val = 0, rev_val = 0; if (!(dev_f >> std::hex >> dev_val) || !(rev_f >> std::hex >> rev_val)) - throw xrt_core::query::sysfs_error("Failed to read device/revision from " + base); + throw xrt_core::query::sysfs_error("Failed to read device/revision from " + base + "/{device,revision}"); return { static_cast(dev_val), static_cast(rev_val) }; } }; +// New query to get the device id +struct pcie_device_id +{ + using result_type = query::pcie_device::result_type; + + static result_type + get(const xrt_core::device* device, key_type key) + { + return pcie_id::get(device, key).device_id; + } +}; + +// Query to get the PCIe vendor id from sysfs +struct pcie_vendor +{ + using result_type = query::pcie_vendor::result_type; + + static result_type + get(const xrt_core::device* device, key_type key) + { + auto [domain, bus, dev, func] = bdf::get(device, key); + std::string bdf_str = boost::str(boost::format("%04x:%02x:%02x.%x") % domain % bus % dev % func); + const std::string base = "/sys/bus/pci/devices/" + bdf_str; + std::ifstream vendor_f(base + "/vendor"); + unsigned int vendor_val = 0; + if (!(vendor_f >> std::hex >> vendor_val)) + throw xrt_core::query::sysfs_error("Failed to read vendor from " + base + "/vendor"); + return static_cast(vendor_val); + } +}; + struct board_name { using result_type = query::board_name::result_type; @@ -1064,6 +1095,8 @@ initialize_query_table() emplace_func0_request(); emplace_func0_request(); emplace_func0_request(); + emplace_func0_request(); + emplace_func0_request(); emplace_func0_request(); emplace_func0_request(); emplace_func0_request(); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 15bc876fc..404b313c8 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -2,4 +2,9 @@ # Copyright (C) 2024, Advanced Micro Devices, Inc. All rights reserved. add_subdirectory(shim_test) + +# xrt_test exercises the public XRT user API and is only wired up for the +# native (non-VE2) build; the VE2 edge build ships shim_test only. +if(NOT XDNA_VE2) add_subdirectory(xrt_test) +endif() diff --git a/test/shim_test/dev_info.cpp b/test/shim_test/dev_info.cpp index deb43a212..304051f2f 100644 --- a/test/shim_test/dev_info.cpp +++ b/test/shim_test/dev_info.cpp @@ -162,6 +162,39 @@ binary_info binary_infos[] = { .path = "local_shim_test_data/npu3a/resnet50/resnet50.elf", .flow = PREEMPT_FULL_ELF, }, + // npu_ve2 (aie2ps / VE2): own FULL_ELF binaries for "good" (vadd), "nop" and + // "bad_timeout". + { + .tag = "good", + .device = npu_ve2_device_id, + .revision_id = npu_any_revision_id, + .ip_name2idx = { + { "DPU:dpu", {0xffffffff} }, + }, + .path = "local_shim_test_data/npu_ve2/vadd/vadd.elf", + .flow = FULL_ELF, + }, + { + .tag = "bad_timeout", + .device = npu_ve2_device_id, + .revision_id = npu_any_revision_id, + .ip_name2idx = { + { "DPU:dpu", {0xffffffff} }, + }, + .path = "local_shim_test_data/npu_ve2/bad/bad_timeout.elf", + .extra = { {"exp_status", exp_status_timeout}, {"exp_val", "5"} }, + .flow = FULL_ELF, + }, + { + .tag = "nop", + .device = npu_ve2_device_id, + .revision_id = npu_any_revision_id, + .ip_name2idx = { + { "DPU:dpu", {0xffffffff} }, + }, + .path = "local_shim_test_data/npu_ve2/nop/nop.elf", + .flow = FULL_ELF, + }, { .tag = "good", .device = npu4_device_id, diff --git a/test/shim_test/dev_info.h b/test/shim_test/dev_info.h index 626df932b..e854107e5 100644 --- a/test/shim_test/dev_info.h +++ b/test/shim_test/dev_info.h @@ -35,6 +35,7 @@ const uint16_t npu3_device_id = 0x17f1; const uint16_t npu3_device_id1 = 0x17f3; const uint16_t npu3a_device_id = 0x1b0a; const uint16_t npu3a_device_id1 = 0x1b0c; +const uint16_t npu_ve2_device_id = 0xb052; const uint16_t npu4_device_id = 0x17f0; const uint16_t npu_any_revision_id = 0xffff; const uint16_t npu1_revision_id = 0x0; diff --git a/test/shim_test/shim_test.cpp b/test/shim_test/shim_test.cpp index c8e539535..501643349 100644 --- a/test/shim_test/shim_test.cpp +++ b/test/shim_test/shim_test.cpp @@ -211,7 +211,8 @@ dev_filter_is_aie4(device::id_type id, device* dev) if (!is_xdna_dev(dev)) return false; auto device_id = canonical_device_id(device_query(dev)); - return device_id == npu3_device_id || device_id == npu3a_device_id; + return device_id == npu3_device_id || device_id == npu3a_device_id || + device_id == npu_ve2_device_id; } bool @@ -274,6 +275,50 @@ dev_filter_is_npu4_and_amdxdna_drv(device::id_type id, device* dev) return true; } +// VE2 (aie2ps) is device id npu_ve2. It is grouped under aie4/aie for the tests +// it supports, but several aie/aie4 features are not implemented on VE2. These +// helpers keep VE2 in the broad groups while excluding it from the specific +// tests it cannot pass (and one helper to opt VE2 into a couple of aie2 tests +// it does pass). +bool +is_npu_ve2(device::id_type id, device* dev) +{ + if (!is_xdna_dev(dev)) + return false; + auto device_id = canonical_device_id(device_query(dev)); + return device_id == npu_ve2_device_id; +} + +bool +dev_filter_xdna_not_npu_ve2(device::id_type id, device* dev) +{ + return dev_filter_xdna(id, dev) && !is_npu_ve2(id, dev); +} + +bool +dev_filter_is_aie_not_npu_ve2(device::id_type id, device* dev) +{ + return dev_filter_is_aie(id, dev) && !is_npu_ve2(id, dev); +} + +bool +dev_filter_is_aie4_not_npu_ve2(device::id_type id, device* dev) +{ + return dev_filter_is_aie4(id, dev) && !is_npu_ve2(id, dev); +} + +bool +dev_filter_is_aie4_or_npu4_not_npu_ve2(device::id_type id, device* dev) +{ + return dev_filter_is_aie4_or_npu4(id, dev) && !is_npu_ve2(id, dev); +} + +bool +dev_filter_is_aie2_or_npu_ve2(device::id_type id, device* dev) +{ + return dev_filter_is_aie2(id, dev) || is_npu_ve2(id, dev); +} + static void TEST_async_error_io_any(device::id_type id, std::shared_ptr& sdev, arg_type& arg) { if (dev_filter_is_npu4(id, sdev.get())) @@ -1506,9 +1551,14 @@ std::vector test_list { {XCL_BO_FLAGS_HOST_ONLY, 0, 0x10000, 0x23000, 0x2000} }, test_case{ "create_and_free_input_output_bo huge pages", {}, - TEST_POSITIVE, dev_filter_is_aie, TEST_create_free_bo, + TEST_POSITIVE, dev_filter_is_aie_not_npu_ve2, TEST_create_free_bo, {XCL_BO_FLAGS_HOST_ONLY, 0, 0x140000000} }, + // VE2 (npu_ve2) has a smaller contiguous CMA pool, so use a 3GB BO instead of 5GB. + test_case{ "create_and_free_input_output_bo huge pages (npu_ve2)", {}, + TEST_POSITIVE, is_npu_ve2, TEST_create_free_bo, + {XCL_BO_FLAGS_HOST_ONLY, 0, 0xC0000000} + }, test_case{ "sync_bo for dpu sequence bo", {}, TEST_POSITIVE, dev_filter_xdna, TEST_sync_bo, {XCL_BO_FLAGS_CACHEABLE, 0, 128} }, @@ -1522,7 +1572,7 @@ std::vector test_list { TEST_POSITIVE, dev_filter_xdna, TEST_map_bo, {XCL_BO_FLAGS_HOST_ONLY, 0, 361264} }, test_case{ "map bo for read only", {}, - TEST_NEGATIVE, dev_filter_xdna, TEST_map_read_bo, {0x1000} + TEST_NEGATIVE, dev_filter_xdna_not_npu_ve2, TEST_map_read_bo, {0x1000} }, test_case{ "map exec_buf_bo and test perf", {}, TEST_POSITIVE, dev_filter_xdna, TEST_create_free_bo, {XCL_BO_FLAGS_EXECBUF, 0, 0x1000} @@ -1535,7 +1585,7 @@ std::vector test_list { }, // Keep bad run before normal run to test recovery of hw ctx test_case{ "io test async error", {}, - TEST_POSITIVE, dev_filter_is_aie4_or_npu4, TEST_async_error_io_any, {} + TEST_POSITIVE, dev_filter_is_aie4_or_npu4_not_npu_ve2, TEST_async_error_io_any, {} }, test_case{ "io test real kernel good run", {}, TEST_POSITIVE, dev_filter_xdna, TEST_io, { IO_TEST_NORMAL_RUN, 1 } @@ -1550,10 +1600,10 @@ std::vector test_list { TEST_POSITIVE, dev_filter_is_aie, TEST_io_latency, { IO_TEST_NORMAL_RUN, IO_TEST_IOCTL_WAIT, NUM_STRESS_IO } }, test_case{ "create and free debug bo", {}, - TEST_POSITIVE, dev_filter_xdna, TEST_create_free_debug_bo, { 0x1000 } + TEST_POSITIVE, dev_filter_xdna_not_npu_ve2, TEST_create_free_debug_bo, { 0x1000 } }, test_case{ "create and free large debug bo", {}, - TEST_POSITIVE, dev_filter_xdna, TEST_create_free_debug_bo, { 0x100000 } + TEST_POSITIVE, dev_filter_xdna_not_npu_ve2, TEST_create_free_debug_bo, { 0x100000 } }, test_case{ "create and free uc_log bo", {}, TEST_POSITIVE, dev_filter_is_aie4, TEST_create_free_uc_log_bo, { 0x10000 } @@ -1574,7 +1624,7 @@ std::vector test_list { TEST_POSITIVE, dev_filter_is_aie2, TEST_elf_io, { IO_TEST_NORMAL_RUN, 1 } }, test_case{ "Cmd fencing (user space side)", {}, - TEST_POSITIVE, dev_filter_xdna, TEST_cmd_fence_host, {} + TEST_POSITIVE, dev_filter_xdna_not_npu_ve2, TEST_cmd_fence_host, {} }, test_case{ "io test no op with duplicated BOs", {}, TEST_POSITIVE, dev_filter_xdna, TEST_noop_io_with_dup_bo, {} @@ -1583,22 +1633,22 @@ std::vector test_list { TEST_POSITIVE, dev_filter_is_aie, TEST_io_runlist_latency, { IO_TEST_NOOP_RUN, IO_TEST_IOCTL_WAIT, NUM_STRESS_IO } }, test_case{ "measure no-op kernel throughput chained command", {}, - TEST_POSITIVE, dev_filter_is_aie, TEST_io_runlist_throughput, { IO_TEST_NOOP_RUN, IO_TEST_IOCTL_WAIT, NUM_STRESS_IO } + TEST_POSITIVE, dev_filter_is_aie_not_npu_ve2, TEST_io_runlist_throughput, { IO_TEST_NOOP_RUN, IO_TEST_IOCTL_WAIT, NUM_STRESS_IO } }, test_case{ "measure no-op kernel latency (polling)", {}, - TEST_POSITIVE, dev_filter_is_aie, TEST_io_latency, { IO_TEST_NOOP_RUN, IO_TEST_POLL_WAIT, NUM_STRESS_IO } + TEST_POSITIVE, dev_filter_is_aie_not_npu_ve2, TEST_io_latency, { IO_TEST_NOOP_RUN, IO_TEST_POLL_WAIT, NUM_STRESS_IO } }, test_case{ "measure no-op kernel throughput (polling)", {}, - TEST_POSITIVE, dev_filter_is_aie, TEST_io_throughput, { IO_TEST_NOOP_RUN, IO_TEST_POLL_WAIT, NUM_STRESS_IO } + TEST_POSITIVE, dev_filter_is_aie_not_npu_ve2, TEST_io_throughput, { IO_TEST_NOOP_RUN, IO_TEST_POLL_WAIT, NUM_STRESS_IO } }, test_case{ "measure no-op kernel latency chained command (polling)", {}, - TEST_POSITIVE, dev_filter_is_aie, TEST_io_runlist_latency, { IO_TEST_NOOP_RUN, IO_TEST_POLL_WAIT, NUM_STRESS_IO } + TEST_POSITIVE, dev_filter_is_aie_not_npu_ve2, TEST_io_runlist_latency, { IO_TEST_NOOP_RUN, IO_TEST_POLL_WAIT, NUM_STRESS_IO } }, test_case{ "measure no-op kernel throughput chained command (polling)", {}, - TEST_POSITIVE, dev_filter_is_aie, TEST_io_runlist_throughput, { IO_TEST_NOOP_RUN, IO_TEST_POLL_WAIT, NUM_STRESS_IO } + TEST_POSITIVE, dev_filter_is_aie_not_npu_ve2, TEST_io_runlist_throughput, { IO_TEST_NOOP_RUN, IO_TEST_POLL_WAIT, NUM_STRESS_IO } }, test_case{ "Cmd fencing (driver side)", {}, - TEST_POSITIVE, dev_filter_xdna, TEST_cmd_fence_device, {} + TEST_POSITIVE, dev_filter_xdna_not_npu_ve2, TEST_cmd_fence_device, {} }, test_case{ "sync_bo for input_output 1MiB BO", {}, TEST_POSITIVE, dev_filter_xdna, TEST_sync_bo, {XCL_BO_FLAGS_HOST_ONLY, 0, 0x100000} @@ -1619,13 +1669,13 @@ std::vector test_list { TEST_NEGATIVE, dev_filter_is_aie, TEST_create_destroy_max_context, { 1 } }, test_case{ "Multi context IO test 1", {}, - TEST_POSITIVE, dev_filter_is_aie2, TEST_multi_context_io_test, { 0 } + TEST_POSITIVE, dev_filter_is_aie2_or_npu_ve2, TEST_multi_context_io_test, { 0 } }, test_case{ "Multi context IO test 2", {}, - TEST_POSITIVE, dev_filter_is_aie2, TEST_multi_context_io_test, { 1 } + TEST_POSITIVE, dev_filter_is_aie2_or_npu_ve2, TEST_multi_context_io_test, { 1 } }, test_case{ "Multi context IO test 3", {}, - TEST_POSITIVE, dev_filter_is_aie2, TEST_multi_context_io_test, { 2 } + TEST_POSITIVE, dev_filter_is_aie2_or_npu_ve2, TEST_multi_context_io_test, { 2 } }, test_case{ "Create and destroy devices", {}, TEST_POSITIVE, dev_filter_xdna, TEST_create_destroy_device, {} @@ -1640,10 +1690,10 @@ std::vector test_list { TEST_POSITIVE, dev_filter_is_aie2_and_amdxdna_drv, TEST_io_with_ubuf_bo, {} }, test_case{ "multi-command preempt full ELF io test real kernel good run", {}, - TEST_POSITIVE, dev_filter_is_aie4_or_npu4, TEST_preempt_full_elf_io, { IO_TEST_FORCE_PREEMPTION, 8 } + TEST_POSITIVE, dev_filter_is_aie4_or_npu4_not_npu_ve2, TEST_preempt_full_elf_io, { IO_TEST_FORCE_PREEMPTION, 8 } }, test_case{ "Real kernel delay run for auto-suspend/resume", {}, - TEST_POSITIVE, dev_filter_is_aie2, TEST_io_suspend_resume, {} + TEST_POSITIVE, dev_filter_is_aie2_or_npu_ve2, TEST_io_suspend_resume, {} }, test_case{ "io test timeout run for context health report", {}, TEST_POSITIVE, dev_filter_is_npu4, TEST_io_timeout, {} @@ -1652,23 +1702,23 @@ std::vector test_list { TEST_POSITIVE, dev_filter_is_npu4_and_amdxdna_drv, TEST_app_health_query_multi_ctx, {} }, test_case{ "query hw_contexts (get_info)", {}, - TEST_POSITIVE, dev_filter_is_aie, TEST_query_hw_contexts, {} + TEST_POSITIVE, dev_filter_is_aie_not_npu_ve2, TEST_query_hw_contexts, {} }, test_case{ "hw_context_all (get_array)", {}, - TEST_POSITIVE, dev_filter_is_aie, TEST_hw_context_all, {} + TEST_POSITIVE, dev_filter_is_aie_not_npu_ve2, TEST_hw_context_all, {} }, test_case{ "query telemetry", {}, - TEST_POSITIVE, dev_filter_is_aie, TEST_query_telemetry, {} + TEST_POSITIVE, dev_filter_is_aie_not_npu_ve2, TEST_query_telemetry, {} }, test_case{ "query telemetry header-only buffer fails", {}, - TEST_POSITIVE, dev_filter_is_aie, TEST_query_telemetry_short_buf, {} + TEST_POSITIVE, dev_filter_is_aie_not_npu_ve2, TEST_query_telemetry_short_buf, {} }, //test_case{ "io test no-op kernel good run", {}, // TEST_POSITIVE, dev_filter_is_aie2, TEST_io, { IO_TEST_NOOP_RUN, 1 } //}, // get async error in multi thread after async error has raised. test_case{ "get async error in multithread - HAS ASYNC ERROR", {}, - TEST_POSITIVE, dev_filter_is_aie4_or_npu4, TEST_async_error_multi, {true} + TEST_POSITIVE, dev_filter_is_aie4_or_npu4_not_npu_ve2, TEST_async_error_multi, {true} }, test_case{ "gemm and debug BO", {}, TEST_POSITIVE, dev_filter_is_npu4, TEST_io_gemm, {} @@ -1733,19 +1783,19 @@ std::vector test_list { TEST_POSITIVE, dev_filter_is_npu4, TEST_dpm_power_modes, {} }, test_case{ "CERT log: attach/detach", {}, - TEST_POSITIVE, dev_filter_is_aie4, TEST_certlog_attach_detach, {} + TEST_POSITIVE, dev_filter_is_aie4_not_npu_ve2, TEST_certlog_attach_detach, {} }, test_case{ "CERT log: max num_ucs", {}, - TEST_POSITIVE, dev_filter_is_aie4, TEST_certlog_multi_uc, {} + TEST_POSITIVE, dev_filter_is_aie4_not_npu_ve2, TEST_certlog_multi_uc, {} }, test_case{ "CERT log: num_ucs > AIE4_MAX_NUM_CERTS rejected", {}, - TEST_POSITIVE, dev_filter_is_aie4, TEST_certlog_num_ucs_overflow, {} + TEST_POSITIVE, dev_filter_is_aie4_not_npu_ve2, TEST_certlog_num_ucs_overflow, {} }, test_case{ "CERT log: out-of-range uc index rejected", {}, - TEST_POSITIVE, dev_filter_is_aie4, TEST_certlog_invalid_uc_index, {} + TEST_POSITIVE, dev_filter_is_aie4_not_npu_ve2, TEST_certlog_invalid_uc_index, {} }, test_case{ "CERT log: payload overflow rejected", {}, - TEST_POSITIVE, dev_filter_is_aie4, TEST_certlog_payload_overflow, {} + TEST_POSITIVE, dev_filter_is_aie4_not_npu_ve2, TEST_certlog_payload_overflow, {} }, };