File indexing completed on 2023-10-25 09:50:25
0001 #include <cassert>
0002 #include <iostream>
0003 #include <limits>
0004 #include <string>
0005 #include <utility>
0006
0007 #include <cuda_runtime_api.h>
0008
0009 #include <fmt/core.h>
0010
0011 #include <catch.hpp>
0012
0013 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
0014 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0015 #include "FWCore/ParameterSetReader/interface/ParameterSetReader.h"
0016 #include "FWCore/ServiceRegistry/interface/Service.h"
0017 #include "FWCore/ServiceRegistry/interface/ServiceRegistry.h"
0018 #include "FWCore/ServiceRegistry/interface/ServiceToken.h"
0019 #include "FWCore/Utilities/interface/Exception.h"
0020 #include "FWCore/Utilities/interface/ResourceInformation.h"
0021 #include "HeterogeneousCore/CUDAServices/interface/CUDAInterface.h"
0022
0023 namespace {
0024 std::string makeProcess(std::string const& name) {
0025 return fmt::format(R"_(
0026 import FWCore.ParameterSet.Config as cms
0027 process = cms.Process('{}')
0028 )_",
0029 name);
0030 }
0031
0032 void addResourceInformationService(std::string& config) {
0033 config += R"_(
0034 process.add_(cms.Service('ResourceInformationService'))
0035 )_";
0036 }
0037
0038 void addCUDAService(std::string& config, bool enabled = true) {
0039 config += fmt::format(R"_(
0040 process.add_(cms.Service('CUDAService',
0041 enabled = cms.untracked.bool({}),
0042 verbose = cms.untracked.bool(True)
0043 ))
0044 )_",
0045 enabled ? "True" : "False");
0046 }
0047
0048 edm::ServiceToken getServiceToken(std::string const& config) {
0049 std::unique_ptr<edm::ParameterSet> params;
0050 edm::makeParameterSets(config, params);
0051 return edm::ServiceToken(edm::ServiceRegistry::createServicesFromConfig(std::move(params)));
0052 }
0053 }
0054
0055 TEST_CASE("Tests of CUDAService", "[CUDAService]") {
0056
0057
0058 int deviceCount = 0;
0059 auto ret = cudaGetDeviceCount(&deviceCount);
0060
0061 if (ret != cudaSuccess) {
0062 WARN("Unable to query the CUDA capable devices from the CUDA runtime API: ("
0063 << ret << ") " << cudaGetErrorString(ret) << ". Running only tests not requiring devices.");
0064 }
0065
0066 std::string config = makeProcess("Test");
0067 addCUDAService(config);
0068 auto serviceToken = getServiceToken(config);
0069 edm::ServiceRegistry::Operate operate(serviceToken);
0070
0071 SECTION("Enable the CUDAService only if there are CUDA capable GPUs") {
0072 edm::Service<CUDAInterface> cuda;
0073 if (deviceCount <= 0) {
0074 REQUIRE((not cuda or not cuda->enabled()));
0075 WARN("CUDAService is not present, or disabled because there are no CUDA GPU devices");
0076 return;
0077 } else {
0078 REQUIRE(cuda);
0079 REQUIRE(cuda->enabled());
0080 INFO("CUDAService is enabled");
0081 }
0082 }
0083
0084 SECTION("CUDAService enabled") {
0085 int driverVersion = 0, runtimeVersion = 0;
0086 edm::Service<CUDAInterface> cuda;
0087 ret = cudaDriverGetVersion(&driverVersion);
0088 if (ret != cudaSuccess) {
0089 FAIL("Unable to query the CUDA driver version from the CUDA runtime API: (" << ret << ") "
0090 << cudaGetErrorString(ret));
0091 }
0092 ret = cudaRuntimeGetVersion(&runtimeVersion);
0093 if (ret != cudaSuccess) {
0094 FAIL("Unable to query the CUDA runtime API version: (" << ret << ") " << cudaGetErrorString(ret));
0095 }
0096
0097 SECTION("CUDA Queries") {
0098 WARN("CUDA Driver Version / Runtime Version: " << driverVersion / 1000 << "." << (driverVersion % 100) / 10
0099 << " / " << runtimeVersion / 1000 << "."
0100 << (runtimeVersion % 100) / 10);
0101
0102
0103
0104 REQUIRE(cuda->numberOfDevices() == deviceCount);
0105 WARN("Detected " << cuda->numberOfDevices() << " CUDA Capable device(s)");
0106
0107
0108
0109 for (int i = 0; i < deviceCount; ++i) {
0110 cudaDeviceProp deviceProp;
0111 ret = cudaGetDeviceProperties(&deviceProp, i);
0112 if (ret != cudaSuccess) {
0113 FAIL("Unable to query the CUDA properties for device " << i << " from the CUDA runtime API: (" << ret << ") "
0114 << cudaGetErrorString(ret));
0115 }
0116
0117 REQUIRE(deviceProp.major == cuda->computeCapability(i).first);
0118 REQUIRE(deviceProp.minor == cuda->computeCapability(i).second);
0119 INFO("Device " << i << ": " << deviceProp.name << "\n CUDA Capability Major/Minor version number: "
0120 << deviceProp.major << "." << deviceProp.minor);
0121 }
0122 }
0123
0124 SECTION("With ResourceInformationService available") {
0125 std::string config = makeProcess("Test");
0126 addResourceInformationService(config);
0127 addCUDAService(config);
0128 auto serviceToken = getServiceToken(config);
0129 edm::ServiceRegistry::Operate operate(serviceToken);
0130
0131 edm::Service<CUDAInterface> cuda;
0132 REQUIRE(cuda);
0133 REQUIRE(cuda->enabled());
0134 edm::Service<edm::ResourceInformation> ri;
0135 REQUIRE(ri);
0136 REQUIRE(ri->gpuModels().size() > 0);
0137 REQUIRE(ri->nvidiaDriverVersion().size() > 0);
0138 REQUIRE(ri->cudaDriverVersion() == driverVersion);
0139 REQUIRE(ri->cudaRuntimeVersion() == runtimeVersion);
0140 }
0141 }
0142
0143 SECTION("CUDAService disabled") {
0144 std::string config = makeProcess("Test");
0145 addCUDAService(config, false);
0146 auto serviceToken = getServiceToken(config);
0147 edm::ServiceRegistry::Operate operate(serviceToken);
0148
0149 edm::Service<CUDAInterface> cuda;
0150 REQUIRE(cuda->enabled() == false);
0151 REQUIRE(cuda->numberOfDevices() == 0);
0152 }
0153 }