Spaces:
Runtime error
Runtime error
| // SPDX-License-Identifier: Apache-2.0 | |
| namespace kp { | |
| static VKAPI_ATTR VkBool32 VKAPI_CALL | |
| debugMessageCallback(VkDebugReportFlagsEXT /*flags*/, | |
| VkDebugReportObjectTypeEXT /*objectType*/, | |
| uint64_t /*object*/, | |
| size_t /*location*/, | |
| int32_t /*messageCode*/, | |
| #if KOMPUTE_OPT_ACTIVE_LOG_LEVEL <= KOMPUTE_LOG_LEVEL_DEBUG | |
| const char* pLayerPrefix, | |
| const char* pMessage, | |
| #else | |
| const char* /*pLayerPrefix*/, | |
| const char* /*pMessage*/, | |
| #endif | |
| void* /*pUserData*/) | |
| { | |
| KP_LOG_DEBUG("[VALIDATION]: {} - {}", pLayerPrefix, pMessage); | |
| return VK_FALSE; | |
| } | |
| Manager::Manager() | |
| { | |
| this->mManageResources = true; | |
| // Make sure the logger is setup | |
| logger::setupLogger(); | |
| this->createInstance(); | |
| } | |
| void Manager::initializeDevice(uint32_t physicalDeviceIndex, | |
| const std::vector<uint32_t>& familyQueueIndices, | |
| const std::vector<std::string>& desiredExtensions) | |
| { | |
| this->createDevice( | |
| familyQueueIndices, physicalDeviceIndex, desiredExtensions); | |
| } | |
| Manager::~Manager() | |
| { | |
| KP_LOG_DEBUG("Kompute Manager Destructor started"); | |
| this->destroy(); | |
| } | |
| void | |
| Manager::destroy() | |
| { | |
| KP_LOG_DEBUG("Kompute Manager destroy() started"); | |
| if (this->mDevice == nullptr) { | |
| KP_LOG_ERROR( | |
| "Kompute Manager destructor reached with null Device pointer"); | |
| return; | |
| } | |
| if (this->mManageResources && this->mManagedSequences.size()) { | |
| KP_LOG_DEBUG("Kompute Manager explicitly running destructor for " | |
| "managed sequences"); | |
| for (const std::weak_ptr<Sequence>& weakSq : this->mManagedSequences) { | |
| if (std::shared_ptr<Sequence> sq = weakSq.lock()) { | |
| sq->destroy(); | |
| } | |
| } | |
| this->mManagedSequences.clear(); | |
| } | |
| if (this->mManageResources && !this->mManagedAlgorithmsMap.empty()) { | |
| KP_LOG_DEBUG("Kompute Manager explicitly freeing algorithms"); | |
| for (const auto& kv : this->mManagedAlgorithmsMap) { | |
| if (std::shared_ptr<Algorithm> algorithm = kv.second) { | |
| algorithm->destroy(); | |
| } | |
| } | |
| this->mManagedAlgorithmsMap.clear(); | |
| } | |
| if (this->mManageResources && this->mManagedTensors.size()) { | |
| KP_LOG_DEBUG("Kompute Manager explicitly freeing tensors"); | |
| for (const std::weak_ptr<Tensor>& weakTensor : this->mManagedTensors) { | |
| if (std::shared_ptr<Tensor> tensor = weakTensor.lock()) { | |
| tensor->destroy(); | |
| } | |
| } | |
| this->mManagedTensors.clear(); | |
| } | |
| if (this->mPipelineCache) { | |
| KP_LOG_DEBUG("Kompute Manager Destroying pipeline cache"); | |
| if (!this->mPipelineCache) { | |
| KP_LOG_WARN("Kompute Manager Error requested to destroy " | |
| "pipeline cache but it is null"); | |
| } | |
| this->mDevice->destroy( | |
| *this->mPipelineCache, | |
| (vk::Optional<const vk::AllocationCallbacks>)nullptr); | |
| this->mPipelineCache = nullptr; | |
| } | |
| if (this->mFreeDevice) { | |
| KP_LOG_INFO("Destroying device"); | |
| this->mDevice->destroy( | |
| (vk::Optional<const vk::AllocationCallbacks>)nullptr); | |
| this->mDevice = nullptr; | |
| KP_LOG_DEBUG("Kompute Manager Destroyed Device"); | |
| } | |
| if (this->mInstance == nullptr) { | |
| KP_LOG_ERROR( | |
| "Kompute Manager destructor reached with null Instance pointer"); | |
| return; | |
| } | |
| if (this->mDebugReportCallback) { | |
| this->mInstance->destroyDebugReportCallbackEXT( | |
| this->mDebugReportCallback, nullptr, this->mDebugDispatcher); | |
| KP_LOG_DEBUG("Kompute Manager Destroyed Debug Report Callback"); | |
| } | |
| if (this->mFreeInstance) { | |
| this->mInstance->destroy( | |
| (vk::Optional<const vk::AllocationCallbacks>)nullptr); | |
| this->mInstance = nullptr; | |
| KP_LOG_DEBUG("Kompute Manager Destroyed Instance"); | |
| } | |
| } | |
| void | |
| Manager::createInstance() | |
| { | |
| KP_LOG_DEBUG("Kompute Manager creating instance"); | |
| this->mFreeInstance = true; | |
| vk::ApplicationInfo applicationInfo; | |
| applicationInfo.pApplicationName = "Kompute"; | |
| applicationInfo.pEngineName = "Kompute"; | |
| applicationInfo.apiVersion = KOMPUTE_VK_API_VERSION; | |
| applicationInfo.engineVersion = KOMPUTE_VK_API_VERSION; | |
| applicationInfo.applicationVersion = KOMPUTE_VK_API_VERSION; | |
| std::vector<const char*> applicationExtensions; | |
| applicationExtensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); | |
| vk::InstanceCreateInfo computeInstanceCreateInfo; | |
| computeInstanceCreateInfo.pApplicationInfo = &applicationInfo; | |
| if (!applicationExtensions.empty()) { | |
| computeInstanceCreateInfo.enabledExtensionCount = | |
| (uint32_t)applicationExtensions.size(); | |
| computeInstanceCreateInfo.ppEnabledExtensionNames = | |
| applicationExtensions.data(); | |
| } | |
| try { | |
| mDynamicLoader = std::make_shared<vk::DynamicLoader>(); | |
| } catch (const std::exception & err) { | |
| return; | |
| } | |
| PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = | |
| mDynamicLoader->getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr"); | |
| VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr); | |
| KP_LOG_DEBUG("Kompute Manager adding debug validation layers"); | |
| // We'll identify the layers that are supported | |
| std::vector<const char*> validLayerNames; | |
| std::vector<const char*> desiredLayerNames = { | |
| "VK_LAYER_LUNARG_assistant_layer", | |
| "VK_LAYER_LUNARG_standard_validation", | |
| "VK_LAYER_KHRONOS_validation", | |
| }; | |
| std::vector<std::string> envLayerNames; | |
| const char* envLayerNamesVal = std::getenv("KOMPUTE_ENV_DEBUG_LAYERS"); | |
| if (envLayerNamesVal != nullptr && *envLayerNamesVal != '\0') { | |
| KP_LOG_DEBUG("Kompute Manager adding environment layers: {}", | |
| envLayerNamesVal); | |
| std::istringstream iss(envLayerNamesVal); | |
| std::istream_iterator<std::string> beg(iss); | |
| std::istream_iterator<std::string> end; | |
| envLayerNames = std::vector<std::string>(beg, end); | |
| for (const std::string& layerName : envLayerNames) { | |
| desiredLayerNames.push_back(layerName.c_str()); | |
| } | |
| KP_LOG_DEBUG("Desired layers: {}", fmt::join(desiredLayerNames, ", ")); | |
| } | |
| // Identify the valid layer names based on the desiredLayerNames | |
| { | |
| std::set<std::string> uniqueLayerNames; | |
| std::vector<vk::LayerProperties> availableLayerProperties = | |
| vk::enumerateInstanceLayerProperties(); | |
| for (vk::LayerProperties layerProperties : availableLayerProperties) { | |
| std::string layerName(layerProperties.layerName.data()); | |
| uniqueLayerNames.insert(layerName); | |
| } | |
| KP_LOG_DEBUG("Available layers: {}", fmt::join(uniqueLayerNames, ", ")); | |
| for (const char* desiredLayerName : desiredLayerNames) { | |
| if (uniqueLayerNames.count(desiredLayerName) != 0) { | |
| validLayerNames.push_back(desiredLayerName); | |
| } | |
| } | |
| } | |
| if (!validLayerNames.empty()) { | |
| KP_LOG_DEBUG( | |
| "Kompute Manager Initializing instance with valid layers: {}", | |
| fmt::join(validLayerNames, ", ")); | |
| computeInstanceCreateInfo.enabledLayerCount = | |
| static_cast<uint32_t>(validLayerNames.size()); | |
| computeInstanceCreateInfo.ppEnabledLayerNames = validLayerNames.data(); | |
| } else { | |
| KP_LOG_WARN("Kompute Manager no valid layer names found from desired " | |
| "layer names"); | |
| } | |
| this->mInstance = std::make_shared<vk::Instance>(); | |
| vk::Result r = vk::createInstance( | |
| &computeInstanceCreateInfo, nullptr, this->mInstance.get()); | |
| if (r != vk::Result::eSuccess) { | |
| KP_LOG_ERROR( | |
| "Kompute Manager Error allocating vulkan instance", vk::to_string(r)); | |
| this->mInstance = nullptr; | |
| this->mFreeInstance = false; | |
| return; | |
| } | |
| VULKAN_HPP_DEFAULT_DISPATCHER.init(*this->mInstance); | |
| KP_LOG_DEBUG("Kompute Manager Instance Created"); | |
| KP_LOG_DEBUG("Kompute Manager adding debug callbacks"); | |
| if (validLayerNames.size() > 0) { | |
| vk::DebugReportFlagsEXT debugFlags = | |
| vk::DebugReportFlagBitsEXT::eError | | |
| vk::DebugReportFlagBitsEXT::eWarning; | |
| vk::DebugReportCallbackCreateInfoEXT debugCreateInfo = {}; | |
| debugCreateInfo.pfnCallback = | |
| (PFN_vkDebugReportCallbackEXT)debugMessageCallback; | |
| debugCreateInfo.flags = debugFlags; | |
| this->mDebugDispatcher.init(*this->mInstance, vkGetInstanceProcAddr); | |
| this->mDebugReportCallback = | |
| this->mInstance->createDebugReportCallbackEXT( | |
| debugCreateInfo, nullptr, this->mDebugDispatcher); | |
| } | |
| } | |
| void | |
| Manager::clear() | |
| { | |
| if (this->mManageResources) { | |
| this->mManagedTensors.erase( | |
| std::remove_if(begin(this->mManagedTensors), | |
| end(this->mManagedTensors), | |
| [](std::weak_ptr<Tensor> t) { return t.expired(); }), | |
| end(this->mManagedTensors)); | |
| for (auto it = this->mManagedAlgorithmsMap.begin(); | |
| it != this->mManagedAlgorithmsMap.end();) { | |
| if (it->second) { | |
| it = this->mManagedAlgorithmsMap.erase(it); | |
| } else { | |
| ++it; | |
| } | |
| } | |
| this->mManagedSequences.erase( | |
| std::remove_if(begin(this->mManagedSequences), | |
| end(this->mManagedSequences), | |
| [](std::weak_ptr<Sequence> t) { return t.expired(); }), | |
| end(this->mManagedSequences)); | |
| } | |
| } | |
| void | |
| Manager::createDevice(const std::vector<uint32_t>& familyQueueIndices, | |
| uint32_t physicalDeviceIndex, | |
| const std::vector<std::string>& desiredExtensions) | |
| { | |
| KP_LOG_DEBUG("Kompute Manager creating Device"); | |
| if (this->mInstance == nullptr) { | |
| throw std::runtime_error("Kompute Manager instance is null"); | |
| } | |
| this->mFreeDevice = true; | |
| // Getting an integer that says how many vuklan devices we have | |
| std::vector<vk::PhysicalDevice> physicalDevices = | |
| this->mInstance->enumeratePhysicalDevices(); | |
| uint32_t deviceCount = physicalDevices.size(); | |
| // This means there are no devices at all | |
| if (deviceCount == 0) { | |
| throw std::runtime_error("Failed to find GPUs with Vulkan support! " | |
| "Maybe you haven't installed vulkan drivers?"); | |
| } | |
| // This means that we're exceeding our device limit, for | |
| // example if we have 2 devices, just physicalDeviceIndex | |
| // 0 and 1 are acceptable. Hence, physicalDeviceIndex should | |
| // always be less than deviceCount, else we raise an error | |
| if (!(deviceCount > physicalDeviceIndex)) { | |
| throw std::runtime_error("There is no such physical index or device, " | |
| "please use your existing device"); | |
| } | |
| vk::PhysicalDevice physicalDevice = physicalDevices[physicalDeviceIndex]; | |
| this->mPhysicalDevice = | |
| std::make_shared<vk::PhysicalDevice>(physicalDevice); | |
| vk::PhysicalDeviceProperties physicalDeviceProperties = | |
| physicalDevice.getProperties(); | |
| KP_LOG_INFO("Using physical device index {} found {}", | |
| physicalDeviceIndex, | |
| physicalDeviceProperties.deviceName.data()); | |
| if (familyQueueIndices.empty()) { | |
| // Find compute queue | |
| std::vector<vk::QueueFamilyProperties> allQueueFamilyProperties = | |
| physicalDevice.getQueueFamilyProperties(); | |
| uint32_t computeQueueFamilyIndex = 0; | |
| bool computeQueueSupported = false; | |
| for (uint32_t i = 0; i < allQueueFamilyProperties.size(); i++) { | |
| vk::QueueFamilyProperties queueFamilyProperties = | |
| allQueueFamilyProperties[i]; | |
| if (queueFamilyProperties.queueFlags & | |
| vk::QueueFlagBits::eCompute) { | |
| computeQueueFamilyIndex = i; | |
| computeQueueSupported = true; | |
| break; | |
| } | |
| } | |
| if (!computeQueueSupported) { | |
| throw std::runtime_error("Compute queue is not supported"); | |
| } | |
| this->mComputeQueueFamilyIndices.push_back(computeQueueFamilyIndex); | |
| } else { | |
| this->mComputeQueueFamilyIndices = familyQueueIndices; | |
| } | |
| std::unordered_map<uint32_t, uint32_t> familyQueueCounts; | |
| std::unordered_map<uint32_t, std::vector<float>> familyQueuePriorities; | |
| for (const auto& value : this->mComputeQueueFamilyIndices) { | |
| familyQueueCounts[value]++; | |
| familyQueuePriorities[value].push_back(1.0f); | |
| } | |
| std::unordered_map<uint32_t, uint32_t> familyQueueIndexCount; | |
| std::vector<vk::DeviceQueueCreateInfo> deviceQueueCreateInfos; | |
| for (const auto& familyQueueInfo : familyQueueCounts) { | |
| // Setting the device count to 0 | |
| familyQueueIndexCount[familyQueueInfo.first] = 0; | |
| // Creating the respective device queue | |
| vk::DeviceQueueCreateInfo deviceQueueCreateInfo( | |
| vk::DeviceQueueCreateFlags(), | |
| familyQueueInfo.first, | |
| familyQueueInfo.second, | |
| familyQueuePriorities[familyQueueInfo.first].data()); | |
| deviceQueueCreateInfos.push_back(deviceQueueCreateInfo); | |
| } | |
| KP_LOG_DEBUG("Kompute Manager desired extension layers {}", | |
| fmt::join(desiredExtensions, ", ")); | |
| std::vector<vk::ExtensionProperties> deviceExtensions = | |
| this->mPhysicalDevice->enumerateDeviceExtensionProperties(); | |
| std::set<std::string> uniqueExtensionNames; | |
| for (const vk::ExtensionProperties& ext : deviceExtensions) { | |
| uniqueExtensionNames.insert(ext.extensionName); | |
| } | |
| KP_LOG_DEBUG("Kompute Manager available extensions {}", | |
| fmt::join(uniqueExtensionNames, ", ")); | |
| std::vector<const char*> validExtensions; | |
| for (const std::string& ext : desiredExtensions) { | |
| if (uniqueExtensionNames.count(ext) != 0) { | |
| validExtensions.push_back(ext.c_str()); | |
| } | |
| } | |
| if (desiredExtensions.size() != validExtensions.size()) { | |
| KP_LOG_ERROR("Kompute Manager not all extensions were added: {}", | |
| fmt::join(validExtensions, ", ")); | |
| } | |
| vk::PhysicalDeviceFeatures features; | |
| features.shaderInt16 = true; | |
| vk::PhysicalDeviceVulkan11Features features11; | |
| features11.uniformAndStorageBuffer16BitAccess = true; | |
| features11.storageBuffer16BitAccess = true; | |
| features11.pNext = nullptr; | |
| vk::PhysicalDeviceVulkan12Features features12; | |
| features12.storageBuffer8BitAccess = true; | |
| features12.uniformAndStorageBuffer8BitAccess = true; | |
| features12.shaderFloat16 = true; | |
| features12.shaderInt8 = true; | |
| features12.pNext = &features11; | |
| vk::DeviceCreateInfo deviceCreateInfo(vk::DeviceCreateFlags(), | |
| deviceQueueCreateInfos.size(), | |
| deviceQueueCreateInfos.data(), | |
| {}, | |
| {}, | |
| validExtensions.size(), | |
| validExtensions.data(), | |
| &features); | |
| deviceCreateInfo.pNext = &features12; | |
| this->mDevice = std::make_shared<vk::Device>(); | |
| vk::Result r = physicalDevice.createDevice( | |
| &deviceCreateInfo, nullptr, this->mDevice.get()); | |
| if (r != vk::Result::eSuccess) { | |
| KP_LOG_ERROR("Kompute Manager could not create device"); | |
| } | |
| KP_LOG_DEBUG("Kompute Manager device created"); | |
| for (const uint32_t& familyQueueIndex : this->mComputeQueueFamilyIndices) { | |
| std::shared_ptr<vk::Queue> currQueue = std::make_shared<vk::Queue>(); | |
| this->mDevice->getQueue(familyQueueIndex, | |
| familyQueueIndexCount[familyQueueIndex], | |
| currQueue.get()); | |
| familyQueueIndexCount[familyQueueIndex]++; | |
| this->mComputeQueues.push_back(currQueue); | |
| } | |
| KP_LOG_DEBUG("Kompute Manager compute queue obtained"); | |
| mPipelineCache = std::make_shared<vk::PipelineCache>(); | |
| vk::PipelineCacheCreateInfo pipelineCacheInfo = | |
| vk::PipelineCacheCreateInfo(); | |
| this->mDevice->createPipelineCache( | |
| &pipelineCacheInfo, nullptr, mPipelineCache.get()); | |
| } | |
| std::shared_ptr<Sequence> | |
| Manager::sequence(uint32_t queueIndex, uint32_t totalTimestamps) | |
| { | |
| KP_LOG_DEBUG("Kompute Manager sequence() with queueIndex: {}", queueIndex); | |
| std::shared_ptr<Sequence> sq{ new kp::Sequence( | |
| this->mPhysicalDevice, | |
| this->mDevice, | |
| this->mComputeQueues[queueIndex], | |
| this->mComputeQueueFamilyIndices[queueIndex], | |
| totalTimestamps) }; | |
| if (this->mManageResources) { | |
| this->mManagedSequences.push_back(sq); | |
| } | |
| return sq; | |
| } | |
| vk::PhysicalDeviceProperties | |
| Manager::getDeviceProperties() const | |
| { | |
| return this->mPhysicalDevice->getProperties(); | |
| } | |
| std::vector<vk::PhysicalDevice> | |
| Manager::listDevices() const | |
| { | |
| return this->mInstance->enumeratePhysicalDevices(); | |
| } | |
| std::shared_ptr<vk::Instance> | |
| Manager::getVkInstance() const | |
| { | |
| return this->mInstance; | |
| } | |
| } | |