LCOV - code coverage report
Current view: top level - src - Manager.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 190 241 78.8 %
Date: 2024-01-20 13:42:20 Functions: 13 16 81.2 %

          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             : }

Generated by: LCOV version 1.14