1 /*
2 * Copyright (c) 2018-2022, Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22 //!
23 //! \file     media_perf_profiler_legacy.cpp
24 //! \brief    Defines data structures and interfaces for media performance profiler.
25 //! \details
26 //!
27 
28 #include "media_perf_profiler.h"
29 
30 #define UMD_PERF_LOG            8
31 #define NAME_LEN                60
32 #define LOCAL_STRING_SIZE       64
33 #define OFFSET_OF(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMBER )
34 
35 typedef enum _UMD_PERF_MODE
36 {
37     UMD_PERF_MODE_TIMING_ONLY      = 0,
38     UMD_PERF_MODE_WITH_MEMORY_INFO = 4
39 } UMD_PERF_MODE;
40 
41 #pragma pack(push)
42 #pragma pack(8)
43 struct PerfEntry
44 {
45     uint32_t    nodeIndex;                  //!< Perf node index
46     uint32_t    processId;                  //!< Process Id
47     uint32_t    instanceId;                 //!< Instance Id
48     uint32_t    engineTag;                  //!< Engine tag
49     uint32_t    perfTag;                    //!< Performance tag
50     uint32_t    timeStampBase;              //!< HW timestamp base
51     uint32_t    beginRegisterValue[8];      //!< Begin register value
52     uint32_t    endRegisterValue[8];        //!< End register value
53     uint32_t    beginCpuTime[2];            //!< Begin CPU Time Stamp
54     uint32_t    reserved[14];               //!< Reserved[14]
55     uint64_t    beginTimeClockValue;        //!< Begin timestamp
56     uint64_t    endTimeClockValue;          //!< End timestamp
57 };
58 #pragma pack(pop)
59 
60 struct NodeHeader
61 {
62     uint32_t osPlatform  : 3;
63     uint32_t genPlatform : 3;
64     uint32_t eventType   : 4;
65     uint32_t perfMode    : 3;
66     uint32_t genAndroid  : 4;
67     uint32_t genPlatform_ext : 2;
68     uint32_t reserved    : 13;
69 };
70 
71 #define BASE_OF_NODE(perfDataIndex) (sizeof(NodeHeader) + (sizeof(PerfEntry) * perfDataIndex))
72 
73 #define CHK_STATUS_RETURN(_stmt)                   \
74 {                                                  \
75     MOS_STATUS stmtStatus = (MOS_STATUS)(_stmt);   \
76     if (stmtStatus != MOS_STATUS_SUCCESS)          \
77     {                                              \
78         return stmtStatus;                         \
79     }                                              \
80 }
81 
82 #define CHK_NULL_RETURN(_ptr)                      \
83 {                                                  \
84     if ((_ptr) == nullptr)                         \
85     {                                              \
86         return MOS_STATUS_NULL_POINTER;            \
87     }                                              \
88 }
89 
90 #define CHK_NULL_NO_STATUS_RETURN(_ptr)            \
91 {                                                  \
92     if ((_ptr) == nullptr)                         \
93     {                                              \
94         return;                                    \
95     }                                              \
96 }
97 
98 #define CHK_STATUS_UNLOCK_MUTEX_RETURN(_stmt)      \
99 {                                                  \
100     MOS_STATUS stmtStatus = (MOS_STATUS)(_stmt);   \
101     if (stmtStatus != MOS_STATUS_SUCCESS)          \
102     {                                              \
103         MosUtilities::MosUnlockMutex(m_mutex);     \
104         return stmtStatus;                         \
105     }                                              \
106 }
107 
108 #define CHK_NULL_UNLOCK_MUTEX_RETURN(_ptr)         \
109 {                                                  \
110     if ((_ptr) == nullptr)                         \
111     {                                              \
112         MosUtilities::MosUnlockMutex(m_mutex);     \
113         return MOS_STATUS_NULL_POINTER;            \
114     }                                              \
115 }
116 
StoreData(MhwMiInterface * miInterface,PMOS_COMMAND_BUFFER cmdBuffer,PMOS_CONTEXT pOsContext,uint32_t offset,uint32_t value)117 MOS_STATUS MediaPerfProfiler::StoreData(
118     MhwMiInterface *miInterface,
119     PMOS_COMMAND_BUFFER cmdBuffer,
120     PMOS_CONTEXT pOsContext,
121     uint32_t offset,
122     uint32_t value)
123 {
124     CHK_NULL_RETURN(miInterface);
125 
126     if (m_miItf)
127     {
128         CHK_STATUS_RETURN(StoreData(m_miItf, cmdBuffer, (MOS_CONTEXT_HANDLE)pOsContext, offset, value));
129     }
130     else
131     {
132         MHW_MI_STORE_DATA_PARAMS storeDataParams;
133         MOS_ZeroMemory(&storeDataParams, sizeof(storeDataParams));
134 
135         storeDataParams.pOsResource         = m_perfStoreBufferMap[pOsContext];
136         storeDataParams.dwResourceOffset    = offset;
137         storeDataParams.dwValue             = value;
138 
139         CHK_STATUS_RETURN(miInterface->AddMiStoreDataImmCmd(cmdBuffer, &storeDataParams));
140     }
141 
142     return MOS_STATUS_SUCCESS;
143 }
144 
StoreRegister(MOS_INTERFACE * osInterface,MhwMiInterface * miInterface,PMOS_COMMAND_BUFFER cmdBuffer,uint32_t offset,uint32_t reg)145 MOS_STATUS MediaPerfProfiler::StoreRegister(
146     MOS_INTERFACE *osInterface,
147     MhwMiInterface *miInterface,
148     PMOS_COMMAND_BUFFER cmdBuffer,
149     uint32_t offset,
150     uint32_t reg)
151 {
152     CHK_NULL_RETURN(osInterface);
153     CHK_NULL_RETURN(miInterface);
154 
155     PMOS_CONTEXT pOsContext = osInterface->pOsContext;
156     CHK_NULL_RETURN(pOsContext);
157 
158     if (m_miItf)
159     {
160         CHK_STATUS_RETURN(StoreRegister(osInterface, m_miItf, cmdBuffer, offset, reg));
161     }
162     else
163     {
164         MHW_MI_STORE_REGISTER_MEM_PARAMS storeRegMemParams;
165         MOS_ZeroMemory(&storeRegMemParams, sizeof(storeRegMemParams));
166 
167         storeRegMemParams.presStoreBuffer = m_perfStoreBufferMap[pOsContext];
168         storeRegMemParams.dwOffset        = offset;
169         storeRegMemParams.dwRegister      = reg;
170 
171         MEDIA_FEATURE_TABLE* skuTable = osInterface->pfnGetSkuTable(osInterface);
172         if(skuTable && MEDIA_IS_SKU(skuTable, FtrMemoryRemapSupport))
173         {
174             storeRegMemParams.dwOption = CCS_HW_FRONT_END_MMIO_REMAP;
175         }
176 
177         CHK_STATUS_RETURN(miInterface->AddMiStoreRegisterMemCmd(cmdBuffer, &storeRegMemParams));
178     };
179 
180     return MOS_STATUS_SUCCESS;
181 }
182 
StoreTSByPipeCtrl(MhwMiInterface * miInterface,PMOS_COMMAND_BUFFER cmdBuffer,PMOS_CONTEXT pOsContext,uint32_t offset)183 MOS_STATUS MediaPerfProfiler::StoreTSByPipeCtrl(
184     MhwMiInterface *miInterface,
185     PMOS_COMMAND_BUFFER cmdBuffer,
186     PMOS_CONTEXT pOsContext,
187     uint32_t offset)
188 {
189     CHK_NULL_RETURN(miInterface);
190 
191     if (m_miItf)
192     {
193         CHK_STATUS_RETURN(StoreTSByPipeCtrl(m_miItf, cmdBuffer, (MOS_CONTEXT_HANDLE)pOsContext, offset));
194     }
195     else
196     {
197         MHW_PIPE_CONTROL_PARAMS PipeControlParams;
198 
199         MOS_ZeroMemory(&PipeControlParams, sizeof(PipeControlParams));
200         PipeControlParams.dwResourceOffset = offset;
201         PipeControlParams.dwPostSyncOp     = MHW_FLUSH_WRITE_TIMESTAMP_REG;
202         PipeControlParams.dwFlushMode      = MHW_FLUSH_READ_CACHE;
203         PipeControlParams.presDest         = m_perfStoreBufferMap[pOsContext];
204 
205         CHK_STATUS_RETURN(miInterface->AddPipeControl(
206             cmdBuffer,
207             NULL,
208             &PipeControlParams));
209     }
210 
211     return MOS_STATUS_SUCCESS;
212 }
213 
StoreTSByMiFlush(MhwMiInterface * miInterface,PMOS_COMMAND_BUFFER cmdBuffer,PMOS_CONTEXT pOsContext,uint32_t offset)214 MOS_STATUS MediaPerfProfiler::StoreTSByMiFlush(
215     MhwMiInterface *miInterface,
216     PMOS_COMMAND_BUFFER cmdBuffer,
217     PMOS_CONTEXT pOsContext,
218     uint32_t offset)
219 {
220     CHK_NULL_RETURN(miInterface);
221 
222     if (m_miItf)
223     {
224         CHK_STATUS_RETURN(StoreTSByMiFlush(m_miItf, cmdBuffer, pOsContext, offset));
225     }
226     else
227     {
228         MHW_MI_FLUSH_DW_PARAMS FlushDwParams;
229 
230         MOS_ZeroMemory(&FlushDwParams, sizeof(FlushDwParams));
231         FlushDwParams.postSyncOperation             = MHW_FLUSH_WRITE_TIMESTAMP_REG;
232         FlushDwParams.dwResourceOffset              = offset;
233         FlushDwParams.pOsResource                   = m_perfStoreBufferMap[pOsContext];
234 
235         CHK_STATUS_RETURN(miInterface->AddMiFlushDwCmd(
236             cmdBuffer,
237             &FlushDwParams));
238     }
239 
240     return MOS_STATUS_SUCCESS;
241 }
242 
StoreDataNext(MhwMiInterface * miInterface,PMOS_COMMAND_BUFFER cmdBuffer,PMOS_CONTEXT pOsContext,uint32_t offset,uint32_t value)243 MOS_STATUS MediaPerfProfiler::StoreDataNext(
244     MhwMiInterface* miInterface,
245     PMOS_COMMAND_BUFFER cmdBuffer,
246     PMOS_CONTEXT pOsContext,
247     uint32_t offset,
248     uint32_t value)
249 {
250     CHK_NULL_RETURN(miInterface);
251 
252     std::shared_ptr<mhw::mi::Itf> miItf = std::static_pointer_cast<mhw::mi::Itf>(miInterface->GetNewMiInterface());
253 
254     if (miItf == nullptr)
255     {
256         return (StoreData(miInterface, cmdBuffer, pOsContext, offset, value));
257     }
258 
259     auto &storeDataParams            = miItf->MHW_GETPAR_F(MI_STORE_DATA_IMM)();
260     storeDataParams                  = {};
261     storeDataParams.pOsResource      = m_perfStoreBufferMap[pOsContext];
262     storeDataParams.dwResourceOffset = offset;
263     storeDataParams.dwValue          = value;
264 
265     CHK_STATUS_RETURN(miItf->MHW_ADDCMD_F(MI_STORE_DATA_IMM)(cmdBuffer));
266 
267     return MOS_STATUS_SUCCESS;
268 }
269 
StoreRegisterNext(MOS_INTERFACE * osInterface,MhwMiInterface * miInterface,PMOS_COMMAND_BUFFER cmdBuffer,uint32_t offset,uint32_t reg)270 MOS_STATUS MediaPerfProfiler::StoreRegisterNext(
271     MOS_INTERFACE* osInterface,
272     MhwMiInterface* miInterface,
273     PMOS_COMMAND_BUFFER cmdBuffer,
274     uint32_t offset,
275     uint32_t reg)
276 {
277     CHK_NULL_RETURN(osInterface);
278     CHK_NULL_RETURN(miInterface);
279 
280     std::shared_ptr<mhw::mi::Itf> miItf = std::static_pointer_cast<mhw::mi::Itf>(miInterface->GetNewMiInterface());
281 
282     if (miItf == nullptr)
283     {
284         return (StoreRegister(osInterface, miInterface, cmdBuffer, offset, reg));
285     }
286 
287     PMOS_CONTEXT pOsContext = osInterface->pOsContext;
288     CHK_NULL_RETURN(pOsContext);
289 
290     auto& storeRegMemParams           = miItf->MHW_GETPAR_F(MI_STORE_REGISTER_MEM)();
291     storeRegMemParams                 = {};
292     storeRegMemParams.presStoreBuffer = m_perfStoreBufferMap[pOsContext];
293     storeRegMemParams.dwOffset        = offset;
294     storeRegMemParams.dwRegister      = reg;
295 
296     MEDIA_FEATURE_TABLE* skuTable = osInterface->pfnGetSkuTable(osInterface);
297     if (skuTable && MEDIA_IS_SKU(skuTable, FtrMemoryRemapSupport))
298     {
299         storeRegMemParams.dwOption = CCS_HW_FRONT_END_MMIO_REMAP;
300     }
301 
302     CHK_STATUS_RETURN(miItf->MHW_ADDCMD_F(MI_STORE_REGISTER_MEM)(cmdBuffer));
303 
304     return MOS_STATUS_SUCCESS;
305 }
306 
StoreTSByPipeCtrlNext(MhwMiInterface * miInterface,PMOS_COMMAND_BUFFER cmdBuffer,PMOS_CONTEXT pOsContext,uint32_t offset)307 MOS_STATUS MediaPerfProfiler::StoreTSByPipeCtrlNext(
308     MhwMiInterface* miInterface,
309     PMOS_COMMAND_BUFFER cmdBuffer,
310     PMOS_CONTEXT pOsContext,
311     uint32_t offset)
312 {
313     CHK_NULL_RETURN(miInterface);
314 
315     std::shared_ptr<mhw::mi::Itf> miItf = std::static_pointer_cast<mhw::mi::Itf>(miInterface->GetNewMiInterface());
316 
317     if (miItf == nullptr)
318     {
319         return (StoreTSByPipeCtrl(miInterface, cmdBuffer, pOsContext, offset));
320     }
321 
322     auto& PipeControlParams            = miItf->MHW_GETPAR_F(PIPE_CONTROL)();
323     PipeControlParams                  = {};
324     PipeControlParams.dwResourceOffset = offset;
325     PipeControlParams.dwPostSyncOp     = MHW_FLUSH_WRITE_TIMESTAMP_REG;
326     PipeControlParams.dwFlushMode      = MHW_FLUSH_READ_CACHE;
327     PipeControlParams.presDest         = m_perfStoreBufferMap[pOsContext];
328 
329     CHK_STATUS_RETURN(miItf->MHW_ADDCMD_F(PIPE_CONTROL)(cmdBuffer));
330 
331     return MOS_STATUS_SUCCESS;
332 }
333 
StoreTSByMiFlushNext(MhwMiInterface * miInterface,PMOS_COMMAND_BUFFER cmdBuffer,PMOS_CONTEXT pOsContext,uint32_t offset)334 MOS_STATUS MediaPerfProfiler::StoreTSByMiFlushNext(
335     MhwMiInterface* miInterface,
336     PMOS_COMMAND_BUFFER cmdBuffer,
337     PMOS_CONTEXT pOsContext,
338     uint32_t offset)
339 {
340     CHK_NULL_RETURN(miInterface);
341 
342     std::shared_ptr<mhw::mi::Itf> miItf = std::static_pointer_cast<mhw::mi::Itf>(miInterface->GetNewMiInterface());
343 
344     if (miItf == nullptr)
345     {
346         return (StoreTSByMiFlush(miInterface, cmdBuffer, pOsContext, offset));
347     }
348 
349     auto& FlushDwParams             = miItf->MHW_GETPAR_F(MI_FLUSH_DW)();
350     FlushDwParams                   = {};
351     FlushDwParams.postSyncOperation = MHW_FLUSH_WRITE_TIMESTAMP_REG;
352     FlushDwParams.dwResourceOffset  = offset;
353     FlushDwParams.pOsResource       = m_perfStoreBufferMap[pOsContext];
354 
355     CHK_STATUS_RETURN(miItf->MHW_ADDCMD_F(MI_FLUSH_DW)(cmdBuffer));
356 
357     return MOS_STATUS_SUCCESS;
358 }
359 
AddPerfCollectStartCmd(void * context,MOS_INTERFACE * osInterface,MhwMiInterface * miInterface,MOS_COMMAND_BUFFER * cmdBuffer)360 MOS_STATUS MediaPerfProfiler::AddPerfCollectStartCmd(
361     void *context,
362     MOS_INTERFACE *osInterface,
363     MhwMiInterface *miInterface,
364     MOS_COMMAND_BUFFER *cmdBuffer)
365 {
366     MOS_STATUS status = MOS_STATUS_SUCCESS;
367 
368     CHK_NULL_RETURN(osInterface);
369     CHK_NULL_RETURN(miInterface);
370     CHK_NULL_RETURN(cmdBuffer);
371     CHK_NULL_RETURN(m_mutex);
372 
373     PMOS_CONTEXT pOsContext = osInterface->pOsContext;
374     CHK_NULL_RETURN(pOsContext);
375 
376     if (m_profilerEnabled == 0 || m_initializedMap[pOsContext] == false)
377     {
378         return status;
379     }
380 
381     uint32_t perfDataIndex = 0;
382 
383     MosUtilities::MosLockMutex(m_mutex);
384 
385     perfDataIndex = m_perfDataIndexMap[pOsContext];
386     m_perfDataIndexMap[pOsContext]++;
387 
388     if (BASE_OF_NODE(perfDataIndex) + sizeof(PerfEntry) > m_bufferSize)
389     {
390         MosUtilities::MosUnlockMutex(m_mutex);
391         MOS_OS_ASSERTMESSAGE("Reached maximum perf data buffer size, please increase it in Performance\\Perf Profiler Buffer Size");
392         return MOS_STATUS_NOT_ENOUGH_BUFFER;
393     }
394 
395     m_contextIndexMap[context] = perfDataIndex;
396     m_miItf = std::static_pointer_cast<mhw::mi::Itf>(miInterface->GetNewMiInterface());
397 
398     bool             rcsEngineUsed = false;
399     MOS_GPU_CONTEXT  gpuContext;
400 
401     gpuContext     = osInterface->pfnGetGpuContext(osInterface);
402     rcsEngineUsed = MOS_RCS_ENGINE_USED(gpuContext);
403 
404     if (m_multiprocess)
405     {
406         CHK_STATUS_UNLOCK_MUTEX_RETURN(StoreDataNext(
407             miInterface,
408             cmdBuffer,
409             pOsContext,
410             BASE_OF_NODE(perfDataIndex) + OFFSET_OF(PerfEntry, processId),
411             MosUtilities::MosGetPid()));
412     }
413 
414     CHK_STATUS_UNLOCK_MUTEX_RETURN(StoreDataNext(
415         miInterface,
416         cmdBuffer,
417         pOsContext,
418         BASE_OF_NODE(perfDataIndex) + OFFSET_OF(PerfEntry, perfTag),
419         osInterface->pfnGetPerfTag(osInterface)));
420 
421     CHK_STATUS_UNLOCK_MUTEX_RETURN(StoreDataNext(
422         miInterface,
423         cmdBuffer,
424         pOsContext,
425         BASE_OF_NODE(perfDataIndex) + OFFSET_OF(PerfEntry, engineTag),
426         GpuContextToGpuNode(gpuContext)));
427 
428     if (m_timerBase != 0)
429     {
430         CHK_STATUS_UNLOCK_MUTEX_RETURN(StoreDataNext(
431             miInterface,
432             cmdBuffer,
433             pOsContext,
434             BASE_OF_NODE(perfDataIndex) + OFFSET_OF(PerfEntry, timeStampBase),
435             m_timerBase));
436     }
437 
438     int8_t regIndex = 0;
439     for (regIndex = 0; regIndex < 8; regIndex++)
440     {
441         if (m_registers[regIndex] != 0)
442         {
443             CHK_STATUS_UNLOCK_MUTEX_RETURN(StoreRegisterNext(
444                 osInterface,
445                 miInterface,
446                 cmdBuffer,
447                 BASE_OF_NODE(perfDataIndex) + OFFSET_OF(PerfEntry, beginRegisterValue[regIndex]),
448                 m_registers[regIndex]));
449         }
450     }
451 
452     uint64_t beginCPUTimestamp = MosUtilities::MosGetCurTime();
453     uint32_t timeStamp[2];
454     MOS_SecureMemcpy(timeStamp, 2*sizeof(uint32_t), &beginCPUTimestamp, 2*sizeof(uint32_t));
455 
456     for (int i = 0; i < 2; i++)
457     {
458         CHK_STATUS_UNLOCK_MUTEX_RETURN(StoreDataNext(
459             miInterface,
460             cmdBuffer,
461             pOsContext,
462             BASE_OF_NODE(perfDataIndex) + OFFSET_OF(PerfEntry, beginCpuTime[i]),
463             timeStamp[i]));
464     }
465 
466     // The address of timestamp must be 8 bytes aligned.
467     uint32_t offset = BASE_OF_NODE(perfDataIndex) + OFFSET_OF(PerfEntry, beginTimeClockValue);
468     offset = MOS_ALIGN_CEIL(offset, 8);
469 
470     if (rcsEngineUsed)
471     {
472         CHK_STATUS_UNLOCK_MUTEX_RETURN(StoreTSByPipeCtrlNext(
473             miInterface,
474             cmdBuffer,
475             pOsContext,
476             offset));
477     }
478     else
479     {
480         CHK_STATUS_UNLOCK_MUTEX_RETURN(StoreTSByMiFlushNext(
481             miInterface,
482             cmdBuffer,
483             pOsContext,
484             offset));
485     }
486     //Decrease share pointer reference count
487     m_miItf = nullptr;
488     MosUtilities::MosUnlockMutex(m_mutex);
489 
490     return status;
491 }
492 
AddPerfCollectEndCmd(void * context,MOS_INTERFACE * osInterface,MhwMiInterface * miInterface,MOS_COMMAND_BUFFER * cmdBuffer)493 MOS_STATUS MediaPerfProfiler::AddPerfCollectEndCmd(
494     void *context,
495     MOS_INTERFACE *osInterface,
496     MhwMiInterface *miInterface,
497     MOS_COMMAND_BUFFER *cmdBuffer)
498 {
499     MOS_STATUS       status        = MOS_STATUS_SUCCESS;
500 
501     CHK_NULL_RETURN(osInterface);
502     CHK_NULL_RETURN(miInterface);
503     CHK_NULL_RETURN(cmdBuffer);
504 
505     PMOS_CONTEXT pOsContext = osInterface->pOsContext;
506     CHK_NULL_RETURN(pOsContext);
507 
508     if (m_profilerEnabled == 0 || m_initializedMap[pOsContext] == false)
509     {
510         return status;
511     }
512 
513     MOS_GPU_CONTEXT  gpuContext;
514     bool             rcsEngineUsed = false;
515     uint32_t         perfDataIndex = 0;
516 
517     MosUtilities::MosLockMutex(m_mutex);
518     m_miItf = std::static_pointer_cast<mhw::mi::Itf>(miInterface->GetNewMiInterface());
519 
520     gpuContext     = osInterface->pfnGetGpuContext(osInterface);
521     rcsEngineUsed = MOS_RCS_ENGINE_USED(gpuContext);
522 
523     perfDataIndex = m_contextIndexMap[context];
524 
525     int8_t regIndex = 0;
526     for (regIndex = 0; regIndex < 8; regIndex++)
527     {
528         if (m_registers[regIndex] != 0)
529         {
530             CHK_STATUS_UNLOCK_MUTEX_RETURN(StoreRegisterNext(
531                 osInterface,
532                 miInterface,
533                 cmdBuffer,
534                 BASE_OF_NODE(perfDataIndex) + OFFSET_OF(PerfEntry, endRegisterValue[regIndex]),
535                 m_registers[regIndex]));
536         }
537     }
538 
539     // The address of timestamp must be 8 bytes aligned.
540     uint32_t offset = BASE_OF_NODE(perfDataIndex) + OFFSET_OF(PerfEntry, endTimeClockValue);
541     offset = MOS_ALIGN_CEIL(offset, 8);
542 
543     if (rcsEngineUsed)
544     {
545         CHK_STATUS_UNLOCK_MUTEX_RETURN(StoreTSByPipeCtrlNext(
546             miInterface,
547             cmdBuffer,
548             pOsContext,
549             offset));
550     }
551     else
552     {
553         CHK_STATUS_UNLOCK_MUTEX_RETURN(StoreTSByMiFlushNext(
554             miInterface,
555             cmdBuffer,
556             pOsContext,
557             offset));
558     }
559     //Decrease share pointer reference count
560     m_miItf = nullptr;
561     MosUtilities::MosUnlockMutex(m_mutex);
562     return status;
563 }