| // SPDX-FileCopyrightText: The Eigen Authors | |
| // SPDX-License-Identifier: MPL-2.0 | |
| #define EIGEN_TEST_NO_LONGDOUBLE | |
| #define EIGEN_TEST_NO_COMPLEX | |
| #define EIGEN_USE_GPU | |
| #define EIGEN_NO_DEBUG | |
| #if defined(EIGEN_USE_HIP) | |
| #include <hip/hip_runtime.h> | |
| using TestGpuError = hipError_t; | |
| using TestGpuAttribute = hipDeviceAttribute_t; | |
| #else | |
| #include <cuda_runtime.h> | |
| using TestGpuError = cudaError_t; | |
| using TestGpuAttribute = cudaDeviceAttr; | |
| #endif | |
| static int driver_version = 11010; | |
| static int pool_support = 1; | |
| static int pool_queries = 0; | |
| static int runtime_errors = 0; | |
| static TestGpuError injected_error = static_cast<TestGpuError>(0); | |
| static TestGpuError last_error = static_cast<TestGpuError>(0); | |
| static TestGpuError test_device_get_attribute(int* value, TestGpuAttribute attribute, int device); | |
| static TestGpuError test_get_device_count(int* count) { | |
| *count = 2; | |
| return static_cast<TestGpuError>(0); | |
| } | |
| static TestGpuError test_get_last_error() { | |
| const TestGpuError result = last_error; | |
| last_error = static_cast<TestGpuError>(0); | |
| return result; | |
| } | |
| #if defined(EIGEN_USE_HIP) | |
| #define hipDeviceGetAttribute test_device_get_attribute | |
| #define hipGetDeviceCount test_get_device_count | |
| #define hipGetLastError test_get_last_error | |
| #else | |
| static cudaError_t test_driver_get_version(int* version) { | |
| *version = driver_version; | |
| return cudaSuccess; | |
| } | |
| #define cudaDeviceGetAttribute test_device_get_attribute | |
| #define cudaGetDeviceCount test_get_device_count | |
| #define cudaGetLastError test_get_last_error | |
| #define cudaDriverGetVersion test_driver_get_version | |
| #endif | |
| static void record_runtime_error(TestGpuError error) { | |
| if (static_cast<int>(error) != 0) ++runtime_errors; | |
| } | |
| #define EIGEN_GPU_RUNTIME_CHECK(expr) record_runtime_error(expr) | |
| #include "main.h" | |
| #include <contrib/Eigen/Tensor> | |
| // Inject old-runtime responses before the public umbrella is parsed, without requiring old drivers or hardware. | |
| static TestGpuError test_device_get_attribute(int* value, TestGpuAttribute attribute, int device) { | |
| *value = -1; | |
| if (injected_error != gpuSuccess) return injected_error; | |
| if (attribute == gpuDevAttrMaxSharedMemoryPerBlockOptin) { | |
| #if defined(EIGEN_USE_HIP) | |
| if (device == 0) return last_error = hipErrorInvalidValue; | |
| #endif | |
| *value = 98304; | |
| } else if (attribute == gpuDevAttrMaxSharedMemoryPerBlock) { | |
| *value = 49152; | |
| } else if (attribute == gpuDevAttrMemoryPoolsSupported) { | |
| ++pool_queries; | |
| #if !defined(EIGEN_USE_HIP) | |
| if (driver_version < 11020) return last_error = cudaErrorInvalidValue; | |
| #endif | |
| *value = pool_support; | |
| } else if (attribute == gpuDevAttrWarpSize) { | |
| *value = 32 * (device + 1); | |
| } else { | |
| *value = 1; | |
| } | |
| return gpuSuccess; | |
| } | |
| static void test_attribute_cache() { | |
| // numThreads() initializes every cached field, even on runtimes missing an optional attribute. | |
| for (int device = 0; device < 2; ++device) { | |
| Eigen::GpuStreamDevice stream(device); | |
| Eigen::GpuDevice gpu_device(&stream); | |
| VERIFY_IS_EQUAL(gpu_device.numThreads(), static_cast<size_t>(32 * (device + 1))); | |
| VERIFY_IS_EQUAL(runtime_errors, 0); | |
| VERIFY_IS_EQUAL(test_get_last_error(), gpuSuccess); | |
| #if defined(EIGEN_USE_HIP) | |
| VERIFY_IS_EQUAL(gpu_device.sharedMemPerBlockOptin(), device == 0 ? 49152 : 98304); | |
| VERIFY(gpu_device.memoryPoolsSupported()); | |
| #else | |
| VERIFY_IS_EQUAL(gpu_device.sharedMemPerBlockOptin(), 98304); | |
| VERIFY(!gpu_device.memoryPoolsSupported()); | |
| VERIFY_IS_EQUAL(pool_queries, 0); | |
| #endif | |
| } | |
| } | |
| static void test_attribute_queries() { | |
| driver_version = 11020; | |
| for (int supported = 0; supported <= 1; ++supported) { | |
| pool_support = supported; | |
| const int queries_before = pool_queries; | |
| VERIFY_IS_EQUAL(Eigen::GetGpuDeviceAttribute(gpuDevAttrMemoryPoolsSupported, 0), supported); | |
| VERIFY_IS_EQUAL(pool_queries, queries_before + 1); | |
| } | |
| VERIFY_IS_EQUAL(runtime_errors, 0); | |
| #if defined(EIGEN_USE_HIP) | |
| injected_error = hipErrorInvalidValue; | |
| #else | |
| injected_error = cudaErrorInvalidValue; | |
| #endif | |
| // An invalid-value error on a required attribute or a supported pool query is still a runtime failure. | |
| Eigen::GetGpuDeviceAttribute(gpuDevAttrWarpSize, 0); | |
| VERIFY_IS_EQUAL(runtime_errors, 1); | |
| Eigen::GetGpuDeviceAttribute(gpuDevAttrMemoryPoolsSupported, 0); | |
| VERIFY_IS_EQUAL(runtime_errors, 2); | |
| #if defined(EIGEN_USE_HIP) | |
| injected_error = hipErrorInvalidDevice; | |
| #else | |
| injected_error = cudaErrorInvalidDevice; | |
| #endif | |
| Eigen::GetGpuDeviceAttribute(gpuDevAttrMaxSharedMemoryPerBlockOptin, 0); | |
| VERIFY_IS_EQUAL(runtime_errors, 3); | |
| injected_error = gpuSuccess; | |
| runtime_errors = 0; | |
| } | |
| EIGEN_DECLARE_TEST(tensor_gpu_device_attributes) { | |
| CALL_SUBTEST(test_attribute_cache()); | |
| CALL_SUBTEST(test_attribute_queries()); | |
| } |