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