1 //
2 // Copyright © 2019 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5
6 #include "PeriodicCounterCapture.hpp"
7
8 #include <common/include/Logging.hpp>
9
10 #include <iostream>
11
12 namespace arm
13 {
14
15 namespace pipe
16 {
17
Start()18 void PeriodicCounterCapture::Start()
19 {
20 // Check if the capture thread is already running
21 if (m_IsRunning)
22 {
23 // The capture thread is already running
24 return;
25 }
26
27 // Mark the capture thread as running
28 m_IsRunning = true;
29
30 // Keep the capture procedure going until the capture thread is signalled to stop
31 m_KeepRunning.store(true);
32
33 // Start the new capture thread.
34 #if !defined(ARMNN_DISABLE_THREADS)
35 m_PeriodCaptureThread = std::thread(&PeriodicCounterCapture::Capture, this, std::ref(m_ReadCounterValues));
36 #endif
37 }
38
Stop()39 void PeriodicCounterCapture::Stop()
40 {
41 // Signal the capture thread to stop
42 m_KeepRunning.store(false);
43
44 #if !defined(ARMNN_DISABLE_THREADS)
45 // Check that the capture thread is running
46 if (m_PeriodCaptureThread.joinable())
47 {
48 // Wait for the capture thread to complete operations
49 m_PeriodCaptureThread.join();
50 }
51 #endif
52
53 // Mark the capture thread as not running
54 m_IsRunning = false;
55 }
56
ReadCaptureData()57 CaptureData PeriodicCounterCapture::ReadCaptureData()
58 {
59 return m_CaptureDataHolder.GetCaptureData();
60 }
61
DispatchPeriodicCounterCapturePacket(const std::string & backendId,const std::vector<Timestamp> & timestampValues)62 void PeriodicCounterCapture::DispatchPeriodicCounterCapturePacket(
63 const std::string& backendId, const std::vector<Timestamp>& timestampValues)
64 {
65 // Report counter values
66 for (const auto& timestampInfo : timestampValues)
67 {
68 std::vector<CounterValue> backendCounterValues = timestampInfo.counterValues;
69 for_each(backendCounterValues.begin(), backendCounterValues.end(), [&](CounterValue& backendCounterValue)
70 {
71 // translate the counterId to globalCounterId
72 backendCounterValue.counterId = m_CounterIdMap.GetGlobalId(backendCounterValue.counterId, backendId);
73 });
74
75 // Send Periodic Counter Capture Packet for the Timestamp
76 m_SendCounterPacket.SendPeriodicCounterCapturePacket(timestampInfo.timestamp, backendCounterValues);
77 }
78 }
79
Capture(IReadCounterValues & readCounterValues)80 void PeriodicCounterCapture::Capture(IReadCounterValues& readCounterValues)
81 {
82 do
83 {
84 // Check if the current capture data indicates that there's data capture
85 auto currentCaptureData = ReadCaptureData();
86 const std::vector<uint16_t>& counterIds = currentCaptureData.GetCounterIds();
87 const uint32_t capturePeriod = currentCaptureData.GetCapturePeriod();
88
89 if (capturePeriod == 0)
90 {
91 // No data capture, wait the indicated capture period (milliseconds), if it is not zero
92 #if !defined(ARMNN_DISABLE_THREADS)
93 std::this_thread::sleep_for(std::chrono::milliseconds(50u));
94 #endif
95 continue;
96 }
97
98 if(counterIds.size() != 0)
99 {
100 std::vector<CounterValue> counterValues;
101
102 auto numCounters = counterIds.size();
103 counterValues.reserve(numCounters);
104
105 // Create a vector of pairs of CounterIndexes and Values
106 for (uint16_t index = 0; index < numCounters; ++index)
107 {
108 auto requestedId = counterIds[index];
109 uint32_t counterValue = 0;
110 try
111 {
112 counterValue = readCounterValues.GetDeltaCounterValue(requestedId);
113 }
114 catch (const arm::pipe::ProfilingException& e)
115 {
116 // Report the error and continue
117 ARM_PIPE_LOG(warning) << "An error has occurred when getting a counter value: "
118 << e.what();
119 continue;
120 }
121
122 counterValues.emplace_back(CounterValue {requestedId, counterValue });
123 }
124
125 // Send Periodic Counter Capture Packet for the Timestamp
126 m_SendCounterPacket.SendPeriodicCounterCapturePacket(GetTimestamp(), counterValues);
127 }
128
129 // Report counter values for each active backend
130 auto activeBackends = currentCaptureData.GetActiveBackends();
131 for_each(activeBackends.begin(), activeBackends.end(), [&](const std::string& backendId)
132 {
133 DispatchPeriodicCounterCapturePacket(
134 backendId, m_BackendProfilingContexts.at(backendId)->ReportCounterValues());
135 });
136
137 // Wait the indicated capture period (microseconds)
138 #if !defined(ARMNN_DISABLE_THREADS)
139 std::this_thread::sleep_for(std::chrono::microseconds(capturePeriod));
140 #endif
141 }
142 while (m_KeepRunning.load());
143 }
144
145 } // namespace pipe
146
147 } // namespace arm
148