LCOV - code coverage report
Current view: top level - src - Algorithm.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 166 174 95.4 %
Date: 2024-01-20 13:42:20 Functions: 12 12 100.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: Apache-2.0
       2             : #include <fstream>
       3             : 
       4             : #include "kompute/Algorithm.hpp"
       5             : 
       6             : namespace kp {
       7             : 
       8          37 : Algorithm::~Algorithm()
       9             : {
      10          74 :     KP_LOG_DEBUG("Kompute Algorithm Destructor started");
      11             : 
      12          37 :     this->destroy();
      13          37 : }
      14             : 
      15             : bool
      16          38 : Algorithm::isInit()
      17             : {
      18          40 :     return this->mPipeline && this->mPipelineCache && this->mPipelineLayout &&
      19           3 :            this->mDescriptorPool && this->mDescriptorSet &&
      20          40 :            this->mDescriptorSetLayout && this->mShaderModule;
      21             : }
      22             : 
      23             : void
      24          38 : Algorithm::destroy()
      25             : {
      26             :     // We don't have to free memory on destroy as it's freed by the
      27             :     // commandBuffer destructor if (this->mPushConstantsData) {
      28             :     //     free(this->mPushConstantsData);
      29             :     // }
      30             :     // if (this->mSpecializationConstantsData) {
      31             :     //     free(this->mSpecializationConstantsData);
      32             :     // }
      33             : 
      34          38 :     if (!this->mDevice) {
      35           0 :         KP_LOG_WARN("Kompute Algorithm destroy function reached with null "
      36             :                     "Device pointer");
      37           0 :         return;
      38             :     }
      39             : 
      40          38 :     if (this->mFreePipeline && this->mPipeline) {
      41          76 :         KP_LOG_DEBUG("Kompute Algorithm Destroying pipeline");
      42          38 :         if (!this->mPipeline) {
      43           0 :             KP_LOG_WARN("Kompute Algorithm Error requested to destroy "
      44             :                         "pipeline but it is null");
      45             :         }
      46          38 :         this->mDevice->destroy(
      47          38 :           *this->mPipeline,
      48             :           (vk::Optional<const vk::AllocationCallbacks>)nullptr);
      49          38 :         this->mPipeline = nullptr;
      50             :     }
      51             : 
      52          38 :     if (this->mFreePipelineCache && this->mPipelineCache) {
      53          76 :         KP_LOG_DEBUG("Kompute Algorithm Destroying pipeline cache");
      54          38 :         if (!this->mPipelineCache) {
      55           0 :             KP_LOG_WARN("Kompute Algorithm Error requested to destroy "
      56             :                         "pipeline cache but it is null");
      57             :         }
      58          38 :         this->mDevice->destroy(
      59          38 :           *this->mPipelineCache,
      60             :           (vk::Optional<const vk::AllocationCallbacks>)nullptr);
      61          38 :         this->mPipelineCache = nullptr;
      62             :     }
      63             : 
      64          38 :     if (this->mFreePipelineLayout && this->mPipelineLayout) {
      65          76 :         KP_LOG_DEBUG("Kompute Algorithm Destroying pipeline layout");
      66          38 :         if (!this->mPipelineLayout) {
      67           0 :             KP_LOG_WARN("Kompute Algorithm Error requested to destroy "
      68             :                         "pipeline layout but it is null");
      69             :         }
      70          38 :         this->mDevice->destroy(
      71          38 :           *this->mPipelineLayout,
      72             :           (vk::Optional<const vk::AllocationCallbacks>)nullptr);
      73          38 :         this->mPipelineLayout = nullptr;
      74             :     }
      75             : 
      76          38 :     if (this->mFreeShaderModule && this->mShaderModule) {
      77          76 :         KP_LOG_DEBUG("Kompute Algorithm Destroying shader module");
      78          38 :         if (!this->mShaderModule) {
      79           0 :             KP_LOG_WARN("Kompute Algorithm Error requested to destroy shader "
      80             :                         "module but it is null");
      81             :         }
      82          38 :         this->mDevice->destroy(
      83          38 :           *this->mShaderModule,
      84             :           (vk::Optional<const vk::AllocationCallbacks>)nullptr);
      85          38 :         this->mShaderModule = nullptr;
      86             :     }
      87             : 
      88             :     // We don't call freeDescriptorSet as the descriptor pool is not created
      89             :     // with VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT more at
      90             :     // (https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#VUID-vkFreeDescriptorSets-descriptorPool-00312))
      91             :     // if (this->mFreeDescriptorSet && this->mDescriptorSet) {
      92             :     //    KP_LOG_DEBUG("Kompute Algorithm Freeing Descriptor Set");
      93             :     //    if (!this->mDescriptorSet) {
      94             :     //        KP_LOG_WARN(
      95             :     //          "Kompute Algorithm Error requested to free descriptor set");
      96             :     //    }
      97             :     //    this->mDevice->freeDescriptorSets(
      98             :     //      *this->mDescriptorPool, 1, this->mDescriptorSet.get());
      99             :     //    this->mDescriptorSet = nullptr;
     100             :     //}
     101             : 
     102          38 :     if (this->mFreeDescriptorSetLayout && this->mDescriptorSetLayout) {
     103          76 :         KP_LOG_DEBUG("Kompute Algorithm Destroying Descriptor Set Layout");
     104          38 :         if (!this->mDescriptorSetLayout) {
     105           0 :             KP_LOG_WARN("Kompute Algorithm Error requested to destroy "
     106             :                         "descriptor set layout but it is null");
     107             :         }
     108          38 :         this->mDevice->destroy(
     109          38 :           *this->mDescriptorSetLayout,
     110             :           (vk::Optional<const vk::AllocationCallbacks>)nullptr);
     111          38 :         this->mDescriptorSetLayout = nullptr;
     112             :     }
     113             : 
     114          38 :     if (this->mFreeDescriptorPool && this->mDescriptorPool) {
     115          76 :         KP_LOG_DEBUG("Kompute Algorithm Destroying Descriptor Pool");
     116          38 :         if (!this->mDescriptorPool) {
     117           0 :             KP_LOG_WARN("Kompute Algorithm Error requested to destroy "
     118             :                         "descriptor pool but it is null");
     119             :         }
     120          38 :         this->mDevice->destroy(
     121          38 :           *this->mDescriptorPool,
     122             :           (vk::Optional<const vk::AllocationCallbacks>)nullptr);
     123          38 :         this->mDescriptorPool = nullptr;
     124             :     }
     125             : }
     126             : 
     127             : void
     128          38 : Algorithm::createParameters()
     129             : {
     130          76 :     KP_LOG_DEBUG("Kompute Algorithm createParameters started");
     131             : 
     132             :     std::vector<vk::DescriptorPoolSize> descriptorPoolSizes = {
     133             :         vk::DescriptorPoolSize(
     134             :           vk::DescriptorType::eStorageBuffer,
     135          38 :           static_cast<uint32_t>(this->mTensors.size()) // Descriptor count
     136             :           )
     137          38 :     };
     138             : 
     139             :     vk::DescriptorPoolCreateInfo descriptorPoolInfo(
     140             :       vk::DescriptorPoolCreateFlags(),
     141             :       1, // Max sets
     142          38 :       static_cast<uint32_t>(descriptorPoolSizes.size()),
     143          76 :       descriptorPoolSizes.data());
     144             : 
     145          76 :     KP_LOG_DEBUG("Kompute Algorithm creating descriptor pool");
     146          38 :     this->mDescriptorPool = std::make_shared<vk::DescriptorPool>();
     147          38 :     this->mDevice->createDescriptorPool(
     148             :       &descriptorPoolInfo, nullptr, this->mDescriptorPool.get());
     149          38 :     this->mFreeDescriptorPool = true;
     150             : 
     151          38 :     std::vector<vk::DescriptorSetLayoutBinding> descriptorSetBindings;
     152         122 :     for (size_t i = 0; i < this->mTensors.size(); i++) {
     153          84 :         descriptorSetBindings.push_back(
     154         168 :           vk::DescriptorSetLayoutBinding(i, // Binding index
     155             :                                          vk::DescriptorType::eStorageBuffer,
     156             :                                          1, // Descriptor count
     157             :                                          vk::ShaderStageFlagBits::eCompute));
     158             :     }
     159             : 
     160             :     // This is the component that is fed into the pipeline
     161             :     vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutInfo(
     162             :       vk::DescriptorSetLayoutCreateFlags(),
     163          38 :       static_cast<uint32_t>(descriptorSetBindings.size()),
     164          76 :       descriptorSetBindings.data());
     165             : 
     166          76 :     KP_LOG_DEBUG("Kompute Algorithm creating descriptor set layout");
     167          38 :     this->mDescriptorSetLayout = std::make_shared<vk::DescriptorSetLayout>();
     168          38 :     this->mDevice->createDescriptorSetLayout(
     169             :       &descriptorSetLayoutInfo, nullptr, this->mDescriptorSetLayout.get());
     170          38 :     this->mFreeDescriptorSetLayout = true;
     171             : 
     172             :     vk::DescriptorSetAllocateInfo descriptorSetAllocateInfo(
     173          38 :       *this->mDescriptorPool,
     174             :       1, // Descriptor set layout count
     175          76 :       this->mDescriptorSetLayout.get());
     176             : 
     177          76 :     KP_LOG_DEBUG("Kompute Algorithm allocating descriptor sets");
     178          38 :     this->mDescriptorSet = std::make_shared<vk::DescriptorSet>();
     179          38 :     this->mDevice->allocateDescriptorSets(&descriptorSetAllocateInfo,
     180             :                                           this->mDescriptorSet.get());
     181          38 :     this->mFreeDescriptorSet = true;
     182             : 
     183          76 :     KP_LOG_DEBUG("Kompute Algorithm updating descriptor sets");
     184         122 :     for (size_t i = 0; i < this->mTensors.size(); i++) {
     185          84 :         std::vector<vk::WriteDescriptorSet> computeWriteDescriptorSets;
     186             : 
     187             :         vk::DescriptorBufferInfo descriptorBufferInfo =
     188          84 :           this->mTensors[i]->constructDescriptorBufferInfo();
     189             : 
     190          84 :         computeWriteDescriptorSets.push_back(
     191          84 :           vk::WriteDescriptorSet(*this->mDescriptorSet,
     192             :                                  i, // Destination binding
     193             :                                  0, // Destination array element
     194             :                                  1, // Descriptor count
     195             :                                  vk::DescriptorType::eStorageBuffer,
     196             :                                  nullptr, // Descriptor image info
     197             :                                  &descriptorBufferInfo));
     198             : 
     199          84 :         this->mDevice->updateDescriptorSets(computeWriteDescriptorSets,
     200             :                                             nullptr);
     201          84 :     }
     202             : 
     203          76 :     KP_LOG_DEBUG("Kompute Algorithm successfully run init");
     204          38 : }
     205             : 
     206             : void
     207          38 : Algorithm::createShaderModule()
     208             : {
     209          76 :     KP_LOG_DEBUG("Kompute Algorithm createShaderModule started");
     210             : 
     211             :     vk::ShaderModuleCreateInfo shaderModuleInfo(vk::ShaderModuleCreateFlags(),
     212             :                                                 sizeof(uint32_t) *
     213          38 :                                                   this->mSpirv.size(),
     214          76 :                                                 this->mSpirv.data());
     215             : 
     216         114 :     KP_LOG_DEBUG("Kompute Algorithm Creating shader module. ShaderFileSize: {}",
     217             :                  this->mSpirv.size());
     218          38 :     this->mFreeShaderModule = true;
     219          38 :     this->mShaderModule = std::make_shared<vk::ShaderModule>();
     220          38 :     this->mDevice->createShaderModule(
     221             :       &shaderModuleInfo, nullptr, this->mShaderModule.get());
     222          38 :     this->mFreeShaderModule = true;
     223             : 
     224          76 :     KP_LOG_DEBUG("Kompute Algorithm create shader module success");
     225          38 : }
     226             : 
     227             : void
     228          38 : Algorithm::createPipeline()
     229             : {
     230          76 :     KP_LOG_DEBUG("Kompute Algorithm calling create Pipeline");
     231             : 
     232             :     vk::PipelineLayoutCreateInfo pipelineLayoutInfo(
     233             :       vk::PipelineLayoutCreateFlags(),
     234             :       1, // Set layout count
     235          38 :       this->mDescriptorSetLayout.get());
     236             : 
     237          38 :     vk::PushConstantRange pushConstantRange;
     238          38 :     if (this->mPushConstantsSize) {
     239           8 :         pushConstantRange.setStageFlags(vk::ShaderStageFlagBits::eCompute);
     240           8 :         pushConstantRange.setOffset(0);
     241           8 :         pushConstantRange.setSize(this->mPushConstantsDataTypeMemorySize *
     242           8 :                                   this->mPushConstantsSize);
     243             : 
     244           8 :         pipelineLayoutInfo.setPushConstantRangeCount(1);
     245           8 :         pipelineLayoutInfo.setPPushConstantRanges(&pushConstantRange);
     246             :     }
     247             : 
     248          38 :     this->mPipelineLayout = std::make_shared<vk::PipelineLayout>();
     249          38 :     this->mDevice->createPipelineLayout(
     250             :       &pipelineLayoutInfo, nullptr, this->mPipelineLayout.get());
     251          38 :     this->mFreePipelineLayout = true;
     252             : 
     253          38 :     std::vector<vk::SpecializationMapEntry> specializationEntries;
     254             : 
     255          46 :     for (uint32_t i = 0; i < this->mSpecializationConstantsSize; i++) {
     256             :         vk::SpecializationMapEntry specializationEntry(
     257             :           static_cast<uint32_t>(i),
     258             :           static_cast<uint32_t>(
     259           8 :             this->mSpecializationConstantsDataTypeMemorySize * i),
     260           8 :           this->mSpecializationConstantsDataTypeMemorySize);
     261             : 
     262           8 :         specializationEntries.push_back(specializationEntry);
     263             :     }
     264             : 
     265             :     // This passes ownership of the memory so we remove ownership from
     266             :     // specialization container by using "transferDataOwnership"
     267             :     vk::SpecializationInfo specializationInfo(
     268          38 :       static_cast<uint32_t>(specializationEntries.size()),
     269          38 :       specializationEntries.data(),
     270          38 :       this->mSpecializationConstantsDataTypeMemorySize *
     271          38 :         this->mSpecializationConstantsSize,
     272          76 :       this->mSpecializationConstantsData);
     273             : 
     274             :     vk::PipelineShaderStageCreateInfo shaderStage(
     275             :       vk::PipelineShaderStageCreateFlags(),
     276             :       vk::ShaderStageFlagBits::eCompute,
     277          38 :       *this->mShaderModule,
     278             :       "main",
     279          38 :       &specializationInfo);
     280             : 
     281             :     vk::ComputePipelineCreateInfo pipelineInfo(vk::PipelineCreateFlags(),
     282             :                                                shaderStage,
     283          38 :                                                *this->mPipelineLayout,
     284             :                                                vk::Pipeline(),
     285          76 :                                                0);
     286             : 
     287          38 :     vk::PipelineCacheCreateInfo pipelineCacheInfo =
     288             :       vk::PipelineCacheCreateInfo();
     289          38 :     this->mPipelineCache = std::make_shared<vk::PipelineCache>();
     290          38 :     this->mDevice->createPipelineCache(
     291             :       &pipelineCacheInfo, nullptr, this->mPipelineCache.get());
     292          38 :     this->mFreePipelineCache = true;
     293             : 
     294             : #ifdef KOMPUTE_CREATE_PIPELINE_RESULT_VALUE
     295             :     vk::ResultValue<vk::Pipeline> pipelineResult =
     296             :       this->mDevice->createComputePipeline(*this->mPipelineCache, pipelineInfo);
     297             : 
     298             :     if (pipelineResult.result != vk::Result::eSuccess) {
     299             :         throw std::runtime_error("Failed to create pipeline result: " +
     300             :                                  vk::to_string(pipelineResult.result));
     301             :     }
     302             : 
     303             :     vk::Pipeline& pipeline = pipelineResult.value;
     304             :     this->mPipeline = std::make_shared<vk::Pipeline>(pipeline);
     305             :     this->mFreePipeline = true;
     306             : #else
     307             :     vk::Pipeline pipeline =
     308          38 :       this->mDevice->createComputePipeline(*this->mPipelineCache, pipelineInfo)
     309          38 :         .value;
     310          38 :     this->mPipeline = std::make_shared<vk::Pipeline>(pipeline);
     311          38 :     this->mFreePipeline = true;
     312             : #endif
     313             : 
     314             :     // TODO: Update to consistent
     315             :     // this->mPipeline = std::make_shared<vk::Pipeline>();
     316             :     // this->mDevice->createComputePipelines(
     317             :     //         *this->mPipelineCache, 1, &pipelineInfo, nullptr,
     318             :     //         this->mPipeline.get());
     319             : 
     320          76 :     KP_LOG_DEBUG("Kompute Algorithm Create Pipeline Success");
     321          38 : }
     322             : 
     323             : void
     324          46 : Algorithm::recordBindCore(const vk::CommandBuffer& commandBuffer)
     325             : {
     326          92 :     KP_LOG_DEBUG("Kompute Algorithm binding pipeline");
     327             : 
     328          92 :     commandBuffer.bindPipeline(vk::PipelineBindPoint::eCompute,
     329          46 :                                *this->mPipeline);
     330             : 
     331          92 :     KP_LOG_DEBUG("Kompute Algorithm binding descriptor sets");
     332             : 
     333          92 :     commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eCompute,
     334          46 :                                      *this->mPipelineLayout,
     335             :                                      0, // First set
     336          46 :                                      *this->mDescriptorSet,
     337             :                                      nullptr // Dispatcher
     338             :     );
     339          46 : }
     340             : 
     341             : void
     342          46 : Algorithm::recordBindPush(const vk::CommandBuffer& commandBuffer)
     343             : {
     344          46 :     if (this->mPushConstantsSize) {
     345          36 :         KP_LOG_DEBUG("Kompute Algorithm binding push constants memory size: {}",
     346             :                      this->mPushConstantsSize *
     347             :                        this->mPushConstantsDataTypeMemorySize);
     348             : 
     349          36 :         commandBuffer.pushConstants(*this->mPipelineLayout,
     350             :                                     vk::ShaderStageFlagBits::eCompute,
     351             :                                     0,
     352          12 :                                     this->mPushConstantsSize *
     353          12 :                                       this->mPushConstantsDataTypeMemorySize,
     354          12 :                                     this->mPushConstantsData);
     355             :     }
     356          46 : }
     357             : 
     358             : void
     359          46 : Algorithm::recordDispatch(const vk::CommandBuffer& commandBuffer)
     360             : {
     361          92 :     KP_LOG_DEBUG("Kompute Algorithm recording dispatch");
     362             : 
     363          92 :     commandBuffer.dispatch(
     364          46 :       this->mWorkgroup[0], this->mWorkgroup[1], this->mWorkgroup[2]);
     365          46 : }
     366             : 
     367             : void
     368          38 : Algorithm::setWorkgroup(const Workgroup& workgroup, uint32_t minSize)
     369             : {
     370             : 
     371          76 :     KP_LOG_INFO("Kompute OpAlgoCreate setting dispatch size");
     372             : 
     373             :     // The dispatch size is set up based on either explicitly provided template
     374             :     // parameters or by default it would take the shape and size of the tensors
     375          38 :     if (workgroup[0] > 0) {
     376             :         // If at least the x value is provided we use mainly the parameters
     377             :         // provided
     378          20 :         this->mWorkgroup = { workgroup[0],
     379          10 :                              workgroup[1] > 0 ? workgroup[1] : 1,
     380          10 :                              workgroup[2] > 0 ? workgroup[2] : 1 };
     381             :     } else {
     382          28 :         this->mWorkgroup = { minSize, 1, 1 };
     383             :     }
     384             : 
     385         114 :     KP_LOG_INFO("Kompute OpAlgoCreate set dispatch size X: {}, Y: {}, Z: {}",
     386             :                 this->mWorkgroup[0],
     387             :                 this->mWorkgroup[1],
     388             :                 this->mWorkgroup[2]);
     389          38 : }
     390             : 
     391             : const Workgroup&
     392           1 : Algorithm::getWorkgroup()
     393             : {
     394           1 :     return this->mWorkgroup;
     395             : }
     396             : 
     397             : const std::vector<std::shared_ptr<Tensor>>&
     398          51 : Algorithm::getTensors()
     399             : {
     400          51 :     return this->mTensors;
     401             : }
     402             : 
     403             : }

Generated by: LCOV version 1.14