diff options
-rw-r--r-- | CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/profiling/IReadCounterValue.hpp | 23 | ||||
-rw-r--r-- | src/profiling/PeriodicCounterCapture.cpp | 94 | ||||
-rw-r--r-- | src/profiling/PeriodicCounterCapture.hpp | 48 | ||||
-rw-r--r-- | src/profiling/test/ProfilingTests.cpp | 101 | ||||
-rw-r--r-- | src/profiling/test/SendCounterPacketTests.hpp | 4 |
6 files changed, 271 insertions, 2 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 6556c102bf..ef09fc02b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -440,10 +440,13 @@ list(APPEND armnn_sources src/profiling/ISendCounterPacket.hpp src/profiling/IPeriodicCounterCapture.hpp src/profiling/IProfilingConnection.hpp + src/profiling/IReadCounterValue.hpp src/profiling/Packet.cpp src/profiling/Packet.hpp src/profiling/PacketVersionResolver.cpp src/profiling/PacketVersionResolver.hpp + src/profiling/PeriodicCounterCapture.hpp + src/profiling/PeriodicCounterCapture.cpp src/profiling/PeriodicCounterSelectionCommandHandler.cpp src/profiling/PeriodicCounterSelectionCommandHandler.hpp src/profiling/ProfilingConnectionFactory.cpp diff --git a/src/profiling/IReadCounterValue.hpp b/src/profiling/IReadCounterValue.hpp new file mode 100644 index 0000000000..3a8236a0f4 --- /dev/null +++ b/src/profiling/IReadCounterValue.hpp @@ -0,0 +1,23 @@ +// +// Copyright © 2019 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +namespace armnn +{ + +namespace profiling +{ + +class IReadCounterValue +{ +public: + virtual void GetCounterValue(uint16_t index, uint32_t &value) const = 0; + virtual ~IReadCounterValue() {} +}; + +} // namespace profiling + +} // namespace armnn
\ No newline at end of file diff --git a/src/profiling/PeriodicCounterCapture.cpp b/src/profiling/PeriodicCounterCapture.cpp new file mode 100644 index 0000000000..5fbaa5d035 --- /dev/null +++ b/src/profiling/PeriodicCounterCapture.cpp @@ -0,0 +1,94 @@ +// +// Copyright © 2019 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "PeriodicCounterCapture.hpp" + +namespace armnn +{ + +namespace profiling +{ + +PeriodicCounterCapture::PeriodicCounterCapture(const Holder& data, ISendCounterPacket& packet, + const IReadCounterValue& readCounterValue) + : m_CaptureDataHolder(data) + , m_IsRunning(false) + , m_ReadCounterValue(readCounterValue) + , m_SendCounterPacket(packet) +{} + +CaptureData PeriodicCounterCapture::ReadCaptureData() +{ + return m_CaptureDataHolder.GetCaptureData(); +} + +void PeriodicCounterCapture::Functionality(const IReadCounterValue& readCounterValue) +{ + bool threadRunning = true; + + while(threadRunning) + { + auto currentCaptureData = ReadCaptureData(); + std::vector<uint16_t> counterIds = currentCaptureData.GetCounterIds(); + if (currentCaptureData.GetCapturePeriod() == 0 || counterIds.empty()) + { + threadRunning = false; + m_IsRunning.store(false, std::memory_order_relaxed); + } + else + { + std::vector<std::pair<uint16_t, uint32_t>> values; + auto numCounters = counterIds.size(); + values.reserve(numCounters); + + // Create vector of pairs of CounterIndexes and Values + uint32_t counterValue; + for (uint16_t index = 0; index < numCounters; ++index) + { + auto requestedId = counterIds[index]; + readCounterValue.GetCounterValue(requestedId, counterValue); + 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(); + + m_SendCounterPacket.SendPeriodicCounterCapturePacket( + static_cast<uint64_t>(timestamp.time_since_epoch().count()), values); + std::this_thread::sleep_for(std::chrono::milliseconds(currentCaptureData.GetCapturePeriod())); + } + } +} + +void PeriodicCounterCapture::Start() +{ + bool tstVal = false; + + if (m_IsRunning.compare_exchange_strong(tstVal, true, std::memory_order_relaxed)) + { + // Check that the thread execution is finished. + if (m_PeriodCaptureThread.joinable()) + { + m_PeriodCaptureThread.join(); + } + // Starts the new thread. + m_PeriodCaptureThread = std::thread(&PeriodicCounterCapture::Functionality, this, + std::ref(m_ReadCounterValue)); + } +} + +void PeriodicCounterCapture::Join() +{ + m_PeriodCaptureThread.join(); +} + +} // namespace profiling + +} // namespace armnn diff --git a/src/profiling/PeriodicCounterCapture.hpp b/src/profiling/PeriodicCounterCapture.hpp new file mode 100644 index 0000000000..8a7ff37bf9 --- /dev/null +++ b/src/profiling/PeriodicCounterCapture.hpp @@ -0,0 +1,48 @@ +// +// Copyright © 2019 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include "Holder.hpp" +#include "IPeriodicCounterCapture.hpp" +#include "Packet.hpp" +#include "IReadCounterValue.hpp" +#include "SendCounterPacket.hpp" + +#include "WallClockTimer.hpp" + +#include <atomic> +#include <chrono> +#include <mutex> +#include <thread> + +namespace armnn +{ + +namespace profiling +{ + +class PeriodicCounterCapture final : public IPeriodicCounterCapture +{ +public: + PeriodicCounterCapture(const Holder& data, ISendCounterPacket& packet, const IReadCounterValue& readCounterValue); + + void Start() override; + void Join(); + +private: + CaptureData ReadCaptureData(); + void Functionality(const IReadCounterValue& readCounterValue); + + const Holder& m_CaptureDataHolder; + std::atomic<bool> m_IsRunning; + std::thread m_PeriodCaptureThread; + const IReadCounterValue& m_ReadCounterValue; + ISendCounterPacket& m_SendCounterPacket; +}; + +} // namespace profiling + +} // namespace armnn diff --git a/src/profiling/test/ProfilingTests.cpp b/src/profiling/test/ProfilingTests.cpp index 1cf0e1e4b9..aec66d31ca 100644 --- a/src/profiling/test/ProfilingTests.cpp +++ b/src/profiling/test/ProfilingTests.cpp @@ -14,12 +14,14 @@ #include <Holder.hpp> #include <Packet.hpp> #include <PacketVersionResolver.hpp> +#include <PeriodicCounterCapture.hpp> #include <PeriodicCounterSelectionCommandHandler.hpp> #include <ProfilingStateMachine.hpp> #include <ProfilingService.hpp> #include <ProfilingUtils.hpp> #include <Runtime.hpp> #include <SocketProfilingConnection.hpp> +#include <IReadCounterValue.hpp> #include <armnn/Conversion.hpp> @@ -1878,4 +1880,103 @@ BOOST_AUTO_TEST_CASE(StringToSwTraceNameStringTest) BOOST_CHECK(buffer.empty()); } +BOOST_AUTO_TEST_CASE(CheckPeriodicCounterCaptureThread) +{ + class CaptureReader : public IReadCounterValue + { + public: + CaptureReader() {} + + void GetCounterValue(uint16_t index, uint32_t &value) const override + { + if (m_Data.count(index)) + { + value = m_Data.at(index); + } + else + { + value = 0; + } + } + + void SetCounterValue(uint16_t index, uint32_t value) + { + if (!m_Data.count(index)) + { + m_Data.insert(std::pair<uint16_t, uint32_t>(index, value)); + } + else + { + m_Data.at(index) = value; + } + } + + private: + std::map<uint16_t, uint32_t> m_Data; + }; + + Holder data; + std::vector<uint16_t> captureIds1 = { 0, 1 }; + std::vector<uint16_t> captureIds2; + + MockBuffer mockBuffer(512); + SendCounterPacket sendCounterPacket(mockBuffer); + + std::vector<uint16_t> counterIds; + CaptureReader captureReader; + + unsigned int valueA = 10; + unsigned int valueB = 15; + unsigned int numSteps = 5; + + PeriodicCounterCapture periodicCounterCapture(std::ref(data), std::ref(sendCounterPacket), captureReader); + + for(unsigned int i = 0; i < numSteps; ++i) + { + data.SetCaptureData(1, captureIds1); + captureReader.SetCounterValue(0, valueA * (i + 1)); + captureReader.SetCounterValue(1, valueB * (i + 1)); + + periodicCounterCapture.Start(); + + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + + periodicCounterCapture.Start(); + + data.SetCaptureData(0, captureIds2); + + periodicCounterCapture.Start(); + } + + periodicCounterCapture.Join(); + + unsigned int size = 0; + + const unsigned char* buffer = mockBuffer.GetReadBuffer(size); + + uint32_t headerWord0 = ReadUint32(buffer, 0); + uint32_t headerWord1 = ReadUint32(buffer, 4); + + BOOST_TEST(((headerWord0 >> 26) & 0x3F) == 1); // packet family + BOOST_TEST(((headerWord0 >> 19) & 0x3F) == 0); // packet class + BOOST_TEST(((headerWord0 >> 16) & 0x3) == 0); // packet type + BOOST_TEST(headerWord1 == 20); // data length + + uint32_t offset = 16; + uint16_t readIndex = ReadUint16(buffer, offset); + BOOST_TEST(0 == readIndex); + + offset += 2; + uint32_t readValue = ReadUint32(buffer, offset); + BOOST_TEST((valueA * numSteps) == readValue); + + offset += 4; + readIndex = ReadUint16(buffer, offset); + BOOST_TEST(1 == readIndex); + + offset += 2; + readValue = ReadUint32(buffer, offset); + BOOST_TEST((valueB * numSteps) == readValue); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/profiling/test/SendCounterPacketTests.hpp b/src/profiling/test/SendCounterPacketTests.hpp index 6c7bb50362..5d5dfd14c7 100644 --- a/src/profiling/test/SendCounterPacketTests.hpp +++ b/src/profiling/test/SendCounterPacketTests.hpp @@ -21,8 +21,8 @@ class MockBuffer : public IBufferWrapper { public: MockBuffer(unsigned int size) - : m_BufferSize(size), - m_Buffer(std::make_unique<unsigned char[]>(size)) {} + : m_BufferSize(size), + m_Buffer(std::make_unique<unsigned char[]>(size)) {} unsigned char* Reserve(unsigned int requestedSize, unsigned int& reservedSize) override { |