1 /*
2  * Copyright (C) 2018-2021 Intel Corporation
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  */
7 
8 #include "shared/source/os_interface/performance_counters.h"
9 
10 #include "shared/source/helpers/engine_node_helper.h"
11 #include "shared/source/os_interface/os_context.h"
12 #include "shared/source/utilities/tag_allocator.h"
13 
14 using namespace MetricsLibraryApi;
15 
16 namespace NEO {
17 
18 //////////////////////////////////////////////////////
19 // PerformanceCounters constructor.
20 //////////////////////////////////////////////////////
PerformanceCounters()21 PerformanceCounters::PerformanceCounters() {
22     metricsLibrary = std::make_unique<MetricsLibrary>();
23     UNRECOVERABLE_IF(metricsLibrary == nullptr);
24 }
25 
26 //////////////////////////////////////////////////////
27 // PerformanceCounters::getReferenceNumber
28 //////////////////////////////////////////////////////
getReferenceNumber()29 uint32_t PerformanceCounters::getReferenceNumber() {
30     std::lock_guard<std::mutex> lockMutex(mutex);
31     return referenceCounter;
32 }
33 
34 //////////////////////////////////////////////////////
35 // PerformanceCounters::enable
36 //////////////////////////////////////////////////////
enable(bool ccsEngine)37 bool PerformanceCounters::enable(bool ccsEngine) {
38     std::lock_guard<std::mutex> lockMutex(mutex);
39 
40     if (referenceCounter == 0) {
41         available = openMetricsLibrary();
42         this->usingCcsEngine = ccsEngine;
43     }
44 
45     referenceCounter++;
46 
47     return available && (this->usingCcsEngine == ccsEngine);
48 }
49 
50 //////////////////////////////////////////////////////
51 // PerformanceCounters::shutdown
52 //////////////////////////////////////////////////////
shutdown()53 void PerformanceCounters::shutdown() {
54     std::lock_guard<std::mutex> lockMutex(mutex);
55 
56     if (referenceCounter >= 1) {
57         if (referenceCounter == 1) {
58             available = false;
59             closeMetricsLibrary();
60         }
61         referenceCounter--;
62     }
63 }
64 
65 //////////////////////////////////////////////////////
66 // PerformanceCounters::getMetricsLibraryInterface
67 //////////////////////////////////////////////////////
getMetricsLibraryInterface()68 MetricsLibrary *PerformanceCounters::getMetricsLibraryInterface() {
69     return metricsLibrary.get();
70 }
71 
72 //////////////////////////////////////////////////////
73 // PerformanceCounters::setMetricsLibraryInterface
74 //////////////////////////////////////////////////////
setMetricsLibraryInterface(std::unique_ptr<MetricsLibrary> newMetricsLibrary)75 void PerformanceCounters::setMetricsLibraryInterface(std::unique_ptr<MetricsLibrary> newMetricsLibrary) {
76     metricsLibrary = std::move(newMetricsLibrary);
77 }
78 
79 //////////////////////////////////////////////////////
80 // PerformanceCounters::getMetricsLibraryContext
81 //////////////////////////////////////////////////////
getMetricsLibraryContext()82 ContextHandle_1_0 PerformanceCounters::getMetricsLibraryContext() {
83     return context;
84 }
85 
86 //////////////////////////////////////////////////////
87 // PerformanceCounters::openMetricsLibrary
88 //////////////////////////////////////////////////////
openMetricsLibrary()89 bool PerformanceCounters::openMetricsLibrary() {
90 
91     // Open metrics library.
92     bool result = metricsLibrary->open();
93     DEBUG_BREAK_IF(!result);
94 
95     // Create metrics library context.
96     if (result) {
97         result = metricsLibrary->contextCreate(
98             clientType,
99             subDevice,
100             subDeviceIndex,
101             subDeviceCount,
102             clientData,
103             contextData,
104             context);
105 
106         // Validate gpu report size.
107         DEBUG_BREAK_IF(!metricsLibrary->hwCountersGetGpuReportSize());
108     }
109 
110     // Error handling.
111     if (!result) {
112         closeMetricsLibrary();
113     }
114 
115     return result;
116 }
117 
118 //////////////////////////////////////////////////////
119 // PerformanceCounters::closeMetricsLibrary
120 //////////////////////////////////////////////////////
closeMetricsLibrary()121 void PerformanceCounters::closeMetricsLibrary() {
122     // Destroy oa configuration.
123     releaseCountersConfiguration();
124 
125     // Destroy hw counters query.
126     if (query.IsValid()) {
127         metricsLibrary->hwCountersDelete(query);
128         query = {};
129     }
130 
131     // Destroy metrics library context.
132     if (context.IsValid()) {
133         metricsLibrary->contextDelete(context);
134         context = {};
135     }
136 }
137 
138 //////////////////////////////////////////////////////
139 // PerformanceCounters::getQueryHandle
140 //////////////////////////////////////////////////////
getQueryHandleRef(QueryHandle_1_0 & handle)141 void PerformanceCounters::getQueryHandleRef(QueryHandle_1_0 &handle) {
142     if (!handle.IsValid()) {
143         metricsLibrary->hwCountersCreate(
144             context,
145             1,
146             nullptr,
147             handle);
148     }
149 
150     DEBUG_BREAK_IF(!handle.IsValid());
151 }
152 
153 //////////////////////////////////////////////////////
154 // PerformanceCounters::getQueryHandle
155 //////////////////////////////////////////////////////
deleteQuery(QueryHandle_1_0 & handle)156 void PerformanceCounters::deleteQuery(QueryHandle_1_0 &handle) {
157     metricsLibrary->hwCountersDelete(handle);
158 }
159 
160 //////////////////////////////////////////////////////
161 // PerformanceCounters::getGpuCommandsSize
162 //////////////////////////////////////////////////////
getGpuCommandsSize(PerformanceCounters * performanceCounters,aub_stream::EngineType engineType,const bool reservePerfCounters)163 uint32_t PerformanceCounters::getGpuCommandsSize(PerformanceCounters *performanceCounters, aub_stream::EngineType engineType, const bool reservePerfCounters) {
164     uint32_t size = 0;
165 
166     if (reservePerfCounters) {
167         const auto commandBufferType = EngineHelpers::isCcs(engineType)
168                                            ? MetricsLibraryApi::GpuCommandBufferType::Compute
169                                            : MetricsLibraryApi::GpuCommandBufferType::Render;
170 
171         size += performanceCounters->getGpuCommandsSize(commandBufferType, true);
172         size += performanceCounters->getGpuCommandsSize(commandBufferType, false);
173     }
174 
175     return size;
176 }
177 
178 //////////////////////////////////////////////////////
179 // PerformanceCounters::getGpuCommandsSize
180 //////////////////////////////////////////////////////
getGpuCommandsSize(const MetricsLibraryApi::GpuCommandBufferType commandBufferType,const bool begin)181 uint32_t PerformanceCounters::getGpuCommandsSize(
182     const MetricsLibraryApi::GpuCommandBufferType commandBufferType,
183     const bool begin) {
184     CommandBufferData_1_0 bufferData = {};
185     CommandBufferSize_1_0 bufferSize = {};
186 
187     if (begin) {
188         // Load currently activated (through metrics discovery) oa configuration and use it.
189         // It will allow to change counters configuration between subsequent clEnqueueNDCommandRange calls.
190         if (!enableCountersConfiguration()) {
191             return 0;
192         }
193     }
194 
195     bufferData.HandleContext = context;
196     bufferData.CommandsType = ObjectType::QueryHwCounters;
197     bufferData.Type = commandBufferType;
198 
199     getQueryHandleRef(query);
200 
201     bufferData.QueryHwCounters.Begin = begin;
202     bufferData.QueryHwCounters.Handle = query;
203 
204     return metricsLibrary->commandBufferGetSize(bufferData, bufferSize)
205                ? bufferSize.GpuMemorySize
206                : 0;
207 }
208 
209 //////////////////////////////////////////////////////
210 // PerformanceCounters::getGpuCommands
211 //////////////////////////////////////////////////////
getGpuCommands(const MetricsLibraryApi::GpuCommandBufferType commandBufferType,TagNodeBase & performanceCounters,const bool begin,const uint32_t bufferSize,void * pBuffer)212 bool PerformanceCounters::getGpuCommands(
213     const MetricsLibraryApi::GpuCommandBufferType commandBufferType,
214     TagNodeBase &performanceCounters,
215     const bool begin,
216     const uint32_t bufferSize,
217     void *pBuffer) {
218 
219     // Command Buffer data.
220     CommandBufferData_1_0 bufferData = {};
221     bufferData.HandleContext = context;
222     bufferData.CommandsType = ObjectType::QueryHwCounters;
223     bufferData.Data = pBuffer;
224     bufferData.Size = bufferSize;
225     bufferData.Type = commandBufferType;
226 
227     // Gpu memory allocation for query hw counters.
228     const uint32_t allocationOffset = offsetof(HwPerfCounter, report);
229     bufferData.Allocation.CpuAddress = reinterpret_cast<uint8_t *>(performanceCounters.getCpuBase()) + allocationOffset;
230     bufferData.Allocation.GpuAddress = performanceCounters.getGpuAddress() + allocationOffset;
231 
232     // Allocate query handle for cl_event if not exists.
233     getQueryHandleRef(performanceCounters.getQueryHandleRef());
234 
235     // Query hw counters specific data.
236     bufferData.QueryHwCounters.Begin = begin;
237     bufferData.QueryHwCounters.Handle = performanceCounters.getQueryHandleRef();
238 
239     return metricsLibrary->commandBufferGet(bufferData);
240 }
241 
242 //////////////////////////////////////////////////////
243 // PerformanceCounters::getApiReportSize
244 //////////////////////////////////////////////////////
getApiReportSize()245 uint32_t PerformanceCounters::getApiReportSize() {
246     return metricsLibrary->hwCountersGetApiReportSize();
247 }
248 
249 //////////////////////////////////////////////////////
250 // PerformanceCounters::getGpuReportSize
251 //////////////////////////////////////////////////////
getGpuReportSize()252 uint32_t PerformanceCounters::getGpuReportSize() {
253     return metricsLibrary->hwCountersGetGpuReportSize();
254 }
255 
256 //////////////////////////////////////////////////////
257 // PerformanceCounters::getApiReport
258 //////////////////////////////////////////////////////
getApiReport(const TagNodeBase * performanceCounters,const size_t inputParamSize,void * pInputParam,size_t * pOutputParamSize,bool isEventComplete)259 bool PerformanceCounters::getApiReport(const TagNodeBase *performanceCounters, const size_t inputParamSize, void *pInputParam, size_t *pOutputParamSize, bool isEventComplete) {
260     const uint32_t outputSize = metricsLibrary->hwCountersGetApiReportSize();
261 
262     if (pOutputParamSize) {
263         *pOutputParamSize = outputSize;
264     }
265 
266     if (!performanceCounters) {
267         return false;
268     }
269 
270     if (pInputParam == nullptr && inputParamSize == 0 && pOutputParamSize) {
271         return true;
272     }
273 
274     if (pInputParam == nullptr || isEventComplete == false) {
275         return false;
276     }
277 
278     if (inputParamSize < outputSize) {
279         return false;
280     }
281 
282     return metricsLibrary->hwCountersGetReport(performanceCounters->getQueryHandleRef(), 0, 1, outputSize, pInputParam);
283 }
284 } // namespace NEO
285