1 | //===------- Offload API tests - gtest environment ------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "Environment.hpp" |
10 | #include "Fixtures.hpp" |
11 | #include "llvm/Support/CommandLine.h" |
12 | #include "llvm/Support/MemoryBuffer.h" |
13 | #include <OffloadAPI.h> |
14 | #include <fstream> |
15 | |
16 | using namespace llvm; |
17 | |
18 | // Wrapper so we don't have to constantly init and shutdown Offload in every |
19 | // test, while having sensible lifetime for the platform environment |
20 | struct OffloadInitWrapper { |
21 | OffloadInitWrapper() { olInit(); } |
22 | ~OffloadInitWrapper() { olShutDown(); } |
23 | }; |
24 | static OffloadInitWrapper Wrapper{}; |
25 | |
26 | static cl::opt<std::string> |
27 | SelectedPlatform("platform" , cl::desc("Only test the specified platform" ), |
28 | cl::value_desc("platform" )); |
29 | |
30 | raw_ostream &operator<<(raw_ostream &Out, |
31 | const ol_platform_handle_t &Platform) { |
32 | size_t Size; |
33 | olGetPlatformInfoSize(Platform, OL_PLATFORM_INFO_NAME, &Size); |
34 | std::vector<char> Name(Size); |
35 | olGetPlatformInfo(Platform, OL_PLATFORM_INFO_NAME, Size, Name.data()); |
36 | Out << Name.data(); |
37 | return Out; |
38 | } |
39 | |
40 | raw_ostream &operator<<(raw_ostream &Out, const ol_device_handle_t &Device) { |
41 | size_t Size; |
42 | olGetDeviceInfoSize(Device, OL_DEVICE_INFO_NAME, &Size); |
43 | std::vector<char> Name(Size); |
44 | olGetDeviceInfo(Device, OL_DEVICE_INFO_NAME, Size, Name.data()); |
45 | Out << Name.data(); |
46 | return Out; |
47 | } |
48 | |
49 | void printPlatforms() { |
50 | SmallDenseSet<ol_platform_handle_t> Platforms; |
51 | using DeviceVecT = SmallVector<ol_device_handle_t, 8>; |
52 | DeviceVecT Devices{}; |
53 | |
54 | olIterateDevices( |
55 | [](ol_device_handle_t D, void *Data) { |
56 | static_cast<DeviceVecT *>(Data)->push_back(D); |
57 | return true; |
58 | }, |
59 | &Devices); |
60 | |
61 | for (auto &Device : Devices) { |
62 | ol_platform_handle_t Platform; |
63 | olGetDeviceInfo(Device, OL_DEVICE_INFO_PLATFORM, sizeof(Platform), |
64 | &Platform); |
65 | Platforms.insert(Platform); |
66 | } |
67 | |
68 | for (const auto &Platform : Platforms) { |
69 | errs() << " * " << Platform << "\n" ; |
70 | } |
71 | } |
72 | |
73 | const std::vector<TestEnvironment::Device> &TestEnvironment::getDevices() { |
74 | static std::vector<TestEnvironment::Device> Devices{}; |
75 | if (Devices.empty()) { |
76 | // If a specific platform is requested, filter to devices belonging to it. |
77 | if (const char *EnvStr = getenv(name: "OFFLOAD_UNITTEST_PLATFORM" )) { |
78 | if (SelectedPlatform != "" ) |
79 | errs() << "Warning: --platform argument ignored as " |
80 | "OFFLOAD_UNITTEST_PLATFORM env var overrides it.\n" ; |
81 | SelectedPlatform = EnvStr; |
82 | } |
83 | |
84 | if (SelectedPlatform != "" ) { |
85 | olIterateDevices( |
86 | [](ol_device_handle_t D, void *Data) { |
87 | ol_platform_handle_t Platform; |
88 | olGetDeviceInfo(D, OL_DEVICE_INFO_PLATFORM, sizeof(Platform), |
89 | &Platform); |
90 | ol_platform_backend_t Backend; |
91 | olGetPlatformInfo(Platform, OL_PLATFORM_INFO_BACKEND, |
92 | sizeof(Backend), &Backend); |
93 | std::string PlatformName; |
94 | raw_string_ostream S(PlatformName); |
95 | S << Platform; |
96 | if (PlatformName == SelectedPlatform && |
97 | Backend != OL_PLATFORM_BACKEND_HOST) { |
98 | std::string Name; |
99 | raw_string_ostream NameStr(Name); |
100 | NameStr << PlatformName << "_" << D; |
101 | static_cast<std::vector<TestEnvironment::Device> *>(Data) |
102 | ->push_back({D, Name}); |
103 | } |
104 | return true; |
105 | }, |
106 | &Devices); |
107 | } else { |
108 | // No platform specified, discover every device that isn't the host. |
109 | olIterateDevices( |
110 | [](ol_device_handle_t D, void *Data) { |
111 | ol_platform_handle_t Platform; |
112 | olGetDeviceInfo(D, OL_DEVICE_INFO_PLATFORM, sizeof(Platform), |
113 | &Platform); |
114 | ol_platform_backend_t Backend; |
115 | olGetPlatformInfo(Platform, OL_PLATFORM_INFO_BACKEND, |
116 | sizeof(Backend), &Backend); |
117 | if (Backend != OL_PLATFORM_BACKEND_HOST) { |
118 | std::string Name; |
119 | raw_string_ostream NameStr(Name); |
120 | NameStr << Platform << "_" << D; |
121 | static_cast<std::vector<TestEnvironment::Device> *>(Data) |
122 | ->push_back({D, Name}); |
123 | } |
124 | return true; |
125 | }, |
126 | &Devices); |
127 | } |
128 | } |
129 | |
130 | return Devices; |
131 | } |
132 | |
133 | ol_device_handle_t TestEnvironment::getHostDevice() { |
134 | static ol_device_handle_t HostDevice = nullptr; |
135 | |
136 | if (!HostDevice) { |
137 | olIterateDevices( |
138 | [](ol_device_handle_t D, void *Data) { |
139 | ol_platform_handle_t Platform; |
140 | olGetDeviceInfo(D, OL_DEVICE_INFO_PLATFORM, sizeof(Platform), |
141 | &Platform); |
142 | ol_platform_backend_t Backend; |
143 | olGetPlatformInfo(Platform, OL_PLATFORM_INFO_BACKEND, sizeof(Backend), |
144 | &Backend); |
145 | |
146 | if (Backend == OL_PLATFORM_BACKEND_HOST) { |
147 | *(static_cast<ol_device_handle_t *>(Data)) = D; |
148 | return false; |
149 | } |
150 | |
151 | return true; |
152 | }, |
153 | &HostDevice); |
154 | } |
155 | |
156 | return HostDevice; |
157 | } |
158 | |
159 | // TODO: Allow overriding via cmd line arg |
160 | const std::string DeviceBinsDirectory = DEVICE_CODE_PATH; |
161 | |
162 | bool TestEnvironment::loadDeviceBinary( |
163 | const std::string &BinaryName, ol_device_handle_t Device, |
164 | std::unique_ptr<MemoryBuffer> &BinaryOut) { |
165 | |
166 | // Get the platform type |
167 | ol_platform_handle_t Platform; |
168 | olGetDeviceInfo(Device, OL_DEVICE_INFO_PLATFORM, sizeof(Platform), &Platform); |
169 | ol_platform_backend_t Backend = OL_PLATFORM_BACKEND_UNKNOWN; |
170 | olGetPlatformInfo(Platform, OL_PLATFORM_INFO_BACKEND, sizeof(Backend), |
171 | &Backend); |
172 | std::string FileExtension; |
173 | if (Backend == OL_PLATFORM_BACKEND_AMDGPU) { |
174 | FileExtension = ".amdgpu.bin" ; |
175 | } else if (Backend == OL_PLATFORM_BACKEND_CUDA) { |
176 | FileExtension = ".nvptx64.bin" ; |
177 | } else { |
178 | errs() << "Unsupported platform type for a device binary test.\n" ; |
179 | return false; |
180 | } |
181 | |
182 | std::string SourcePath = |
183 | DeviceBinsDirectory + "/" + BinaryName + FileExtension; |
184 | |
185 | auto SourceFile = MemoryBuffer::getFile(Filename: SourcePath, IsText: false, RequiresNullTerminator: false); |
186 | if (!SourceFile) { |
187 | errs() << "failed to read device binary file: " + SourcePath; |
188 | return false; |
189 | } |
190 | |
191 | BinaryOut = std::move(SourceFile.get()); |
192 | return true; |
193 | } |
194 | |