Skip to content

Commit 75ebe75

Browse files
committed
Created SPipelineExecutableInfo instead of a string, more error checks, getPipelineExecutableProperties_impl overloads with one helper function
1 parent d4ade8c commit 75ebe75

4 files changed

Lines changed: 144 additions & 47 deletions

File tree

include/nbl/video/ILogicalDevice.h

Lines changed: 93 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "nbl/video/IGPUCommandBuffer.h"
1515
#include "nbl/video/CThreadSafeQueueAdapter.h"
1616
#include "nbl/video/CJITIncludeLoader.h"
17+
#include "nbl/system/to_string.h"
1718

1819
#include "git_info.h"
1920
#define NBL_LOG_FUNCTION m_logger.log
@@ -1033,24 +1034,45 @@ class NBL_API2 ILogicalDevice : public core::IReferenceCounted, public IDeviceMe
10331034
const std::span<const IGPURayTracingPipeline::SCreationParams> params,
10341035
core::smart_refctd_ptr<IGPURayTracingPipeline>* const output);
10351036

1036-
// Pipeline executable statistics report (VK_KHR_pipeline_executable_properties).
1037-
// Pipeline must have been created with CAPTURE_STATISTICS flag.
1038-
// If includeInternalRepresentations is true, also includes shader IR/assembly
1039-
// (pipeline must have been created with CAPTURE_INTERNAL_REPRESENTATIONS flag).
1037+
// Per-executable info from VK_KHR_pipeline_executable_properties
1038+
struct SPipelineExecutableInfo
1039+
{
1040+
std::string name;
1041+
std::string description;
1042+
core::bitflag<hlsl::ShaderStage> stages = hlsl::ShaderStage::ESS_UNKNOWN;
1043+
uint32_t subgroupSize = 0;
1044+
std::string statistics;
1045+
std::string internalRepresentations;
1046+
};
1047+
1048+
// Query pipeline executable properties (VK_KHR_pipeline_executable_properties).
1049+
// Pipeline must have been created with CAPTURE_STATISTICS flag for statistics.
1050+
// Pipeline must have been created with CAPTURE_INTERNAL_REPRESENTATIONS flag for IR.
10401051
template<typename Pipeline>
1041-
std::string getPipelineExecutableReport(const Pipeline* pipeline, bool includeInternalRepresentations = false)
1052+
core::vector<SPipelineExecutableInfo> getPipelineExecutableProperties(const Pipeline* pipeline, bool includeInternalRepresentations = false)
10421053
{
10431054
if (!pipeline)
10441055
{
10451056
NBL_LOG_ERROR("Null pipeline");
10461057
return {};
10471058
}
1048-
if (!getEnabledFeatures().pipelineExecutableInfo)
1059+
using flags_t = Pipeline::SCreationParams::FLAGS;
1060+
if (!pipeline->getCreationFlags().hasFlags(flags_t::CAPTURE_STATISTICS))
10491061
{
1050-
NBL_LOG_ERROR("Feature `pipelineExecutableInfo` is not enabled");
1062+
NBL_LOG_ERROR("Pipeline was not created with CAPTURE_STATISTICS flag");
10511063
return {};
10521064
}
1053-
return getPipelineExecutableReport_impl(pipeline->getNativeHandle(), includeInternalRepresentations);
1065+
if (includeInternalRepresentations && !pipeline->getCreationFlags().hasFlags(flags_t::CAPTURE_INTERNAL_REPRESENTATIONS))
1066+
{
1067+
NBL_LOG_ERROR("Pipeline was not created with CAPTURE_INTERNAL_REPRESENTATIONS flag");
1068+
return {};
1069+
}
1070+
auto properties = getPipelineExecutableProperties_impl(pipeline, includeInternalRepresentations);
1071+
if (properties.empty())
1072+
{
1073+
NBL_LOG_ERROR("Driver returned 0 executables for pipeline created with CAPTURE_STATISTICS flag. This pipeline type may not be supported by the driver's VK_KHR_pipeline_executable_properties implementation.");
1074+
}
1075+
return properties;
10541076
}
10551077

10561078
// queries
@@ -1293,6 +1315,20 @@ class NBL_API2 ILogicalDevice : public core::IReferenceCounted, public IDeviceMe
12931315
return {};
12941316
}
12951317

1318+
// CAPTURE_STATISTICS and CAPTURE_INTERNAL_REPRESENTATIONS require pipelineExecutableInfo feature
1319+
constexpr auto CaptureStatsFlag = CreationParams::FLAGS::CAPTURE_STATISTICS;
1320+
constexpr auto CaptureIRFlag = CreationParams::FLAGS::CAPTURE_INTERNAL_REPRESENTATIONS;
1321+
if (ci.getFlags().hasFlags(CaptureStatsFlag) && !getEnabledFeatures().pipelineExecutableInfo)
1322+
{
1323+
NBL_LOG_ERROR("CAPTURE_STATISTICS flag requires `pipelineExecutableInfo` feature (params[%d])", i);
1324+
return {};
1325+
}
1326+
if (ci.getFlags().hasFlags(CaptureIRFlag) && !getEnabledFeatures().pipelineExecutableInfo)
1327+
{
1328+
NBL_LOG_ERROR("CAPTURE_INTERNAL_REPRESENTATIONS flag requires `pipelineExecutableInfo` feature (params[%d])", i);
1329+
return {};
1330+
}
1331+
12961332
retval += validation;
12971333
}
12981334
return retval;
@@ -1316,7 +1352,9 @@ class NBL_API2 ILogicalDevice : public core::IReferenceCounted, public IDeviceMe
13161352
const SSpecializationValidationResult& validation
13171353
) = 0;
13181354

1319-
virtual std::string getPipelineExecutableReport_impl(const void* nativeHandle, bool includeInternalRepresentations) = 0;
1355+
virtual core::vector<SPipelineExecutableInfo> getPipelineExecutableProperties_impl(const IGPUComputePipeline* pipeline, bool includeInternalRepresentations) = 0;
1356+
virtual core::vector<SPipelineExecutableInfo> getPipelineExecutableProperties_impl(const IGPUGraphicsPipeline* pipeline, bool includeInternalRepresentations) = 0;
1357+
virtual core::vector<SPipelineExecutableInfo> getPipelineExecutableProperties_impl(const IGPURayTracingPipeline* pipeline, bool includeInternalRepresentations) = 0;
13201358

13211359
virtual core::smart_refctd_ptr<IQueryPool> createQueryPool_impl(const IQueryPool::SCreationParams& params) = 0;
13221360
virtual bool getQueryPoolResults_impl(const IQueryPool* const queryPool, const uint32_t firstQuery, const uint32_t queryCount, void* const pData, const size_t stride, const core::bitflag<IQueryPool::RESULTS_FLAGS> flags) = 0;
@@ -1627,5 +1665,51 @@ inline bool ILogicalDevice::validateMemoryBarrier(const uint32_t queueFamilyInde
16271665

16281666
} // namespace nbl::video
16291667

1668+
namespace nbl::system::impl
1669+
{
1670+
1671+
template<>
1672+
struct to_string_helper<video::ILogicalDevice::SPipelineExecutableInfo>
1673+
{
1674+
static std::string __call(const video::ILogicalDevice::SPipelineExecutableInfo& info)
1675+
{
1676+
std::string result;
1677+
result += "======== ";
1678+
result += info.name;
1679+
result += " ========\n";
1680+
result += info.description;
1681+
result += "\nSubgroup Size: ";
1682+
result += std::to_string(info.subgroupSize);
1683+
if (!info.statistics.empty())
1684+
{
1685+
result += "\n";
1686+
result += info.statistics;
1687+
}
1688+
if (!info.internalRepresentations.empty())
1689+
{
1690+
result += "\n";
1691+
result += info.internalRepresentations;
1692+
}
1693+
return result;
1694+
}
1695+
};
1696+
1697+
template<>
1698+
struct to_string_helper<core::vector<video::ILogicalDevice::SPipelineExecutableInfo>>
1699+
{
1700+
static std::string __call(const core::vector<video::ILogicalDevice::SPipelineExecutableInfo>& infos)
1701+
{
1702+
std::string result;
1703+
for (const auto& info : infos)
1704+
{
1705+
result += to_string_helper<video::ILogicalDevice::SPipelineExecutableInfo>::__call(info);
1706+
result += "\n";
1707+
}
1708+
return result;
1709+
}
1710+
};
1711+
1712+
}
1713+
16301714
#include "nbl/undef_logging_macros.h"
16311715
#endif //_NBL_VIDEO_I_LOGICAL_DEVICE_H_INCLUDED_

src/nbl/video/CVulkanLogicalDevice.cpp

Lines changed: 45 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1662,44 +1662,56 @@ void CVulkanLogicalDevice::createRayTracingPipelines_impl(
16621662
std::fill_n(output,vk_createInfos.size(),nullptr);
16631663
}
16641664

1665-
std::string CVulkanLogicalDevice::getPipelineExecutableReport_impl(const void* nativeHandle, bool includeInternalRepresentations)
1665+
core::vector<ILogicalDevice::SPipelineExecutableInfo> CVulkanLogicalDevice::getPipelineExecutableProperties_impl(const IGPUComputePipeline* pipeline, bool includeInternalRepresentations)
16661666
{
1667-
const VkPipeline vkPipeline = *reinterpret_cast<const VkPipeline*>(nativeHandle);
1667+
return getPipelineExecutableProperties_helper(static_cast<const CVulkanComputePipeline*>(pipeline)->getInternalObject(), includeInternalRepresentations);
1668+
}
1669+
1670+
core::vector<ILogicalDevice::SPipelineExecutableInfo> CVulkanLogicalDevice::getPipelineExecutableProperties_impl(const IGPUGraphicsPipeline* pipeline, bool includeInternalRepresentations)
1671+
{
1672+
return getPipelineExecutableProperties_helper(static_cast<const CVulkanGraphicsPipeline*>(pipeline)->getInternalObject(), includeInternalRepresentations);
1673+
}
1674+
1675+
core::vector<ILogicalDevice::SPipelineExecutableInfo> CVulkanLogicalDevice::getPipelineExecutableProperties_impl(const IGPURayTracingPipeline* pipeline, bool includeInternalRepresentations)
1676+
{
1677+
return getPipelineExecutableProperties_helper(static_cast<const CVulkanRayTracingPipeline*>(pipeline)->getInternalObject(), includeInternalRepresentations);
1678+
}
16681679

1680+
core::vector<ILogicalDevice::SPipelineExecutableInfo> CVulkanLogicalDevice::getPipelineExecutableProperties_helper(VkPipeline vkPipeline, bool includeInternalRepresentations)
1681+
{
16691682
VkPipelineInfoKHR pipelineInfo = {VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR, nullptr};
16701683
pipelineInfo.pipeline = vkPipeline;
16711684

16721685
// Enumerate executables
16731686
uint32_t executableCount = 0;
16741687
m_devf.vk.vkGetPipelineExecutablePropertiesKHR(m_vkdev, &pipelineInfo, &executableCount, nullptr);
16751688

1689+
if (executableCount == 0)
1690+
{
1691+
return {};
1692+
}
1693+
16761694
core::vector<VkPipelineExecutablePropertiesKHR> properties(executableCount);
16771695
for (uint32_t i = 0; i < executableCount; ++i)
16781696
properties[i] = {VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_PROPERTIES_KHR, nullptr};
16791697
m_devf.vk.vkGetPipelineExecutablePropertiesKHR(m_vkdev, &pipelineInfo, &executableCount, properties.data());
16801698

1681-
std::string report;
1682-
report.reserve(1024); // avoid some reallocations, we can adjust this if needed
1699+
core::vector<SPipelineExecutableInfo> result(executableCount);
1700+
16831701
for (uint32_t i = 0; i < executableCount; ++i)
16841702
{
16851703
const auto& prop = properties[i];
1704+
auto& info = result[i];
16861705

1687-
report += "======== ";
1688-
report += prop.name;
1689-
report += " ========\n";
1690-
report += prop.description;
1691-
report += "\n";
1706+
info.name = prop.name;
1707+
info.description = prop.description;
1708+
info.stages = static_cast<hlsl::ShaderStage>(prop.stages);
1709+
info.subgroupSize = prop.subgroupSize;
16921710

16931711
VkPipelineExecutableInfoKHR execInfo = {VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INFO_KHR, nullptr};
16941712
execInfo.pipeline = vkPipeline;
16951713
execInfo.executableIndex = i;
16961714

1697-
// Statistics
1698-
report += "==== Statistics ====\n";
1699-
report += "Subgroup Size: ";
1700-
report += std::to_string(prop.subgroupSize);
1701-
report += "\n";
1702-
17031715
uint32_t statCount = 0;
17041716
m_devf.vk.vkGetPipelineExecutableStatisticsKHR(m_vkdev, &execInfo, &statCount, nullptr);
17051717

@@ -1739,15 +1751,15 @@ std::string CVulkanLogicalDevice::getPipelineExecutableReport_impl(const void* n
17391751
maxNameValueLen = std::max(maxNameValueLen, nameValues[s].size());
17401752
}
17411753

1742-
// Overkill for now, but it produces nicely aligned output which is easier to read. We can optimize later if needed.
17431754
// Second pass: emit with aligned columns
1755+
std::string& statsStr = info.statistics;
17441756
for (uint32_t s = 0; s < statCount; ++s)
17451757
{
1746-
report += nameValues[s];
1747-
report.append(maxNameValueLen - nameValues[s].size() + 4, ' ');
1748-
report += "// ";
1749-
report += stats[s].description;
1750-
report += "\n";
1758+
statsStr += nameValues[s];
1759+
statsStr.append(maxNameValueLen - nameValues[s].size() + 4, ' ');
1760+
statsStr += "// ";
1761+
statsStr += stats[s].description;
1762+
statsStr += "\n";
17511763
}
17521764
}
17531765

@@ -1776,34 +1788,32 @@ std::string CVulkanLogicalDevice::getPipelineExecutableReport_impl(const void* n
17761788

17771789
m_devf.vk.vkGetPipelineExecutableInternalRepresentationsKHR(m_vkdev, &execInfo, &irCount, irs.data());
17781790

1779-
report += "\n";
1791+
std::string& irStr = info.internalRepresentations;
17801792
for (uint32_t r = 0; r < irCount; ++r)
17811793
{
1782-
report += "---- ";
1783-
report += irs[r].name;
1784-
report += " ----\n";
1785-
report += "; ";
1786-
report += irs[r].description;
1787-
report += "\n";
1794+
irStr += "---- ";
1795+
irStr += irs[r].name;
1796+
irStr += " ----\n";
1797+
irStr += irs[r].description;
1798+
irStr += "\n";
17881799
if (irs[r].isText)
17891800
{
17901801
auto* str = static_cast<const char*>(irs[r].pData);
1791-
report.append(str, irs[r].dataSize > 0 ? irs[r].dataSize - 1 : 0);
1792-
report += "\n";
1802+
irStr.append(str, irs[r].dataSize > 0 ? irs[r].dataSize - 1 : 0);
1803+
irStr += "\n";
17931804
}
17941805
else
17951806
{
1796-
report += "[binary data, ";
1797-
report += std::to_string(irs[r].dataSize);
1798-
report += " bytes]\n";
1807+
irStr += "[binary data, ";
1808+
irStr += std::to_string(irs[r].dataSize);
1809+
irStr += " bytes]\n";
17991810
}
18001811
}
18011812
}
18021813
}
1803-
report += "\n";
18041814
}
18051815

1806-
return report;
1816+
return result;
18071817
}
18081818

18091819
core::smart_refctd_ptr<IQueryPool> CVulkanLogicalDevice::createQueryPool_impl(const IQueryPool::SCreationParams& params)

src/nbl/video/CVulkanLogicalDevice.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,11 @@ class CVulkanLogicalDevice final : public ILogicalDevice
301301
const SSpecializationValidationResult& validation
302302
) override;
303303

304-
// pipeline executable statistics
305-
std::string getPipelineExecutableReport_impl(const void* nativeHandle, bool includeInternalRepresentations) override;
304+
// pipeline executable properties
305+
core::vector<SPipelineExecutableInfo> getPipelineExecutableProperties_impl(const IGPUComputePipeline* pipeline, bool includeInternalRepresentations) override;
306+
core::vector<SPipelineExecutableInfo> getPipelineExecutableProperties_impl(const IGPUGraphicsPipeline* pipeline, bool includeInternalRepresentations) override;
307+
core::vector<SPipelineExecutableInfo> getPipelineExecutableProperties_impl(const IGPURayTracingPipeline* pipeline, bool includeInternalRepresentations) override;
308+
core::vector<SPipelineExecutableInfo> getPipelineExecutableProperties_helper(VkPipeline vkPipeline, bool includeInternalRepresentations);
306309

307310
// queries
308311
core::smart_refctd_ptr<IQueryPool> createQueryPool_impl(const IQueryPool::SCreationParams& params) override;

0 commit comments

Comments
 (0)