| // |
| // Copyright © 2019 Arm Ltd. All rights reserved. |
| // SPDX-License-Identifier: MIT |
| // |
| |
| #include "PeriodicCounterCapture.hpp" |
| |
| #include <boost/log/trivial.hpp> |
| #include <iostream> |
| |
| namespace armnn |
| { |
| |
| namespace profiling |
| { |
| |
| void PeriodicCounterCapture::Start() |
| { |
| // Check if the capture thread is already running |
| if (m_IsRunning) |
| { |
| // The capture thread is already running |
| return; |
| } |
| |
| // Mark the capture thread as running |
| m_IsRunning = true; |
| |
| // Keep the capture procedure going until the capture thread is signalled to stop |
| m_KeepRunning.store(true); |
| |
| // Start the new capture thread. |
| m_PeriodCaptureThread = std::thread(&PeriodicCounterCapture::Capture, this, std::ref(m_ReadCounterValues)); |
| } |
| |
| void PeriodicCounterCapture::Stop() |
| { |
| // Signal the capture thread to stop |
| m_KeepRunning.store(false); |
| |
| // Check that the capture thread is running |
| if (m_PeriodCaptureThread.joinable()) |
| { |
| // Wait for the capture thread to complete operations |
| m_PeriodCaptureThread.join(); |
| } |
| |
| // Mark the capture thread as not running |
| m_IsRunning = false; |
| } |
| |
| CaptureData PeriodicCounterCapture::ReadCaptureData() |
| { |
| return m_CaptureDataHolder.GetCaptureData(); |
| } |
| |
| void PeriodicCounterCapture::Capture(const IReadCounterValues& readCounterValues) |
| { |
| do |
| { |
| // Check if the current capture data indicates that there's data capture |
| auto currentCaptureData = ReadCaptureData(); |
| const std::vector<uint16_t>& counterIds = currentCaptureData.GetCounterIds(); |
| |
| if (currentCaptureData.GetCapturePeriod() == 0 || counterIds.empty()) |
| { |
| // No data capture, wait the indicated capture period (milliseconds) |
| std::this_thread::sleep_for(std::chrono::milliseconds(5)); |
| continue; |
| } |
| |
| std::vector<std::pair<uint16_t, uint32_t>> values; |
| auto numCounters = counterIds.size(); |
| values.reserve(numCounters); |
| |
| // Create a vector of pairs of CounterIndexes and Values |
| for (uint16_t index = 0; index < numCounters; ++index) |
| { |
| auto requestedId = counterIds[index]; |
| uint32_t counterValue = 0; |
| try |
| { |
| counterValue = readCounterValues.GetCounterValue(requestedId); |
| } |
| catch (const Exception& e) |
| { |
| // Report the error and continue |
| BOOST_LOG_TRIVIAL(warning) << "An error has occurred when getting a counter value: " |
| << e.what() << std::endl; |
| continue; |
| } |
| values.emplace_back(std::make_pair(requestedId, counterValue)); |
| } |
| |
| #if USE_CLOCK_MONOTONIC_RAW |
| using clock = MonotonicClockRaw; |
| #else |
| using clock = std::chrono::steady_clock; |
| #endif |
| |
| // Take a timestamp |
| auto timestamp = clock::now(); |
| |
| // Write a Periodic Counter Capture packet to the Counter Stream Buffer |
| m_SendCounterPacket.SendPeriodicCounterCapturePacket( |
| static_cast<uint64_t>(timestamp.time_since_epoch().count()), values); |
| |
| // Notify the Send Thread that new data is available in the Counter Stream Buffer |
| m_SendCounterPacket.SetReadyToRead(); |
| |
| // Wait the indicated capture period (microseconds) |
| std::this_thread::sleep_for(std::chrono::microseconds(currentCaptureData.GetCapturePeriod())); |
| |
| } |
| while (m_KeepRunning.load()); |
| } |
| |
| } // namespace profiling |
| |
| } // namespace armnn |