diff --git a/projects/hip-tests/catch/contract/graph_debug/test_hip_graph_debug_contract.cc b/projects/hip-tests/catch/contract/graph_debug/test_hip_graph_debug_contract.cc index b0552f36ccac..ac3d44c5f641 100644 --- a/projects/hip-tests/catch/contract/graph_debug/test_hip_graph_debug_contract.cc +++ b/projects/hip-tests/catch/contract/graph_debug/test_hip_graph_debug_contract.cc @@ -12,18 +12,17 @@ #include #include +#include #include namespace { constexpr size_t kByteCount = 64; -// Builds a unique temporary file path for the exported dot graph so concurrent -// test binaries do not collide on a shared filename. -std::string UniqueDotPath() { +// Temp dir: an installed test tree may be read-only. +std::string DotPath() { int device = 0; HIP_CHECK(hipGetDevice(&device)); - return std::string("hip_contract_graph_debug_") + std::to_string(device) + "_" + - std::to_string(static_cast(reinterpret_cast(&device))) + ".dot"; + return hip_test::TempPath("hip_contract_graph_debug_" + std::to_string(device), ".dot"); } hipMemsetParams MakeByteMemsetParams(void* device_ptr, unsigned int value) { @@ -61,8 +60,7 @@ HIP_TEST_CASE(Contract_GraphDebug_HipGraphDebugDotPrint_Default_WritesNonEmptyFi hipMemsetParams memset_params = MakeByteMemsetParams(device_ptr, 0x5A); HIP_CHECK(hipGraphAddMemsetNode(&node, graph, nullptr, 0, &memset_params)); - const std::string path = UniqueDotPath(); - std::remove(path.c_str()); + const std::string path = DotPath(); // Exporting a non-empty graph to a dot file must succeed (or report the // feature unsupported) and, on success, produce a non-empty file on disk. @@ -87,8 +85,7 @@ HIP_TEST_CASE(Contract_GraphDebug_HipGraphDebugDotPrint_Default_VerboseFlagIsAcc cleanup.Add([graph] { (void)hipGraphDestroy(graph); }); HIP_CHECK(hipGraphAddEmptyNode(&node, graph, nullptr, 0)); - const std::string path = UniqueDotPath(); - std::remove(path.c_str()); + const std::string path = DotPath(); // The verbose flag augments the output but must not change the success // contract: a valid graph still exports to a non-empty file. diff --git a/projects/hip-tests/catch/contract/library_file/test_hip_library_file_contract.cc b/projects/hip-tests/catch/contract/library_file/test_hip_library_file_contract.cc index bf627ffd0471..2858f37d72a8 100644 --- a/projects/hip-tests/catch/contract/library_file/test_hip_library_file_contract.cc +++ b/projects/hip-tests/catch/contract/library_file/test_hip_library_file_contract.cc @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -68,15 +69,15 @@ bool CompileLibrarySource(std::vector& code) { return true; } -// Compiles the library source and writes it to a unique per-test file in the -// current working directory, returning the path. Skips when HIPRTC is -// unavailable. The caller must remove the file when done. +// Compile to a temp file: an installed test tree may be read-only. +// Caller removes the returned path. std::string WriteCodeObjectFile(const char* suffix) { std::vector code; if (!CompileLibrarySource(code)) { HIP_SKIP_TEST("HIPRTC compilation is not supported by this device/runtime path."); } - const std::string path = std::string("hip-contract-library-file-") + suffix + ".code"; + const std::string path = + hip_test::TempPath("hip-contract-library-file-" + std::string(suffix), ".code"); std::ofstream out(path, std::ios::binary); REQUIRE(out.is_open()); out.write(code.data(), static_cast(code.size())); diff --git a/projects/hip-tests/catch/include/hip_test_temp_path.hh b/projects/hip-tests/catch/include/hip_test_temp_path.hh new file mode 100644 index 000000000000..87385c64c98a --- /dev/null +++ b/projects/hip-tests/catch/include/hip_test_temp_path.hh @@ -0,0 +1,45 @@ +/* + * Copyright (c) Advanced Micro Devices, Inc., or its affiliates. + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include "hip_test_filesystem.hh" + +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#define HIP_TEST_GETPID _getpid +#else +#include +#define HIP_TEST_GETPID getpid +#endif + +// Naming for temporary test artifacts. The temp directory is shared, so names +// must be unguessable: a predictable path can be pre-seeded with a symlink. +namespace hip_test { + +// 64 bits from std::random_device as 16 hex chars. The pid keeps the name +// unique if random_device degenerates to a fixed sequence, which the standard +// permits; live pids in a namespace are distinct, clock readings are not. +inline std::string RandomTag() { + std::random_device dev; + uint64_t value = (static_cast(dev()) << 32) ^ dev(); + value ^= static_cast(HIP_TEST_GETPID()); + char buf[17]; + snprintf(buf, sizeof(buf), "%016llx", static_cast(value)); + return std::string(buf); +} + +// /-. +inline std::string TempPath(const std::string& stem, const std::string& extension) { + return (fs::temp_directory_path() / (stem + "-" + RandomTag() + extension)).string(); +} + +} // namespace hip_test