Line data Source code
1 : // SPDX-License-Identifier: Apache-2.0
2 :
3 : #include "kompute/Manager.hpp"
4 : #include "fmt/format.h"
5 : #include "kompute/logger/Logger.hpp"
6 : #include <fmt/core.h>
7 : #include <iterator>
8 : #include <set>
9 : #include <sstream>
10 : #include <string>
11 :
12 : namespace kp {
13 :
14 : #ifndef KOMPUTE_DISABLE_VK_DEBUG_LAYERS
15 : static VKAPI_ATTR VkBool32 VKAPI_CALL
16 0 : debugMessageCallback(VkDebugReportFlagsEXT /*flags*/,
17 : VkDebugReportObjectTypeEXT /*objectType*/,
18 : uint64_t /*object*/,
19 : size_t /*location*/,
20 : int32_t /*messageCode*/,
21 : #if KOMPUTE_OPT_ACTIVE_LOG_LEVEL <= KOMPUTE_LOG_LEVEL_DEBUG
22 : const char* pLayerPrefix,
23 : const char* pMessage,
24 : #else
25 : const char* /*pLayerPrefix*/,
26 : const char* /*pMessage*/,
27 : #endif
28 : void* /*pUserData*/)
29 : {
30 0 : KP_LOG_DEBUG("[VALIDATION]: {} - {}", pLayerPrefix, pMessage);
31 0 : return VK_FALSE;
32 : }
33 : #endif
34 :
35 47 : Manager::Manager()
36 47 : : Manager(0)
37 : {
38 47 : }
39 :
40 47 : Manager::Manager(uint32_t physicalDeviceIndex,
41 : const std::vector<uint32_t>& familyQueueIndices,
42 47 : const std::vector<std::string>& desiredExtensions)
43 : {
44 47 : this->mManageResources = true;
45 :
46 : // Make sure the logger is setup
47 : #if !KOMPUTE_OPT_LOG_LEVEL_DISABLED
48 47 : logger::setupLogger();
49 : #endif
50 :
51 47 : this->createInstance();
52 47 : this->createDevice(
53 : familyQueueIndices, physicalDeviceIndex, desiredExtensions);
54 47 : }
55 :
56 0 : Manager::Manager(std::shared_ptr<vk::Instance> instance,
57 : std::shared_ptr<vk::PhysicalDevice> physicalDevice,
58 0 : std::shared_ptr<vk::Device> device)
59 : {
60 0 : this->mManageResources = false;
61 :
62 0 : this->mInstance = instance;
63 0 : this->mPhysicalDevice = physicalDevice;
64 0 : this->mDevice = device;
65 :
66 : // Make sure the logger is setup
67 : #if !KOMPUTE_OPT_LOG_LEVEL_DISABLED
68 0 : logger::setupLogger();
69 : #endif
70 0 : }
71 :
72 47 : Manager::~Manager()
73 : {
74 94 : KP_LOG_DEBUG("Kompute Manager Destructor started");
75 47 : this->destroy();
76 47 : }
77 :
78 : void
79 48 : Manager::destroy()
80 : {
81 :
82 96 : KP_LOG_DEBUG("Kompute Manager destroy() started");
83 :
84 48 : if (this->mDevice == nullptr) {
85 2 : KP_LOG_ERROR(
86 : "Kompute Manager destructor reached with null Device pointer");
87 1 : return;
88 : }
89 :
90 47 : if (this->mManageResources && this->mManagedSequences.size()) {
91 80 : KP_LOG_DEBUG("Kompute Manager explicitly running destructor for "
92 : "managed sequences");
93 99 : for (const std::weak_ptr<Sequence>& weakSq : this->mManagedSequences) {
94 59 : if (std::shared_ptr<Sequence> sq = weakSq.lock()) {
95 12 : sq->destroy();
96 59 : }
97 : }
98 40 : this->mManagedSequences.clear();
99 : }
100 :
101 47 : if (this->mManageResources && this->mManagedAlgorithms.size()) {
102 62 : KP_LOG_DEBUG("Kompute Manager explicitly freeing algorithms");
103 31 : for (const std::weak_ptr<Algorithm>& weakAlgorithm :
104 98 : this->mManagedAlgorithms) {
105 36 : if (std::shared_ptr<Algorithm> algorithm = weakAlgorithm.lock()) {
106 0 : algorithm->destroy();
107 36 : }
108 : }
109 31 : this->mManagedAlgorithms.clear();
110 : }
111 :
112 47 : if (this->mManageResources && this->mManagedTensors.size()) {
113 80 : KP_LOG_DEBUG("Kompute Manager explicitly freeing tensors");
114 133 : for (const std::weak_ptr<Tensor>& weakTensor : this->mManagedTensors) {
115 93 : if (std::shared_ptr<Tensor> tensor = weakTensor.lock()) {
116 7 : tensor->destroy();
117 93 : }
118 : }
119 40 : this->mManagedTensors.clear();
120 : }
121 :
122 47 : if (this->mFreeDevice) {
123 94 : KP_LOG_INFO("Destroying device");
124 47 : this->mDevice->destroy(
125 : (vk::Optional<const vk::AllocationCallbacks>)nullptr);
126 47 : this->mDevice = nullptr;
127 94 : KP_LOG_DEBUG("Kompute Manager Destroyed Device");
128 : }
129 :
130 47 : if (this->mInstance == nullptr) {
131 0 : KP_LOG_ERROR(
132 : "Kompute Manager destructor reached with null Instance pointer");
133 0 : return;
134 : }
135 :
136 : #ifndef KOMPUTE_DISABLE_VK_DEBUG_LAYERS
137 47 : if (this->mDebugReportCallback) {
138 0 : this->mInstance->destroyDebugReportCallbackEXT(
139 0 : this->mDebugReportCallback, nullptr, this->mDebugDispatcher);
140 0 : KP_LOG_DEBUG("Kompute Manager Destroyed Debug Report Callback");
141 : }
142 : #endif
143 :
144 47 : if (this->mFreeInstance) {
145 47 : this->mInstance->destroy(
146 : (vk::Optional<const vk::AllocationCallbacks>)nullptr);
147 47 : this->mInstance = nullptr;
148 94 : KP_LOG_DEBUG("Kompute Manager Destroyed Instance");
149 : }
150 : }
151 :
152 : void
153 47 : Manager::createInstance()
154 : {
155 :
156 94 : KP_LOG_DEBUG("Kompute Manager creating instance");
157 :
158 47 : this->mFreeInstance = true;
159 :
160 47 : vk::ApplicationInfo applicationInfo;
161 47 : applicationInfo.pApplicationName = "Kompute";
162 47 : applicationInfo.pEngineName = "Kompute";
163 47 : applicationInfo.apiVersion = KOMPUTE_VK_API_VERSION;
164 47 : applicationInfo.engineVersion = KOMPUTE_VK_API_VERSION;
165 47 : applicationInfo.applicationVersion = KOMPUTE_VK_API_VERSION;
166 :
167 47 : std::vector<const char*> applicationExtensions;
168 :
169 : #ifndef KOMPUTE_DISABLE_VK_DEBUG_LAYERS
170 47 : applicationExtensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
171 : #endif
172 :
173 47 : vk::InstanceCreateInfo computeInstanceCreateInfo;
174 47 : computeInstanceCreateInfo.pApplicationInfo = &applicationInfo;
175 47 : if (!applicationExtensions.empty()) {
176 47 : computeInstanceCreateInfo.enabledExtensionCount =
177 47 : (uint32_t)applicationExtensions.size();
178 47 : computeInstanceCreateInfo.ppEnabledExtensionNames =
179 47 : applicationExtensions.data();
180 : }
181 :
182 : #ifndef KOMPUTE_DISABLE_VK_DEBUG_LAYERS
183 94 : KP_LOG_DEBUG("Kompute Manager adding debug validation layers");
184 : // We'll identify the layers that are supported
185 47 : std::vector<const char*> validLayerNames;
186 : std::vector<const char*> desiredLayerNames = {
187 : "VK_LAYER_LUNARG_assistant_layer",
188 : "VK_LAYER_LUNARG_standard_validation",
189 : "VK_LAYER_KHRONOS_validation",
190 47 : };
191 47 : std::vector<std::string> envLayerNames;
192 47 : const char* envLayerNamesVal = std::getenv("KOMPUTE_ENV_DEBUG_LAYERS");
193 47 : if (envLayerNamesVal != nullptr && *envLayerNamesVal != '\0') {
194 0 : KP_LOG_DEBUG("Kompute Manager adding environment layers: {}",
195 : envLayerNamesVal);
196 0 : std::istringstream iss(envLayerNamesVal);
197 0 : std::istream_iterator<std::string> beg(iss);
198 0 : std::istream_iterator<std::string> end;
199 0 : envLayerNames = std::vector<std::string>(beg, end);
200 0 : for (const std::string& layerName : envLayerNames) {
201 0 : desiredLayerNames.push_back(layerName.c_str());
202 : }
203 0 : KP_LOG_DEBUG("Desired layers: {}", fmt::join(desiredLayerNames, ", "));
204 0 : }
205 :
206 : // Identify the valid layer names based on the desiredLayerNames
207 : {
208 47 : std::set<std::string> uniqueLayerNames;
209 : std::vector<vk::LayerProperties> availableLayerProperties =
210 47 : vk::enumerateInstanceLayerProperties();
211 94 : for (vk::LayerProperties layerProperties : availableLayerProperties) {
212 47 : std::string layerName(layerProperties.layerName.data());
213 47 : uniqueLayerNames.insert(layerName);
214 47 : }
215 141 : KP_LOG_DEBUG("Available layers: {}", fmt::join(uniqueLayerNames, ", "));
216 188 : for (const char* desiredLayerName : desiredLayerNames) {
217 141 : if (uniqueLayerNames.count(desiredLayerName) != 0) {
218 0 : validLayerNames.push_back(desiredLayerName);
219 : }
220 : }
221 47 : }
222 :
223 47 : if (!validLayerNames.empty()) {
224 0 : KP_LOG_DEBUG(
225 : "Kompute Manager Initializing instance with valid layers: {}",
226 : fmt::join(validLayerNames, ", "));
227 0 : computeInstanceCreateInfo.enabledLayerCount =
228 0 : static_cast<uint32_t>(validLayerNames.size());
229 0 : computeInstanceCreateInfo.ppEnabledLayerNames = validLayerNames.data();
230 : } else {
231 94 : KP_LOG_WARN("Kompute Manager no valid layer names found from desired "
232 : "layer names");
233 : }
234 : #endif
235 :
236 : #if VK_USE_PLATFORM_ANDROID_KHR
237 : vk::DynamicLoader dl;
238 : PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr =
239 : dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
240 : VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);
241 : #endif // VK_USE_PLATFORM_ANDROID_KHR
242 :
243 47 : this->mInstance = std::make_shared<vk::Instance>();
244 47 : vk::createInstance(
245 : &computeInstanceCreateInfo, nullptr, this->mInstance.get());
246 :
247 : #if VK_USE_PLATFORM_ANDROID_KHR
248 : VULKAN_HPP_DEFAULT_DISPATCHER.init(*this->mInstance);
249 : #endif // VK_USE_PLATFORM_ANDROID_KHR
250 :
251 94 : KP_LOG_DEBUG("Kompute Manager Instance Created");
252 :
253 : #ifndef KOMPUTE_DISABLE_VK_DEBUG_LAYERS
254 94 : KP_LOG_DEBUG("Kompute Manager adding debug callbacks");
255 47 : if (validLayerNames.size() > 0) {
256 0 : vk::DebugReportFlagsEXT debugFlags =
257 : vk::DebugReportFlagBitsEXT::eError |
258 : vk::DebugReportFlagBitsEXT::eWarning;
259 0 : vk::DebugReportCallbackCreateInfoEXT debugCreateInfo = {};
260 0 : debugCreateInfo.pfnCallback =
261 : (PFN_vkDebugReportCallbackEXT)debugMessageCallback;
262 0 : debugCreateInfo.flags = debugFlags;
263 :
264 0 : this->mDebugDispatcher.init(*this->mInstance, &vkGetInstanceProcAddr);
265 : this->mDebugReportCallback =
266 0 : this->mInstance->createDebugReportCallbackEXT(
267 0 : debugCreateInfo, nullptr, this->mDebugDispatcher);
268 : }
269 : #endif
270 47 : }
271 :
272 : void
273 1 : Manager::clear()
274 : {
275 1 : if (this->mManageResources) {
276 2 : this->mManagedTensors.erase(
277 1 : std::remove_if(begin(this->mManagedTensors),
278 1 : end(this->mManagedTensors),
279 3 : [](std::weak_ptr<Tensor> t) { return t.expired(); }),
280 1 : end(this->mManagedTensors));
281 2 : this->mManagedAlgorithms.erase(
282 1 : std::remove_if(
283 1 : begin(this->mManagedAlgorithms),
284 1 : end(this->mManagedAlgorithms),
285 1 : [](std::weak_ptr<Algorithm> t) { return t.expired(); }),
286 1 : end(this->mManagedAlgorithms));
287 2 : this->mManagedSequences.erase(
288 1 : std::remove_if(begin(this->mManagedSequences),
289 1 : end(this->mManagedSequences),
290 3 : [](std::weak_ptr<Sequence> t) { return t.expired(); }),
291 2 : end(this->mManagedSequences));
292 : }
293 1 : }
294 :
295 : void
296 47 : Manager::createDevice(const std::vector<uint32_t>& familyQueueIndices,
297 : uint32_t physicalDeviceIndex,
298 : const std::vector<std::string>& desiredExtensions)
299 : {
300 :
301 94 : KP_LOG_DEBUG("Kompute Manager creating Device");
302 :
303 47 : if (this->mInstance == nullptr) {
304 0 : throw std::runtime_error("Kompute Manager instance is null");
305 : }
306 :
307 47 : this->mFreeDevice = true;
308 :
309 : // Getting an integer that says how many vuklan devices we have
310 : std::vector<vk::PhysicalDevice> physicalDevices =
311 47 : this->mInstance->enumeratePhysicalDevices();
312 47 : uint32_t deviceCount = physicalDevices.size();
313 :
314 : // This means there are no devices at all
315 47 : if (deviceCount == 0) {
316 0 : throw std::runtime_error("Failed to find GPUs with Vulkan support! "
317 0 : "Maybe you haven't installed vulkan drivers?");
318 : }
319 :
320 : // This means that we're exceeding our device limit, for
321 : // example if we have 2 devices, just physicalDeviceIndex
322 : // 0 and 1 are acceptable. Hence, physicalDeviceIndex should
323 : // always be less than deviceCount, else we raise an error
324 47 : if (!(deviceCount > physicalDeviceIndex)) {
325 0 : throw std::runtime_error("There is no such physical index or device, "
326 0 : "please use your existing device");
327 : }
328 :
329 47 : vk::PhysicalDevice physicalDevice = physicalDevices[physicalDeviceIndex];
330 :
331 : this->mPhysicalDevice =
332 47 : std::make_shared<vk::PhysicalDevice>(physicalDevice);
333 :
334 : #if KOMPUTE_OPT_ACTIVE_LOG_LEVEL <= KOMPUTE_LOG_LEVEL_INFO
335 : vk::PhysicalDeviceProperties physicalDeviceProperties =
336 47 : physicalDevice.getProperties();
337 : #endif
338 :
339 141 : KP_LOG_INFO("Using physical device index {} found {}",
340 : physicalDeviceIndex,
341 : physicalDeviceProperties.deviceName.data());
342 :
343 47 : if (familyQueueIndices.empty()) {
344 : // Find compute queue
345 : std::vector<vk::QueueFamilyProperties> allQueueFamilyProperties =
346 47 : physicalDevice.getQueueFamilyProperties();
347 :
348 47 : uint32_t computeQueueFamilyIndex = 0;
349 47 : bool computeQueueSupported = false;
350 47 : for (uint32_t i = 0; i < allQueueFamilyProperties.size(); i++) {
351 : vk::QueueFamilyProperties queueFamilyProperties =
352 47 : allQueueFamilyProperties[i];
353 :
354 47 : if (queueFamilyProperties.queueFlags &
355 47 : vk::QueueFlagBits::eCompute) {
356 47 : computeQueueFamilyIndex = i;
357 47 : computeQueueSupported = true;
358 47 : break;
359 : }
360 : }
361 :
362 47 : if (!computeQueueSupported) {
363 0 : throw std::runtime_error("Compute queue is not supported");
364 : }
365 :
366 47 : this->mComputeQueueFamilyIndices.push_back(computeQueueFamilyIndex);
367 47 : } else {
368 0 : this->mComputeQueueFamilyIndices = familyQueueIndices;
369 : }
370 :
371 47 : std::unordered_map<uint32_t, uint32_t> familyQueueCounts;
372 47 : std::unordered_map<uint32_t, std::vector<float>> familyQueuePriorities;
373 94 : for (const auto& value : this->mComputeQueueFamilyIndices) {
374 47 : familyQueueCounts[value]++;
375 47 : familyQueuePriorities[value].push_back(1.0f);
376 : }
377 :
378 47 : std::unordered_map<uint32_t, uint32_t> familyQueueIndexCount;
379 47 : std::vector<vk::DeviceQueueCreateInfo> deviceQueueCreateInfos;
380 94 : for (const auto& familyQueueInfo : familyQueueCounts) {
381 : // Setting the device count to 0
382 47 : familyQueueIndexCount[familyQueueInfo.first] = 0;
383 :
384 : // Creating the respective device queue
385 : vk::DeviceQueueCreateInfo deviceQueueCreateInfo(
386 : vk::DeviceQueueCreateFlags(),
387 47 : familyQueueInfo.first,
388 47 : familyQueueInfo.second,
389 47 : familyQueuePriorities[familyQueueInfo.first].data());
390 47 : deviceQueueCreateInfos.push_back(deviceQueueCreateInfo);
391 : }
392 :
393 141 : KP_LOG_DEBUG("Kompute Manager desired extension layers {}",
394 : fmt::join(desiredExtensions, ", "));
395 :
396 : std::vector<vk::ExtensionProperties> deviceExtensions =
397 47 : this->mPhysicalDevice->enumerateDeviceExtensionProperties();
398 :
399 47 : std::set<std::string> uniqueExtensionNames;
400 3619 : for (const vk::ExtensionProperties& ext : deviceExtensions) {
401 3572 : uniqueExtensionNames.insert(ext.extensionName);
402 : }
403 141 : KP_LOG_DEBUG("Kompute Manager available extensions {}",
404 : fmt::join(uniqueExtensionNames, ", "));
405 47 : std::vector<const char*> validExtensions;
406 47 : for (const std::string& ext : desiredExtensions) {
407 0 : if (uniqueExtensionNames.count(ext) != 0) {
408 0 : validExtensions.push_back(ext.c_str());
409 : }
410 : }
411 47 : if (desiredExtensions.size() != validExtensions.size()) {
412 0 : KP_LOG_ERROR("Kompute Manager not all extensions were added: {}",
413 : fmt::join(validExtensions, ", "));
414 : }
415 :
416 : vk::DeviceCreateInfo deviceCreateInfo(vk::DeviceCreateFlags(),
417 47 : deviceQueueCreateInfos.size(),
418 47 : deviceQueueCreateInfos.data(),
419 : {},
420 : {},
421 47 : validExtensions.size(),
422 141 : validExtensions.data());
423 :
424 47 : this->mDevice = std::make_shared<vk::Device>();
425 47 : physicalDevice.createDevice(
426 : &deviceCreateInfo, nullptr, this->mDevice.get());
427 94 : KP_LOG_DEBUG("Kompute Manager device created");
428 :
429 94 : for (const uint32_t& familyQueueIndex : this->mComputeQueueFamilyIndices) {
430 47 : std::shared_ptr<vk::Queue> currQueue = std::make_shared<vk::Queue>();
431 :
432 47 : this->mDevice->getQueue(familyQueueIndex,
433 47 : familyQueueIndexCount[familyQueueIndex],
434 : currQueue.get());
435 :
436 47 : familyQueueIndexCount[familyQueueIndex]++;
437 :
438 47 : this->mComputeQueues.push_back(currQueue);
439 47 : }
440 :
441 94 : KP_LOG_DEBUG("Kompute Manager compute queue obtained");
442 47 : }
443 :
444 : std::shared_ptr<Sequence>
445 62 : Manager::sequence(uint32_t queueIndex, uint32_t totalTimestamps)
446 : {
447 124 : KP_LOG_DEBUG("Kompute Manager sequence() with queueIndex: {}", queueIndex);
448 :
449 : std::shared_ptr<Sequence> sq{ new kp::Sequence(
450 62 : this->mPhysicalDevice,
451 62 : this->mDevice,
452 62 : this->mComputeQueues[queueIndex],
453 62 : this->mComputeQueueFamilyIndices[queueIndex],
454 124 : totalTimestamps) };
455 :
456 62 : if (this->mManageResources) {
457 62 : this->mManagedSequences.push_back(sq);
458 : }
459 :
460 62 : return sq;
461 0 : }
462 :
463 : vk::PhysicalDeviceProperties
464 1 : Manager::getDeviceProperties() const
465 : {
466 2 : return this->mPhysicalDevice->getProperties();
467 : }
468 :
469 : std::vector<vk::PhysicalDevice>
470 1 : Manager::listDevices() const
471 : {
472 1 : return this->mInstance->enumeratePhysicalDevices();
473 : }
474 :
475 : std::shared_ptr<vk::Instance>
476 0 : Manager::getVkInstance() const
477 : {
478 0 : return this->mInstance;
479 : }
480 :
481 : }
|