vsg: include/vsg/utils/TracyInstrumentation.h Source File

vsg 1.1.9 VulkanSceneGraph library |

Loading...
Searching...
No Matches
TracyInstrumentation.h
1#pragma once
2
3/* <editor-fold desc="MIT License">
4
5Copyright(c) 2023 Robert Osfield
6
7Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8
9The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10
11THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12
13</editor-fold> */
14
15#include <tracy/Tracy.hpp>
16#include <tracy/TracyVulkan.hpp>
17
18#include <vsg/utils/Instrumentation.h>
19
20using namespace tracy;
21
22namespace vsg
23{
24
25 class TracySettings : public Inherit<Object, TracySettings>
26 {
27 public:
28 uint32_t cpu_instrumentation_level = 3;
29 uint32_t gpu_instrumentation_level = 3;
30 };
31 VSG_type_name(vsg::TracySettings);
32
33#ifdef TRACY_ENABLE
35 class TracyContexts : public Inherit<Object, TracyContexts>
36 {
37 public:
38 VkCtx* getOrCreateContext(CommandBuffer& commandBuffer) const
39 {
40 std::scoped_lock<std::mutex> lock(mutex);
41
42 ref_ptr<Device> device(commandBuffer.getDevice());
43 auto& [ctx, requiresCollection] = ctxMap[device];
44 if (!ctx)
45 {
46 auto queue = device->getQueue(commandBuffer.getCommandPool()->queueFamilyIndex, 0);
47 auto commandPool = CommandPool::create(device, queue->queueFamilyIndex(), VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT);
48 auto temporaryCommandBuffer = commandPool->allocate();
49 auto extensions = device->getInstance()->getExtensions();
50
51 if (device->supportsDeviceExtension("VK_EXT_calibrated_timestamps"))
52 {
53 ctx = TracyVkContextCalibrated(device->getPhysicalDevice()->vk(), device->vk(), queue->vk(), temporaryCommandBuffer->vk(),
54 extensions->vkGetPhysicalDeviceCalibrateableTimeDomainsEXT, extensions->vkGetCalibratedTimestampsEXT);
55 }
56 else
57 {
58 ctx = TracyVkContext(device->getPhysicalDevice()->vk(), device->vk(), queue->vk(), temporaryCommandBuffer->vk());
59 }
60 requiresCollection = false;
61 }
62
63 if (ctx && requiresCollection)
64 {
65 TracyVkCollect(ctx, commandBuffer.vk());
66 requiresCollection = false;
67 }
68
69 return ctx;
70 }
71
72 void frameComplete()
73 {
74 std::scoped_lock<std::mutex> lock(mutex);
75 for (auto itr = ctxMap.begin(); itr != ctxMap.end(); ++itr)
76 {
77 itr->second.second = true;
78 }
79 }
80
81 mutable std::mutex mutex;
82 mutable std::map<ref_ptr<Device>, std::pair<VkCtx*, bool>> ctxMap;
83
84 protected:
85 ~TracyContexts()
86 {
87 for (auto itr = ctxMap.begin(); itr != ctxMap.end(); ++itr)
88 {
89 TracyVkDestroy(itr->second.first);
90 }
91 }
92 };
93 VSG_type_name(vsg::TracyContexts);
94
96 class TracyInstrumentation : public Inherit<Instrumentation, TracyInstrumentation>
97 {
98 public:
99 TracyInstrumentation() :
100 settings(TracySettings::create()),
101 contexts(TracyContexts::create())
102 {
103 }
104
105 TracyInstrumentation(TracyInstrumentation& parent) :
106 Inherit(),
107 settings(parent.settings),
108 contexts(parent.contexts)
109 {
110 }
111
112 ref_ptr<TracySettings> settings;
113 ref_ptr<TracyContexts> contexts;
114 mutable VkCtx* ctx = nullptr;
115 bool requiresCollection = false;
116
117 ref_ptr<Instrumentation> shareOrDuplicateForThreadSafety() override
118 {
119 return TracyInstrumentation::create(*this);
120 }
121
122 void setThreadName(const std::string& name) const override
123 {
124 tracy::SetThreadName(name.c_str());
125 }
126
127 void enterFrame(const SourceLocation*, uint64_t&, FrameStamp&) const override {}
128
129 void leaveFrame(const SourceLocation*, uint64_t&, FrameStamp&) const override
130 {
131 contexts->frameComplete();
132
133 FrameMark;
134 }
135
136 void enter(const SourceLocation* slcloc, uint64_t& reference, const Object*) const override
137 {
138# ifdef TRACY_ON_DEMAND
139 if (!GetProfiler().IsConnected() || (slcloc->level > settings->cpu_instrumentation_level))
140# else
141 if (slcloc->level > settings->cpu_instrumentation_level)
142# endif
143 {
144 reference = 0;
145 return;
146 }
147
148# ifdef TRACY_ON_DEMAND
149 reference = GetProfiler().ConnectionId();
150# else
151 reference = 1;
152# endif
153
154 TracyQueuePrepare(QueueType::ZoneBegin);
155 MemWrite(&item->zoneBegin.time, tracy::Profiler::GetTime());
156 MemWrite(&item->zoneBegin.srcloc, (uint64_t)slcloc);
157 TracyQueueCommit(zoneBeginThread);
158 }
159
160 void leave(const SourceLocation*, uint64_t& reference, const Object*) const override
161 {
162# ifdef TRACY_ON_DEMAND
163 if (reference == 0 || GetProfiler().ConnectionId() != reference) return;
164# else
165 if (reference == 0) return;
166# endif
167
168 TracyQueuePrepare(QueueType::ZoneEnd);
169 MemWrite(&item->zoneEnd.time, tracy::Profiler::GetTime());
170 TracyQueueCommit(zoneEndThread);
171 }
172
173 void enterCommandBuffer(const SourceLocation* slcloc, uint64_t& reference, CommandBuffer& commandBuffer) const override
174 {
175 if ((ctx = contexts->getOrCreateContext(commandBuffer)))
176 {
177 enter(slcloc, reference, commandBuffer, nullptr);
178 }
179 }
180
181 void leaveCommandBuffer(const SourceLocation* slcloc, uint64_t& reference, CommandBuffer& commandBuffer) const override
182 {
183 if (ctx)
184 {
185 leave(slcloc, reference, commandBuffer, nullptr);
186 }
187
188 ctx = nullptr;
189 }
190
191 void enter(const SourceLocation* slcloc, uint64_t& reference, CommandBuffer& cmdbuf, const Object*) const override
192 {
193# ifdef TRACY_ON_DEMAND
194 if (!ctx || !GetProfiler().IsConnected() || (slcloc->level > settings->gpu_instrumentation_level))
195# else
196 if (!ctx || slcloc->level > settings->gpu_instrumentation_level)
197# endif
198 {
199 reference = 0;
200 return;
201 }
202
203# ifdef TRACY_ON_DEMAND
204 reference = GetProfiler().ConnectionId();
205# else
206 reference = 1;
207# endif
208
209 const auto queryId = ctx->NextQueryId();
210 CONTEXT_VK_FUNCTION_WRAPPER(vkCmdWriteTimestamp(cmdbuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, ctx->GetQueryPool(), queryId));
211
212 auto item = tracy::Profiler::QueueSerial();
213 MemWrite(&item->hdr.type, QueueType::GpuZoneBeginSerial);
214 MemWrite(&item->gpuZoneBegin.cpuTime, tracy::Profiler::GetTime());
215 MemWrite(&item->gpuZoneBegin.srcloc, (uint64_t)slcloc);
216 MemWrite(&item->gpuZoneBegin.thread, GetThreadHandle());
217 MemWrite(&item->gpuZoneBegin.queryId, uint16_t(queryId));
218 MemWrite(&item->gpuZoneBegin.context, ctx->GetId());
219 tracy::Profiler::QueueSerialFinish();
220 }
221
222 void leave(const SourceLocation*, uint64_t& reference, CommandBuffer& cmdbuf, const Object*) const override
223 {
224# ifdef TRACY_ON_DEMAND
225 if (reference == 0 || GetProfiler().ConnectionId() != reference) return;
226# else
227 if (reference == 0) return;
228# endif
229
230 const auto queryId = ctx->NextQueryId();
231 CONTEXT_VK_FUNCTION_WRAPPER(vkCmdWriteTimestamp(cmdbuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, ctx->GetQueryPool(), queryId));
232
233 auto item = tracy::Profiler::QueueSerial();
234 MemWrite(&item->hdr.type, QueueType::GpuZoneEndSerial);
235 MemWrite(&item->gpuZoneEnd.cpuTime, tracy::Profiler::GetTime());
236 MemWrite(&item->gpuZoneEnd.thread, GetThreadHandle());
237 MemWrite(&item->gpuZoneEnd.queryId, uint16_t(queryId));
238 MemWrite(&item->gpuZoneEnd.context, ctx->GetId());
239 tracy::Profiler::QueueSerialFinish();
240 }
241 };
242 VSG_type_name(vsg::TracyInstrumentation);
243#else
244 class TracyInstrumentation : public Inherit<Instrumentation, TracyInstrumentation>
245 {
246 public:
247 TracyInstrumentation()
248 {
249 vsg::info("TracyInstrumentation not supported and the tracy's TRACY_ENABLE is set to OFF.");
250 }
251
252 ref_ptr<TracySettings> settings;
253 };
254 VSG_type_name(vsg::TracyInstrumentation);
255#endif
256} // namespace vsg
vsg::CommandBuffer
CommandBuffer encapsulates VkCommandBuffer.
Definition CommandBuffer.h:27
vsg::Inherit
Definition Inherit.h:28
vsg::TracyInstrumentation
Definition TracyInstrumentation.h:245
vsg::TracySettings
Definition TracyInstrumentation.h:26
vsg::ref_ptr
Definition ref_ptr.h:22