| // |
| // Copyright © 2017 Arm Ltd. All rights reserved. |
| // SPDX-License-Identifier: MIT |
| // |
| |
| #include "../SendCounterPacket.hpp" |
| #include "../ProfilingUtils.hpp" |
| #include "../EncodeVersion.hpp" |
| |
| #include <armnn/Exceptions.hpp> |
| |
| #include <boost/test/unit_test.hpp> |
| #include <boost/numeric/conversion/cast.hpp> |
| |
| #include <chrono> |
| #include <iostream> |
| |
| BOOST_AUTO_TEST_SUITE(SendCounterPacketTests) |
| |
| using namespace armnn::profiling; |
| |
| class MockBuffer : public IBufferWrapper |
| { |
| public: |
| MockBuffer(unsigned int size) |
| : m_BufferSize(size), |
| m_Buffer(std::make_unique<unsigned char[]>(size)) {} |
| |
| unsigned char* Reserve(unsigned int requestedSize, unsigned int& reservedSize) override |
| { |
| if (requestedSize > m_BufferSize) |
| { |
| reservedSize = m_BufferSize; |
| } |
| else |
| { |
| reservedSize = requestedSize; |
| } |
| |
| return m_Buffer.get(); |
| } |
| |
| void Commit(unsigned int size) override {} |
| |
| const unsigned char* GetReadBuffer(unsigned int& size) override |
| { |
| size = static_cast<unsigned int>(strlen(reinterpret_cast<const char*>(m_Buffer.get())) + 1); |
| return m_Buffer.get(); |
| } |
| |
| void Release( unsigned int size) override {} |
| |
| private: |
| unsigned int m_BufferSize; |
| std::unique_ptr<unsigned char[]> m_Buffer; |
| }; |
| |
| class MockSendCounterPacket : public ISendCounterPacket |
| { |
| public: |
| MockSendCounterPacket(IBufferWrapper& sendBuffer) : m_Buffer(sendBuffer) {} |
| |
| void SendStreamMetaDataPacket() override |
| { |
| std::string message("SendStreamMetaDataPacket"); |
| unsigned int reserved = 0; |
| unsigned char* buffer = m_Buffer.Reserve(1024, reserved); |
| memcpy(buffer, message.c_str(), static_cast<unsigned int>(message.size()) + 1); |
| } |
| |
| void SendCounterDirectoryPacket(const CounterDirectory& counterDirectory) override |
| { |
| std::string message("SendCounterDirectoryPacket"); |
| unsigned int reserved = 0; |
| unsigned char* buffer = m_Buffer.Reserve(1024, reserved); |
| memcpy(buffer, message.c_str(), static_cast<unsigned int>(message.size()) + 1); |
| } |
| |
| void SendPeriodicCounterCapturePacket(uint64_t timestamp, |
| const std::vector<std::pair<uint16_t, uint32_t>>& values) override |
| { |
| std::string message("SendPeriodicCounterCapturePacket"); |
| unsigned int reserved = 0; |
| unsigned char* buffer = m_Buffer.Reserve(1024, reserved); |
| memcpy(buffer, message.c_str(), static_cast<unsigned int>(message.size()) + 1); |
| } |
| |
| void SendPeriodicCounterSelectionPacket(uint32_t capturePeriod, |
| const std::vector<uint16_t>& selectedCounterIds) override |
| { |
| std::string message("SendPeriodicCounterSelectionPacket"); |
| unsigned int reserved = 0; |
| unsigned char* buffer = m_Buffer.Reserve(1024, reserved); |
| memcpy(buffer, message.c_str(), static_cast<unsigned int>(message.size()) + 1); |
| m_Buffer.Commit(reserved); |
| } |
| |
| void SetReadyToRead() override |
| {} |
| |
| private: |
| IBufferWrapper& m_Buffer; |
| }; |
| |
| BOOST_AUTO_TEST_CASE(MockSendCounterPacketTest) |
| { |
| unsigned int size = 0; |
| |
| MockBuffer mockBuffer(512); |
| MockSendCounterPacket sendCounterPacket(mockBuffer); |
| |
| sendCounterPacket.SendStreamMetaDataPacket(); |
| const char* buffer = reinterpret_cast<const char*>(mockBuffer.GetReadBuffer(size)); |
| |
| BOOST_TEST(strcmp(buffer, "SendStreamMetaDataPacket") == 0); |
| |
| CounterDirectory counterDirectory(1, "counter_directory", 0, 0, 0); |
| sendCounterPacket.SendCounterDirectoryPacket(counterDirectory); |
| |
| BOOST_TEST(strcmp(buffer, "SendCounterDirectoryPacket") == 0); |
| |
| uint64_t timestamp = 0; |
| std::vector<std::pair<uint16_t, uint32_t>> indexValuePairs; |
| |
| sendCounterPacket.SendPeriodicCounterCapturePacket(timestamp, indexValuePairs); |
| |
| BOOST_TEST(strcmp(buffer, "SendPeriodicCounterCapturePacket") == 0); |
| |
| uint32_t capturePeriod = 0; |
| std::vector<uint16_t> selectedCounterIds; |
| sendCounterPacket.SendPeriodicCounterSelectionPacket(capturePeriod, selectedCounterIds); |
| |
| BOOST_TEST(strcmp(buffer, "SendPeriodicCounterSelectionPacket") == 0); |
| |
| } |
| |
| BOOST_AUTO_TEST_CASE(SendPeriodicCounterSelectionPacketTest) |
| { |
| // Error no space left in buffer |
| MockBuffer mockBuffer1(10); |
| SendCounterPacket sendPacket1(mockBuffer1); |
| |
| uint32_t capturePeriod = 1000; |
| std::vector<uint16_t> selectedCounterIds; |
| BOOST_CHECK_THROW(sendPacket1.SendPeriodicCounterSelectionPacket(capturePeriod, selectedCounterIds), |
| armnn::profiling::BufferExhaustion); |
| |
| // Packet without any counters |
| MockBuffer mockBuffer2(512); |
| SendCounterPacket sendPacket2(mockBuffer2); |
| |
| sendPacket2.SendPeriodicCounterSelectionPacket(capturePeriod, selectedCounterIds); |
| unsigned int sizeRead = 0; |
| const unsigned char* readBuffer2 = mockBuffer2.GetReadBuffer(sizeRead); |
| |
| uint32_t headerWord0 = ReadUint32(readBuffer2, 0); |
| uint32_t headerWord1 = ReadUint32(readBuffer2, 4); |
| uint32_t period = ReadUint32(readBuffer2, 8); |
| |
| BOOST_TEST(((headerWord0 >> 26) & 0x3F) == 0); // packet family |
| BOOST_TEST(((headerWord0 >> 16) & 0x3FF) == 4); // packet id |
| BOOST_TEST(headerWord1 == 4); // data lenght |
| BOOST_TEST(period == 1000); // capture period |
| |
| // Full packet message |
| MockBuffer mockBuffer3(512); |
| SendCounterPacket sendPacket3(mockBuffer3); |
| |
| selectedCounterIds.reserve(5); |
| selectedCounterIds.emplace_back(100); |
| selectedCounterIds.emplace_back(200); |
| selectedCounterIds.emplace_back(300); |
| selectedCounterIds.emplace_back(400); |
| selectedCounterIds.emplace_back(500); |
| sendPacket3.SendPeriodicCounterSelectionPacket(capturePeriod, selectedCounterIds); |
| sizeRead = 0; |
| const unsigned char* readBuffer3 = mockBuffer3.GetReadBuffer(sizeRead); |
| |
| headerWord0 = ReadUint32(readBuffer3, 0); |
| headerWord1 = ReadUint32(readBuffer3, 4); |
| period = ReadUint32(readBuffer3, 8); |
| |
| BOOST_TEST(((headerWord0 >> 26) & 0x3F) == 0); // packet family |
| BOOST_TEST(((headerWord0 >> 16) & 0x3FF) == 4); // packet id |
| BOOST_TEST(headerWord1 == 14); // data lenght |
| BOOST_TEST(period == 1000); // capture period |
| |
| uint16_t counterId = 0; |
| uint32_t offset = 12; |
| |
| // Counter Ids |
| for(const uint16_t& id : selectedCounterIds) |
| { |
| counterId = ReadUint16(readBuffer3, offset); |
| BOOST_TEST(counterId == id); |
| offset += 2; |
| } |
| } |
| |
| BOOST_AUTO_TEST_CASE(SendPeriodicCounterCapturePacketTest) |
| { |
| // Error no space left in buffer |
| MockBuffer mockBuffer1(10); |
| SendCounterPacket sendPacket1(mockBuffer1); |
| |
| auto captureTimestamp = std::chrono::steady_clock::now(); |
| uint64_t time = static_cast<uint64_t >(captureTimestamp.time_since_epoch().count()); |
| std::vector<std::pair<uint16_t, uint32_t>> indexValuePairs; |
| |
| BOOST_CHECK_THROW(sendPacket1.SendPeriodicCounterCapturePacket(time, indexValuePairs), |
| BufferExhaustion); |
| |
| // Packet without any counters |
| MockBuffer mockBuffer2(512); |
| SendCounterPacket sendPacket2(mockBuffer2); |
| |
| sendPacket2.SendPeriodicCounterCapturePacket(time, indexValuePairs); |
| unsigned int sizeRead = 0; |
| const unsigned char* readBuffer2 = mockBuffer2.GetReadBuffer(sizeRead); |
| |
| uint32_t headerWord0 = ReadUint32(readBuffer2, 0); |
| uint32_t headerWord1 = ReadUint32(readBuffer2, 4); |
| uint64_t readTimestamp = ReadUint64(readBuffer2, 8); |
| |
| 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 == 8); // data length |
| BOOST_TEST(time == readTimestamp); // capture period |
| |
| // Full packet message |
| MockBuffer mockBuffer3(512); |
| SendCounterPacket sendPacket3(mockBuffer3); |
| |
| indexValuePairs.reserve(5); |
| indexValuePairs.emplace_back(std::make_pair<uint16_t, uint32_t >(0, 100)); |
| indexValuePairs.emplace_back(std::make_pair<uint16_t, uint32_t >(1, 200)); |
| indexValuePairs.emplace_back(std::make_pair<uint16_t, uint32_t >(2, 300)); |
| indexValuePairs.emplace_back(std::make_pair<uint16_t, uint32_t >(3, 400)); |
| indexValuePairs.emplace_back(std::make_pair<uint16_t, uint32_t >(4, 500)); |
| sendPacket3.SendPeriodicCounterCapturePacket(time, indexValuePairs); |
| sizeRead = 0; |
| const unsigned char* readBuffer3 = mockBuffer3.GetReadBuffer(sizeRead); |
| |
| headerWord0 = ReadUint32(readBuffer3, 0); |
| headerWord1 = ReadUint32(readBuffer3, 4); |
| uint64_t readTimestamp2 = ReadUint64(readBuffer3, 8); |
| |
| 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 == 38); // data length |
| BOOST_TEST(time == readTimestamp2); // capture period |
| |
| uint16_t counterIndex = 0; |
| uint32_t counterValue = 100; |
| uint32_t offset = 16; |
| |
| // Counter Ids |
| for (auto it = indexValuePairs.begin(), end = indexValuePairs.end(); it != end; ++it) |
| { |
| // Check Counter Index |
| uint16_t readIndex = ReadUint16(readBuffer3, offset); |
| BOOST_TEST(counterIndex == readIndex); |
| counterIndex++; |
| offset += 2; |
| |
| // Check Counter Value |
| uint32_t readValue = ReadUint32(readBuffer3, offset); |
| BOOST_TEST(counterValue == readValue); |
| counterValue += 100; |
| offset += 4; |
| } |
| |
| } |
| |
| BOOST_AUTO_TEST_CASE(SendStreamMetaDataPacketTest) |
| { |
| using boost::numeric_cast; |
| |
| uint32_t sizeUint32 = numeric_cast<uint32_t>(sizeof(uint32_t)); |
| |
| // Error no space left in buffer |
| MockBuffer mockBuffer1(10); |
| SendCounterPacket sendPacket1(mockBuffer1); |
| BOOST_CHECK_THROW(sendPacket1.SendStreamMetaDataPacket(), armnn::profiling::BufferExhaustion); |
| |
| // Full metadata packet |
| |
| std::string processName = GetProcessName().substr(0, 60); |
| |
| uint32_t infoSize = numeric_cast<uint32_t>(GetSoftwareInfo().size()) > 0 ? |
| numeric_cast<uint32_t>(GetSoftwareInfo().size()) + 1 : 0; |
| uint32_t hardwareVersionSize = numeric_cast<uint32_t>(GetHardwareVersion().size()) > 0 ? |
| numeric_cast<uint32_t>(GetHardwareVersion().size()) + 1 : 0; |
| uint32_t softwareVersionSize = numeric_cast<uint32_t>(GetSoftwareVersion().size()) > 0 ? |
| numeric_cast<uint32_t>(GetSoftwareVersion().size()) + 1 : 0; |
| uint32_t processNameSize = numeric_cast<uint32_t>(processName.size()) > 0 ? |
| numeric_cast<uint32_t>(processName.size()) + 1 : 0; |
| |
| uint32_t packetEntries = 5; |
| |
| MockBuffer mockBuffer2(512); |
| SendCounterPacket sendPacket2(mockBuffer2); |
| sendPacket2.SendStreamMetaDataPacket(); |
| unsigned int sizeRead = 0; |
| const unsigned char* readBuffer2 = mockBuffer2.GetReadBuffer(sizeRead); |
| |
| uint32_t headerWord0 = ReadUint32(readBuffer2, 0); |
| uint32_t headerWord1 = ReadUint32(readBuffer2, sizeUint32); |
| |
| BOOST_TEST(((headerWord0 >> 26) & 0x3F) == 0); // packet family |
| BOOST_TEST(((headerWord0 >> 16) & 0x3FF) == 0); // packet id |
| |
| uint32_t totalLength = numeric_cast<uint32_t>(2 * sizeUint32 + 10 * sizeUint32 + infoSize + hardwareVersionSize + |
| softwareVersionSize + processNameSize + sizeUint32 + |
| 2 * packetEntries * sizeUint32); |
| |
| BOOST_TEST(headerWord1 == totalLength - (2 * sizeUint32)); // data length |
| |
| uint32_t offset = sizeUint32 * 2; |
| BOOST_TEST(ReadUint32(readBuffer2, offset) == SendCounterPacket::PIPE_MAGIC); // pipe_magic |
| offset += sizeUint32; |
| BOOST_TEST(ReadUint32(readBuffer2, offset) == EncodeVersion(1, 0, 0)); // stream_metadata_version |
| offset += sizeUint32; |
| BOOST_TEST(ReadUint32(readBuffer2, offset) == SendCounterPacket::MAX_METADATA_PACKET_LENGTH); // max_data_len |
| offset += sizeUint32; |
| BOOST_TEST(ReadUint32(readBuffer2, offset) == numeric_cast<uint32_t>(getpid())); // pid |
| offset += sizeUint32; |
| uint32_t poolOffset = 10 * sizeUint32; |
| BOOST_TEST(ReadUint32(readBuffer2, offset) == (infoSize ? poolOffset : 0)); // offset_info |
| offset += sizeUint32; |
| poolOffset += infoSize; |
| BOOST_TEST(ReadUint32(readBuffer2, offset) == (hardwareVersionSize ? poolOffset : 0)); // offset_hw_version |
| offset += sizeUint32; |
| poolOffset += hardwareVersionSize; |
| BOOST_TEST(ReadUint32(readBuffer2, offset) == (softwareVersionSize ? poolOffset : 0)); // offset_sw_version |
| offset += sizeUint32; |
| poolOffset += softwareVersionSize; |
| BOOST_TEST(ReadUint32(readBuffer2, offset) == (processNameSize ? poolOffset : 0)); // offset_process_name |
| offset += sizeUint32; |
| poolOffset += processNameSize; |
| BOOST_TEST(ReadUint32(readBuffer2, offset) == (packetEntries ? poolOffset : 0)); // offset_packet_version_table |
| offset += sizeUint32; |
| BOOST_TEST(ReadUint32(readBuffer2, offset) == 0); // reserved |
| |
| offset += sizeUint32; |
| if (infoSize) |
| { |
| BOOST_TEST(strcmp(reinterpret_cast<const char *>(&readBuffer2[offset]), GetSoftwareInfo().c_str()) == 0); |
| offset += infoSize; |
| } |
| |
| if (hardwareVersionSize) |
| { |
| BOOST_TEST(strcmp(reinterpret_cast<const char *>(&readBuffer2[offset]), GetHardwareVersion().c_str()) == 0); |
| offset += hardwareVersionSize; |
| } |
| |
| if (softwareVersionSize) |
| { |
| BOOST_TEST(strcmp(reinterpret_cast<const char *>(&readBuffer2[offset]), GetSoftwareVersion().c_str()) == 0); |
| offset += softwareVersionSize; |
| } |
| |
| if (processNameSize) |
| { |
| BOOST_TEST(strcmp(reinterpret_cast<const char *>(&readBuffer2[offset]), GetProcessName().c_str()) == 0); |
| offset += processNameSize; |
| } |
| |
| if (packetEntries) |
| { |
| BOOST_TEST((ReadUint32(readBuffer2, offset) >> 16) == packetEntries); |
| offset += sizeUint32; |
| for (uint32_t i = 0; i < packetEntries; ++i) |
| { |
| BOOST_TEST(((ReadUint32(readBuffer2, offset) >> 26) & 0x3F) == 0); |
| BOOST_TEST(((ReadUint32(readBuffer2, offset) >> 16) & 0x3FF) == i); |
| offset += sizeUint32; |
| BOOST_TEST(ReadUint32(readBuffer2, offset) == EncodeVersion(1, 0, 0)); |
| offset += sizeUint32; |
| } |
| } |
| |
| BOOST_TEST(offset == totalLength); |
| } |
| |
| |
| BOOST_AUTO_TEST_SUITE_END() |