aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorFinn Williams <Finn.Williams@arm.com>2019-10-15 14:22:13 +0100
committerJim Flynn Arm <jim.flynn@arm.com>2019-10-21 16:52:03 +0000
commit15db745d59a796fd05e3bb5a8b735f25710bdf22 (patch)
tree01e5e320bd92cb152464adb82c02e3b37342b571 /tests
parent422f2fb6c7ef13e48124991af6f27e78934b8ece (diff)
downloadarmnn-15db745d59a796fd05e3bb5a8b735f25710bdf22.tar.gz
IVGCVSW-3989 Create the Counter Directory Decoder
Signed-off-by: Finn Williams <Finn.Williams@arm.com> Change-Id: If388e60434eae39d82b639d2275680679963624c
Diffstat (limited to 'tests')
-rw-r--r--tests/profiling/gatordmock/CommandFileParser.cpp9
-rw-r--r--tests/profiling/gatordmock/CounterDirectory.hpp263
-rw-r--r--tests/profiling/gatordmock/DirectoryCaptureCommandHandler.cpp341
-rw-r--r--tests/profiling/gatordmock/DirectoryCaptureCommandHandler.hpp75
-rw-r--r--tests/profiling/gatordmock/GatordMockMain.cpp5
-rw-r--r--tests/profiling/gatordmock/GatordMockService.cpp10
-rw-r--r--tests/profiling/gatordmock/GatordMockService.hpp3
-rw-r--r--tests/profiling/gatordmock/MockUtils.cpp57
-rw-r--r--tests/profiling/gatordmock/MockUtils.hpp25
-rw-r--r--tests/profiling/gatordmock/PeriodicCounterCaptureCommandHandler.cpp21
-rw-r--r--tests/profiling/gatordmock/tests/GatordMockTests.cpp167
11 files changed, 923 insertions, 53 deletions
diff --git a/tests/profiling/gatordmock/CommandFileParser.cpp b/tests/profiling/gatordmock/CommandFileParser.cpp
index e86763b55f..d08e72cadd 100644
--- a/tests/profiling/gatordmock/CommandFileParser.cpp
+++ b/tests/profiling/gatordmock/CommandFileParser.cpp
@@ -34,6 +34,15 @@ void CommandFileParser::ParseFile(std::string CommandFile, GatordMockService& mo
std::string command = tokens[0];
+ if (command == "LIST")
+ {
+ // Expected format for the SET command
+ //
+ // LIST
+ //
+
+ mockService.SendRequestCounterDir();
+ }
if (command == "SET")
{
// Expected format for the SET command
diff --git a/tests/profiling/gatordmock/CounterDirectory.hpp b/tests/profiling/gatordmock/CounterDirectory.hpp
new file mode 100644
index 0000000000..7b45e661e0
--- /dev/null
+++ b/tests/profiling/gatordmock/CounterDirectory.hpp
@@ -0,0 +1,263 @@
+//
+// Copyright © 2019 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+
+#include "GatordMockService.hpp"
+#include "MockUtils.hpp"
+
+#include "Packet.hpp"
+#include "CommandHandlerFunctor.hpp"
+#include "SendCounterPacket.hpp"
+#include "IPeriodicCounterCapture.hpp"
+
+#include <vector>
+#include <thread>
+#include <atomic>
+#include <iostream>
+#include <functional>
+
+namespace armnn
+{
+
+namespace gatordmock
+{
+
+struct EventRecord
+{
+ uint16_t m_CounterUid;
+ uint16_t m_MaxCounterUid;
+ uint16_t m_DeviceUid;
+ uint16_t m_CounterSetUid;
+ uint16_t m_CounterClass;
+ uint16_t m_CounterInterpolation;
+ double m_CounterMultiplier;
+ std::string m_CounterName;
+ std::string m_CounterDescription;
+ std::string m_CounterUnits;
+
+ static void printHeader(std::string categoryName)
+ {
+ std::string header;
+
+ header.append(gatordmock::CentreAlignFormatting("Counter Name", 20));
+ header.append(" | ");
+ header.append(gatordmock::CentreAlignFormatting("Description", 50));
+ header.append(" | ");
+ header.append(gatordmock::CentreAlignFormatting("Units", 14));
+ header.append(" | ");
+ header.append(gatordmock::CentreAlignFormatting("UID", 6));
+ header.append(" | ");
+ header.append(gatordmock::CentreAlignFormatting("Max UID",10));
+ header.append(" | ");
+ header.append(gatordmock::CentreAlignFormatting("Class", 8));
+ header.append(" | ");
+ header.append(gatordmock::CentreAlignFormatting("Interpolation", 14));
+ header.append(" | ");
+ header.append(gatordmock::CentreAlignFormatting("Multiplier", 20));
+ header.append(" | ");
+ header.append(gatordmock::CentreAlignFormatting("Counter set UID", 16));
+ header.append(" | ");
+ header.append(gatordmock::CentreAlignFormatting("Device UID", 14));
+ header.append("\n");
+
+ std::cout << "\n" << "\n";
+ std::cout << gatordmock::CentreAlignFormatting("EVENTS IN CATEGORY: " + categoryName,
+ static_cast<int>(header.size()));
+ std::cout << "\n";
+ std::cout << std::string(header.size(), '=') << "\n";
+ std::cout << header;
+ }
+
+ void printContents() const
+ {
+ std::string body;
+
+ body.append(gatordmock::CentreAlignFormatting(m_CounterName, 20));
+ body.append(" | ");
+ body.append(gatordmock::CentreAlignFormatting(m_CounterDescription, 50));
+ body.append(" | ");
+ body.append(gatordmock::CentreAlignFormatting(m_CounterUnits, 14));
+ body.append(" | ");
+ body.append(gatordmock::CentreAlignFormatting(std::to_string(m_CounterUid), 6));
+ body.append(" | ");
+ body.append(gatordmock::CentreAlignFormatting(std::to_string(m_MaxCounterUid), 10));
+ body.append(" | ");
+ body.append(gatordmock::CentreAlignFormatting(std::to_string(m_CounterClass), 8));
+ body.append(" | ");
+ body.append(gatordmock::CentreAlignFormatting(std::to_string(m_CounterInterpolation), 14));
+ body.append(" | ");
+ body.append(gatordmock::CentreAlignFormatting(std::to_string(m_CounterMultiplier), 20));
+ body.append(" | ");
+ body.append(gatordmock::CentreAlignFormatting(std::to_string(m_CounterSetUid), 16));
+ body.append(" | ");
+ body.append(gatordmock::CentreAlignFormatting(std::to_string(m_DeviceUid), 14));
+
+ body.append("\n");
+
+ std::cout << std::string(body.size(), '-') << "\n";
+
+ std::cout << body;
+ }
+};
+
+struct CategoryRecord
+{
+ uint16_t m_DeviceUid;
+ uint16_t m_CounterSet;
+ uint16_t m_EventCount;
+ std::string m_CategoryName;
+ std::vector<EventRecord> m_EventRecords;
+
+ void print() const
+ {
+ std::string body;
+ std::string header;
+
+ header.append(gatordmock::CentreAlignFormatting("Name", 20));
+ header.append(" | ");
+ header.append(gatordmock::CentreAlignFormatting("Device", 12));
+ header.append(" | ");
+ header.append(gatordmock::CentreAlignFormatting("Counter set UID:", 16));
+ header.append(" | ");
+ header.append(gatordmock::CentreAlignFormatting("Event Count", 14));
+ header.append("\n");
+
+ body.append(gatordmock::CentreAlignFormatting(m_CategoryName, 20));
+ body.append(" | ");
+ body.append(gatordmock::CentreAlignFormatting(std::to_string(m_DeviceUid), 12));
+ body.append(" | ");
+ body.append(gatordmock::CentreAlignFormatting(std::to_string(m_CounterSet), 16));
+ body.append(" | ");
+ body.append(gatordmock::CentreAlignFormatting(std::to_string(m_EventCount), 14));
+
+ std::cout << "\n" << "\n";
+ std::cout << gatordmock::CentreAlignFormatting("CATEGORY", static_cast<int>(header.size()));
+ std::cout << "\n";
+ std::cout << std::string(header.size(), '=') << "\n";
+
+ std::cout<< header;
+
+ std::cout << std::string(body.size(), '-') << "\n";
+
+ std::cout<< body;
+
+ if(m_EventRecords.size() > 0)
+ {
+ EventRecord::printHeader(m_CategoryName);
+
+ std::for_each(m_EventRecords.begin(), m_EventRecords.end(), std::mem_fun_ref(&EventRecord::printContents));
+ }
+ }
+};
+
+struct CounterSetRecord
+{
+ uint16_t m_CounterSetUid;
+ uint16_t m_CounterSetCount;
+ std::string m_CounterSetName;
+
+ static void printHeader()
+ {
+ std::string header;
+
+ header.append(gatordmock::CentreAlignFormatting("Counter set name", 20));
+ header.append(" | ");
+ header.append(gatordmock::CentreAlignFormatting("UID",13));
+ header.append(" | ");
+ header.append(gatordmock::CentreAlignFormatting("Count",10));
+ header.append("\n");
+
+ std::cout << "\n" << "\n";
+ std::cout << gatordmock::CentreAlignFormatting("COUNTER SETS", static_cast<int>(header.size()));
+ std::cout << "\n";
+ std::cout << std::string(header.size(), '=') << "\n";
+
+ std::cout<< header;
+ }
+
+ void printContents() const
+ {
+ std::string body;
+
+ body.append(gatordmock::CentreAlignFormatting(m_CounterSetName, 20));
+ body.append(" | ");
+ body.append(gatordmock::CentreAlignFormatting(std::to_string(m_CounterSetUid), 13));
+ body.append(" | ");
+ body.append(gatordmock::CentreAlignFormatting(std::to_string(m_CounterSetCount), 10));
+ body.append("\n");
+
+ std::cout << std::string(body.size(), '-') << "\n";
+
+ std::cout<< body;
+ }
+};
+
+struct DeviceRecord
+{
+ uint16_t m_DeviceUid;
+ uint16_t m_DeviceCores;
+ std::string m_DeviceName;
+
+ static void printHeader()
+ {
+ std::string header;
+
+ header.append(gatordmock::CentreAlignFormatting("Device name", 20));
+ header.append(" | ");
+ header.append(gatordmock::CentreAlignFormatting("UID",13));
+ header.append(" | ");
+ header.append(gatordmock::CentreAlignFormatting("Cores",10));
+ header.append("\n");
+
+ std::cout << "\n" << "\n";
+ std::cout << gatordmock::CentreAlignFormatting("DEVICES", static_cast<int>(header.size()));
+ std::cout << "\n";
+ std::cout << std::string(header.size(), '=') << "\n";
+ std::cout<< header;
+ }
+
+ void printContents() const
+ {
+ std::string body;
+
+ body.append(gatordmock::CentreAlignFormatting(m_DeviceName, 20));
+ body.append(" | ");
+ body.append(gatordmock::CentreAlignFormatting(std::to_string(m_DeviceUid), 13));
+ body.append(" | ");
+ body.append(gatordmock::CentreAlignFormatting(std::to_string(m_DeviceCores), 10));
+ body.append("\n");
+
+ std::cout << std::string(body.size(), '-') << "\n";
+ std::cout<< body;
+ }
+};
+
+struct CounterDirectory
+{
+ std::vector<CategoryRecord> m_Categories;
+ std::vector<CounterSetRecord> m_CounterSets;
+ std::vector<DeviceRecord> m_DeviceRecords;
+
+ void print() const
+ {
+ DeviceRecord::printHeader();
+ std::for_each(m_DeviceRecords.begin(), m_DeviceRecords.end(),
+ std::mem_fun_ref(&DeviceRecord::printContents));
+
+ CounterSetRecord::printHeader();
+ std::for_each(m_CounterSets.begin(), m_CounterSets.end(),
+ std::mem_fun_ref(&CounterSetRecord::printContents));
+
+ std::for_each(m_Categories.begin(), m_Categories.end(),
+ std::mem_fun_ref(&CategoryRecord::print));
+ std::cout << "\n";
+ }
+};
+
+} // namespace gatordmock
+
+} // namespace armnn \ No newline at end of file
diff --git a/tests/profiling/gatordmock/DirectoryCaptureCommandHandler.cpp b/tests/profiling/gatordmock/DirectoryCaptureCommandHandler.cpp
new file mode 100644
index 0000000000..eafef0b53c
--- /dev/null
+++ b/tests/profiling/gatordmock/DirectoryCaptureCommandHandler.cpp
@@ -0,0 +1,341 @@
+//
+// Copyright © 2019 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include <atomic>
+#include "DirectoryCaptureCommandHandler.hpp"
+
+namespace armnn
+{
+
+namespace gatordmock
+{
+
+// Utils
+uint32_t uint16_t_size = sizeof(uint16_t);
+uint32_t uint32_t_size = sizeof(uint32_t);
+
+void DirectoryCaptureCommandHandler::ParseData(const armnn::profiling::Packet& packet)
+{
+ uint16_t categoryRecordCount;
+ uint16_t counterSetRecordCount;
+ uint16_t deviceRecordCount;
+
+ uint32_t offset = 0;
+
+ if (packet.GetLength() < 8)
+ {
+ std::cout << "Counter directory packet received." << std::endl;
+ return;
+ }
+
+ const unsigned char* data = reinterpret_cast<const unsigned char*>(packet.GetData());
+ // Body header word 0:
+ // 0:15 [16] reserved: all zeros
+ offset += uint16_t_size;
+ // 16:31 [16] device_records_count: number of entries in the device_records_pointer_table
+ deviceRecordCount = profiling::ReadUint16(data, offset);
+ offset += uint16_t_size;
+
+ // Body header word 1:
+ // 0:31 [32] device_records_pointer_table_offset: offset to the device_records_pointer_table
+ // The offset is always zero here, as the device record pointer table field is always the first item in the pool
+ offset += uint32_t_size;
+
+ // Body header word 2:
+ // 0:15 [16] reserved: all zeros
+ offset += uint16_t_size;
+ // 16:31 [16] counter_set_count: number of entries in the counter_set_pointer_table
+ counterSetRecordCount = profiling::ReadUint16(data, offset);
+ offset += uint16_t_size;
+
+ // Body header word 3:
+ // 0:31 [32] counter_set_pointer_table_offset: offset to the counter_set_pointer_table
+ // counterPointerTableSetOffset = profiling::ReadUint32(data, offset);
+ offset += uint32_t_size;
+
+ // Body header word 4:
+ // 0:15 [16] reserved: all zeros
+ offset += uint16_t_size;
+ // 16:31 [16] categories_count: number of entries in the categories_pointer_table
+ categoryRecordCount = profiling::ReadUint16(data, offset);
+ offset += uint16_t_size;
+
+ // Body header word 5:
+ // 0:31 [32] categories_pointer_table_offset: offset to the categories_pointer_table
+ // categoriesPointerTableOffset = profiling::ReadUint32(data, offset);
+ offset += uint32_t_size;
+
+ std::vector<uint32_t> deviceRecordOffsets(deviceRecordCount);
+ std::vector<uint32_t> counterSetOffsets(counterSetRecordCount);
+ std::vector<uint32_t> categoryOffsets(categoryRecordCount);
+
+ for (uint32_t i = 0; i < deviceRecordCount; ++i)
+ {
+ deviceRecordOffsets[i] = profiling::ReadUint32(data, offset);
+ offset += uint32_t_size;
+ }
+
+ for (uint32_t i = 0; i < counterSetRecordCount; ++i)
+ {
+ counterSetOffsets[i] = profiling::ReadUint32(data, offset);
+ offset += uint32_t_size;
+ }
+
+ for (uint32_t i = 0; i < categoryRecordCount; ++i)
+ {
+ categoryOffsets[i] = profiling::ReadUint32(data, offset);
+ offset += uint32_t_size;
+ }
+
+ m_CounterDirectory.m_DeviceRecords = ReadDeviceRecords(data, offset, deviceRecordOffsets);
+ m_CounterDirectory.m_CounterSets = ReadCounterSetRecords(data, offset, counterSetOffsets);
+ m_CounterDirectory.m_Categories = ReadCategoryRecords(data, offset, categoryOffsets);
+
+ m_CounterDirectoryCount.operator++(std::memory_order_release);
+}
+
+std::vector<DeviceRecord> DirectoryCaptureCommandHandler::ReadDeviceRecords(const unsigned char* const data,
+ uint32_t offset,
+ std::vector<uint32_t> deviceRecordOffsets)
+{
+ uint32_t deviceRecordCount = static_cast<uint32_t >(deviceRecordOffsets.size());
+ std::vector<DeviceRecord> deviceRecords(deviceRecordCount);
+
+ for(uint32_t deviceIndex = 0; deviceIndex < deviceRecordCount; ++deviceIndex)
+ {
+ uint32_t deviceRecordOffset = offset + deviceRecordOffsets[deviceIndex];
+ // Device record word 0:
+ // 0:15 [16] cores: the number of individual streams of counters for one or more cores of some device
+ deviceRecords[deviceIndex].m_DeviceCores = profiling::ReadUint16(data, deviceRecordOffset);
+ // 16:31 [16] deviceUid: the unique identifier for the device
+ deviceRecordOffset += uint16_t_size;
+ deviceRecords[deviceIndex].m_DeviceUid = profiling::ReadUint16(data, deviceRecordOffset);
+ deviceRecordOffset += uint16_t_size;
+
+ // Device record word 1:
+ // Offset from the beginning of the device record pool to the name field.
+ uint32_t nameOffset = profiling::ReadUint32(data, deviceRecordOffset);
+
+ deviceRecordOffset += uint32_t_size;
+ deviceRecordOffset += uint32_t_size;
+ deviceRecordOffset += nameOffset;
+
+ deviceRecords[deviceIndex].m_DeviceName = GetStringNameFromBuffer(data, deviceRecordOffset);
+ }
+
+ return deviceRecords;
+}
+
+
+std::vector<CounterSetRecord>
+ DirectoryCaptureCommandHandler::ReadCounterSetRecords(const unsigned char* const data,
+ uint32_t offset,
+ std::vector<uint32_t> counterSetOffsets)
+{
+ uint32_t counterSetRecordCount = static_cast<uint32_t >(counterSetOffsets.size());
+ std::vector<CounterSetRecord> counterSets(counterSetRecordCount);
+
+ for (uint32_t counterSetIndex = 0; counterSetIndex < counterSetRecordCount; ++counterSetIndex)
+ {
+ uint32_t counterSetOffset = offset + counterSetOffsets[counterSetIndex];
+
+ // Counter set record word 0:
+ // 0:15 [16] count: the number of counters which can be active in this set at any one time
+ counterSets[counterSetIndex].m_CounterSetCount = profiling::ReadUint16(data, counterSetOffset);
+ counterSetOffset += uint16_t_size;
+
+ // 16:31 [16] deviceUid: the unique identifier for the counter_set
+ counterSets[counterSetIndex].m_CounterSetUid = profiling::ReadUint16(data, counterSetOffset);
+ counterSetOffset += uint16_t_size;
+
+ // Counter set record word 1:
+ // 0:31 [32] name_offset: offset from the beginning of the counter set pool to the name field
+ // The offset is always zero here, as the name field is always the first (and only) item in the pool
+ counterSetOffset += uint32_t_size;
+ counterSetOffset += uint32_t_size;
+
+ counterSets[counterSetIndex].m_CounterSetName = GetStringNameFromBuffer(data, counterSetOffset);
+ }
+
+ return counterSets;
+}
+
+std::vector<CategoryRecord> DirectoryCaptureCommandHandler::ReadCategoryRecords(const unsigned char* const data,
+ uint32_t offset,
+ std::vector<uint32_t> categoryOffsets)
+{
+ uint32_t categoryRecordCount = static_cast<uint32_t >(categoryOffsets.size());
+ std::vector<CategoryRecord> categories(categoryRecordCount);
+
+ for (uint32_t categoryIndex = 0; categoryIndex < categoryRecordCount; ++categoryIndex)
+ {
+ uint32_t categoryRecordOffset = offset + categoryOffsets[categoryIndex];
+
+ // Category record word 0:
+ // 0:15 The deviceUid of a counter_set the category is associated with.
+ // Set to zero if the category is NOT associated with a counter set.
+ categories[categoryIndex].m_CounterSet = profiling::ReadUint16(data, categoryRecordOffset);
+ categoryRecordOffset += uint16_t_size;
+
+ // 16:31 The deviceUid of a device element which identifies some hardware device that the category belongs to.
+ // Set to zero if the category is NOT associated with a device
+ categories[categoryIndex].m_DeviceUid = profiling::ReadUint16(data, categoryRecordOffset);
+ categoryRecordOffset += uint16_t_size;
+
+ // Category record word 1:
+ // 0:15 Reserved, value 0x0000.
+ categoryRecordOffset += uint16_t_size;
+ // 16:31 Number of events belonging to this category.
+ categories[categoryIndex].m_EventCount = profiling::ReadUint16(data, categoryRecordOffset);
+ categoryRecordOffset += uint16_t_size;
+
+ // Category record word 2
+ // 0:31 Offset from the beginning of the category data pool to the event_pointer_table
+ uint32_t eventPointerTableOffset = profiling::ReadUint32(data, categoryRecordOffset);
+ categoryRecordOffset += uint32_t_size;
+
+ // Category record word 3
+ // 0:31 Offset from the beginning of the category data pool to the name field.
+ uint32_t nameOffset = profiling::ReadUint32(data, categoryRecordOffset);
+ categoryRecordOffset += uint32_t_size;
+
+ //Get the events for the category
+ uint32_t eventCount = categories[categoryIndex].m_EventCount;
+
+ std::vector<uint32_t> eventRecordsOffsets(eventCount);
+
+ eventPointerTableOffset += categoryRecordOffset;
+
+ for (uint32_t eventIndex = 0; eventIndex < eventCount; ++eventIndex)
+ {
+ eventRecordsOffsets[eventIndex] =
+ profiling::ReadUint32(data, eventPointerTableOffset + uint32_t_size * eventIndex);
+ }
+
+ categories[categoryIndex].m_EventRecords = ReadEventRecords(data, categoryRecordOffset, eventRecordsOffsets);
+
+ categoryRecordOffset += uint32_t_size;
+
+ categories[categoryIndex].m_CategoryName = GetStringNameFromBuffer(data, categoryRecordOffset + nameOffset);
+ }
+
+ return categories;
+}
+
+
+std::vector<EventRecord> DirectoryCaptureCommandHandler::ReadEventRecords(const unsigned char* const data,
+ uint32_t offset,
+ std::vector<uint32_t> eventRecordsOffsets)
+{
+ uint32_t eventCount = static_cast<uint32_t>(eventRecordsOffsets.size());
+
+ std::vector<EventRecord> eventRecords(eventCount);
+ for (unsigned long i = 0; i < eventCount; ++i)
+ {
+ uint32_t eventRecordOffset = eventRecordsOffsets[i] + offset;
+
+ // Event record word 0:
+ // 0:15 [16] count_uid: unique ID for the counter. Must be unique across all counters in all categories
+ eventRecords[i].m_CounterUid = profiling::ReadUint16(data, eventRecordOffset);
+ eventRecordOffset += uint16_t_size;
+ // 16:31 [16] max_counter_uid: if the device this event is associated with has more than one core and there
+ // is one of these counters per core this value will be set to
+ // (counter_uid + cores (from device_record)) - 1.
+ // If there is only a single core then this value will be the same as
+ // the counter_uid value
+ eventRecords[i].m_MaxCounterUid = profiling::ReadUint16(data, eventRecordOffset);
+ eventRecordOffset += uint16_t_size;
+
+ // Event record word 1:
+ // 0:15 [16] counter_set: UID of the counter_set this event is associated with. Set to zero if the event
+ // is NOT associated with a counter_set
+ eventRecords[i].m_DeviceUid = profiling::ReadUint16(data, eventRecordOffset);
+ eventRecordOffset += uint16_t_size;
+
+ // 16:31 [16] device: UID of the device this event is associated with. Set to zero if the event is NOT
+ // associated with a device
+ eventRecords[i].m_CounterSetUid = profiling::ReadUint16(data, eventRecordOffset);
+ eventRecordOffset += uint16_t_size;
+
+ // Event record word 2:
+ // 0:15 [16] interpolation: type describing how to interpolate each data point in a stream of data points
+ eventRecords[i].m_CounterClass =profiling::ReadUint16(data, eventRecordOffset);
+ eventRecordOffset += uint16_t_size;
+
+ // 16:31 [16] class: type describing how to treat each data point in a stream of data points
+ eventRecords[i].m_CounterInterpolation = profiling::ReadUint16(data, eventRecordOffset);
+ eventRecordOffset += uint16_t_size;
+
+ // Event record word 3-4:
+ // 0:63 [64] multiplier: internal data stream is represented as integer values, this allows scaling of
+ // those values as if they are fixed point numbers. Zero is not a valid value
+ uint32_t multiplier[2] = { 0u, 0u };
+
+ multiplier[0] = profiling::ReadUint32(data, eventRecordOffset);
+ eventRecordOffset += uint32_t_size;
+ multiplier[1] = profiling::ReadUint32(data, eventRecordOffset);
+ eventRecordOffset += uint32_t_size;
+
+ std::memcpy(&eventRecords[i].m_CounterMultiplier, &multiplier, sizeof(multiplier));
+
+ // Event record word 5:
+ // 0:31 [32] name_eventRecordOffset: eventRecordOffset from the
+ // beginning of the event record pool to the name field
+ // The eventRecordOffset is always zero here, as the name field is always the first item in the pool
+ eventRecordOffset += uint32_t_size;
+
+ // Event record word 6:
+ // 0:31 [32] description_eventRecordOffset: eventRecordOffset from the
+ // beginning of the event record pool to the description field
+ // The size of the name buffer in bytes
+ uint32_t descriptionOffset = profiling::ReadUint32(data, eventRecordOffset);
+ eventRecordOffset += uint32_t_size;
+
+ // Event record word 7:
+ // 0:31 [32] units_eventRecordOffset: (optional) eventRecordOffset from the
+ // beginning of the event record pool to the units field.
+ // An eventRecordOffset value of zero indicates this field is not provided
+ uint32_t unitsOffset = profiling::ReadUint32(data, eventRecordOffset);
+ eventRecordOffset += uint32_t_size;
+ eventRecordOffset += uint32_t_size;
+
+ eventRecords[i].m_CounterName = GetStringNameFromBuffer(data, eventRecordOffset);
+
+ eventRecords[i].m_CounterDescription = GetStringNameFromBuffer(data, eventRecordOffset + descriptionOffset);
+
+ eventRecords[i].m_CounterUnits = GetStringNameFromBuffer(data, eventRecordOffset + unitsOffset);
+ }
+
+ return eventRecords;
+}
+
+void DirectoryCaptureCommandHandler::operator()(const profiling::Packet& packet)
+{
+ if (!m_QuietOperation)// Are we supposed to print to stdout?
+ {
+ std::cout << "Counter directory packet received." << std::endl;
+ }
+
+ ParseData(packet);
+
+ if (!m_QuietOperation)
+ {
+ m_CounterDirectory.print();
+ }
+}
+
+CounterDirectory DirectoryCaptureCommandHandler::GetCounterDirectory() const
+{
+ return m_CounterDirectory;
+}
+
+uint32_t DirectoryCaptureCommandHandler::GetCounterDirectoryCount() const
+{
+ return m_CounterDirectoryCount.load(std::memory_order_acquire);
+}
+
+} // namespace gatordmock
+
+} // namespace armnn \ No newline at end of file
diff --git a/tests/profiling/gatordmock/DirectoryCaptureCommandHandler.hpp b/tests/profiling/gatordmock/DirectoryCaptureCommandHandler.hpp
new file mode 100644
index 0000000000..4cf96be741
--- /dev/null
+++ b/tests/profiling/gatordmock/DirectoryCaptureCommandHandler.hpp
@@ -0,0 +1,75 @@
+//
+// Copyright © 2019 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include "CounterDirectory.hpp"
+#include "GatordMockService.hpp"
+#include "MockUtils.hpp"
+
+
+#include "Packet.hpp"
+#include "CommandHandlerFunctor.hpp"
+#include "SendCounterPacket.hpp"
+#include "IPeriodicCounterCapture.hpp"
+
+
+#include <vector>
+#include <thread>
+#include <functional>
+
+namespace armnn
+{
+
+namespace gatordmock
+{
+
+class DirectoryCaptureCommandHandler : public profiling::CommandHandlerFunctor
+{
+
+public:
+
+ DirectoryCaptureCommandHandler(uint32_t familyId,
+ uint32_t packetId,
+ uint32_t version,
+ bool quietOperation = false)
+ : CommandHandlerFunctor(familyId, packetId, version)
+ , m_QuietOperation(quietOperation)
+ , m_CounterDirectoryCount(0)
+ {}
+
+ void operator()(const armnn::profiling::Packet &packet) override;
+
+ CounterDirectory GetCounterDirectory() const;
+ uint32_t GetCounterDirectoryCount() const;
+
+private:
+ void ParseData(const armnn::profiling::Packet &packet);
+
+ std::vector<CategoryRecord> ReadCategoryRecords(const unsigned char *const data,
+ uint32_t offset,
+ std::vector<uint32_t> categoryOffsets);
+
+ std::vector<CounterSetRecord> ReadCounterSetRecords(const unsigned char *const data,
+ uint32_t offset,
+ std::vector<uint32_t> eventRecordsOffsets);
+
+ std::vector<DeviceRecord> ReadDeviceRecords(const unsigned char *const data,
+ uint32_t offset,
+ std::vector<uint32_t> eventRecordsOffsets);
+
+ std::vector<EventRecord> ReadEventRecords(const unsigned char *const data,
+ uint32_t offset,
+ std::vector<uint32_t> eventRecordsOffsets);
+
+ CounterDirectory m_CounterDirectory;
+
+ bool m_QuietOperation;
+ std::atomic<uint32_t> m_CounterDirectoryCount;
+};
+
+} // namespace gatordmock
+
+} // namespace armnn
diff --git a/tests/profiling/gatordmock/GatordMockMain.cpp b/tests/profiling/gatordmock/GatordMockMain.cpp
index dd483631ad..9dac6d976e 100644
--- a/tests/profiling/gatordmock/GatordMockMain.cpp
+++ b/tests/profiling/gatordmock/GatordMockMain.cpp
@@ -7,6 +7,7 @@
#include "../../../src/profiling/PeriodicCounterSelectionCommandHandler.hpp"
#include "CommandFileParser.hpp"
#include "CommandLineProcessor.hpp"
+#include "DirectoryCaptureCommandHandler.hpp"
#include "GatordMockService.hpp"
#include "PeriodicCounterCaptureCommandHandler.hpp"
#include "PeriodicCounterSelectionResponseHandler.hpp"
@@ -34,9 +35,13 @@ int main(int argc, char* argv[])
armnn::gatordmock::PeriodicCounterCaptureCommandHandler counterCaptureCommandHandler(
1, 0, packetVersionResolver.ResolvePacketVersion(1, 0).GetEncodedValue());
+ armnn::gatordmock::DirectoryCaptureCommandHandler directoryCaptureCommandHandler(
+ 0, 2, packetVersionResolver.ResolvePacketVersion(0, 2).GetEncodedValue());
+
// Register different derived functors
registry.RegisterFunctor(&periodicCounterSelectionResponseHandler);
registry.RegisterFunctor(&counterCaptureCommandHandler);
+ registry.RegisterFunctor(&directoryCaptureCommandHandler);
armnn::gatordmock::GatordMockService mockService(registry, cmdLine.IsEchoEnabled());
diff --git a/tests/profiling/gatordmock/GatordMockService.cpp b/tests/profiling/gatordmock/GatordMockService.cpp
index 194b097af1..bf326a64c3 100644
--- a/tests/profiling/gatordmock/GatordMockService.cpp
+++ b/tests/profiling/gatordmock/GatordMockService.cpp
@@ -136,6 +136,16 @@ void GatordMockService::SendConnectionAck()
SendPacket(0, 1, nullptr, 0);
}
+void GatordMockService::SendRequestCounterDir()
+{
+ if (m_EchoPackets)
+ {
+ std::cout << "Sending connection acknowledgement." << std::endl;
+ }
+ // The connection ack packet is an empty data packet with packetId == 1.
+ SendPacket(0, 3, nullptr, 0);
+}
+
bool GatordMockService::LaunchReceivingThread()
{
if (m_EchoPackets)
diff --git a/tests/profiling/gatordmock/GatordMockService.hpp b/tests/profiling/gatordmock/GatordMockService.hpp
index 10bf88406e..deafcfdc92 100644
--- a/tests/profiling/gatordmock/GatordMockService.hpp
+++ b/tests/profiling/gatordmock/GatordMockService.hpp
@@ -69,6 +69,9 @@ public:
/// Send a connection acknowledged packet back to the client.
void SendConnectionAck();
+ /// Send a request counter directory packet back to the client.
+ void SendRequestCounterDir();
+
/// Start the thread that will receive all packets and print them nicely to stdout.
bool LaunchReceivingThread();
diff --git a/tests/profiling/gatordmock/MockUtils.cpp b/tests/profiling/gatordmock/MockUtils.cpp
new file mode 100644
index 0000000000..bdbffc9253
--- /dev/null
+++ b/tests/profiling/gatordmock/MockUtils.cpp
@@ -0,0 +1,57 @@
+//
+// Copyright © 2019 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "MockUtils.hpp"
+
+namespace armnn
+{
+
+namespace gatordmock
+{
+
+std::string CentreAlignFormatting(const std::string& stringToPass, const int spacingWidth)
+{
+ std::stringstream outputStream, centrePadding;
+ int padding = spacingWidth - static_cast<int>(stringToPass.size());
+
+ for (int i = 0; i < padding / 2; ++i)
+ {
+ centrePadding << " ";
+ }
+
+ outputStream << centrePadding.str() << stringToPass << centrePadding.str();
+
+ if (padding > 0 && padding %2 != 0)
+ {
+ outputStream << " ";
+ }
+
+ return outputStream.str();
+}
+
+std::string GetStringNameFromBuffer(const unsigned char* const data, uint32_t offset)
+{
+ std::string deviceName;
+ u_char nextChar = profiling::ReadUint8(data, offset);
+
+ while (IsValidChar(nextChar))
+ {
+ deviceName += static_cast<char>(nextChar);
+ offset ++;
+ nextChar = profiling::ReadUint8(data, offset);
+ }
+
+ return deviceName;
+}
+
+bool IsValidChar(unsigned char c)
+{
+ // Check that the given character has ASCII 7-bit encoding, alpha-numeric, whitespace, and underscore only
+ return c < 128 && (std::isalnum(c) || c == '_' || c == ' ');
+}
+
+} // gatordmock
+
+} // armnn
diff --git a/tests/profiling/gatordmock/MockUtils.hpp b/tests/profiling/gatordmock/MockUtils.hpp
new file mode 100644
index 0000000000..78bd867b0f
--- /dev/null
+++ b/tests/profiling/gatordmock/MockUtils.hpp
@@ -0,0 +1,25 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include <EncodeVersion.hpp>
+#include <ProfilingUtils.hpp>
+
+namespace armnn
+{
+
+namespace gatordmock
+{
+
+std::string CentreAlignFormatting(const std::string& stringToPass, const int spacingWidth);
+
+std::string GetStringNameFromBuffer(const unsigned char *const data, uint32_t offset);
+
+bool IsValidChar(unsigned char c);
+
+} // gatordmock
+
+} // armnn
diff --git a/tests/profiling/gatordmock/PeriodicCounterCaptureCommandHandler.cpp b/tests/profiling/gatordmock/PeriodicCounterCaptureCommandHandler.cpp
index 90d52a7848..893351463f 100644
--- a/tests/profiling/gatordmock/PeriodicCounterCaptureCommandHandler.cpp
+++ b/tests/profiling/gatordmock/PeriodicCounterCaptureCommandHandler.cpp
@@ -3,6 +3,7 @@
// SPDX-License-Identifier: MIT
//
+#include "MockUtils.hpp"
#include "PeriodicCounterCaptureCommandHandler.hpp"
#include <ProfilingUtils.hpp>
@@ -19,26 +20,6 @@ namespace gatordmock
using boost::numeric_cast;
-std::string CentreAlignFormatting(const std::string stringToPass, const int spacingWidth)
-{
- std::stringstream outputStream, centrePadding;
- int padding = spacingWidth - static_cast<int>(stringToPass.size());
-
- for (int i = 0; i < padding / 2; ++i)
- {
- centrePadding << " ";
- }
-
- outputStream << centrePadding.str() << stringToPass << centrePadding.str();
-
- if (padding > 0 && padding % 2 != 0)
- {
- outputStream << " ";
- }
-
- return outputStream.str();
-}
-
void PeriodicCounterCaptureCommandHandler::ParseData(const armnn::profiling::Packet& packet)
{
std::vector<uint16_t> counterIds;
diff --git a/tests/profiling/gatordmock/tests/GatordMockTests.cpp b/tests/profiling/gatordmock/tests/GatordMockTests.cpp
index f5e60f83b2..eb827bec69 100644
--- a/tests/profiling/gatordmock/tests/GatordMockTests.cpp
+++ b/tests/profiling/gatordmock/tests/GatordMockTests.cpp
@@ -5,6 +5,7 @@
#include "../GatordMockService.hpp"
#include "../PeriodicCounterCaptureCommandHandler.hpp"
+#include "../DirectoryCaptureCommandHandler.hpp"
#include <CommandHandlerRegistry.hpp>
#include <ProfilingService.hpp>
@@ -21,28 +22,11 @@ using namespace armnn;
using namespace std::this_thread; // sleep_for, sleep_until
using namespace std::chrono_literals;
-// Required so build succeeds when local variable used only in assert
-#define _unused(x) ((void)(x))
-
-uint32_t ConstructHeader(uint32_t packetFamily, uint32_t packetClass, uint32_t packetType)
-{
- return ((packetFamily & 0x3F) << 26) | ((packetClass & 0x3FF) << 19) | ((packetType & 0x3FFF) << 16);
-}
-
-uint32_t ConstructHeader(uint32_t packetFamily, uint32_t packetId)
-{
- return ((packetFamily & 0x3F) << 26) | ((packetId & 0x3FF) << 16);
-}
-
BOOST_AUTO_TEST_CASE(CounterCaptureHandlingTest)
{
using boost::numeric_cast;
- // Initialise functors and register into the CommandHandlerRegistry
- uint32_t headerWord1 = ConstructHeader(1, 0, 0);
-
- // Create the Command Handler Registry
- profiling::CommandHandlerRegistry registry;
+ profiling::PacketVersionResolver packetVersionResolver;
// Data with timestamp, counter idx & counter values
std::vector<std::pair<uint16_t, uint32_t>> indexValuePairs;
@@ -98,18 +82,19 @@ BOOST_AUTO_TEST_CASE(CounterCaptureHandlingTest)
offset += sizeOfUint32;
}
+ uint32_t headerWord1 = packetVersionResolver.ResolvePacketVersion(0, 4).GetEncodedValue();
// Create packet to send through to the command functor
profiling::Packet packet1(headerWord1, dataLength, uniqueData1);
profiling::Packet packet2(headerWord1, dataLength, uniqueData2);
- uint32_t version = 1;
- gatordmock::PeriodicCounterCaptureCommandHandler commandHandler(0, 4, version, true);
+ gatordmock::PeriodicCounterCaptureCommandHandler commandHandler
+ (0, 4, headerWord1, true);
// Simulate two separate packets coming in to calculate period
commandHandler(packet1);
commandHandler(packet2);
- BOOST_ASSERT(4500 < commandHandler.m_CurrentPeriodValue && 5500 > commandHandler.m_CurrentPeriodValue);
+ BOOST_ASSERT(commandHandler.m_CurrentPeriodValue == 5000);
for (size_t i = 0; i < commandHandler.m_CounterCaptureValues.m_Uids.size(); ++i)
{
@@ -122,18 +107,26 @@ BOOST_AUTO_TEST_CASE(GatorDMockEndToEnd)
// The purpose of this test is to setup both sides of the profiling service and get to the point of receiving
// performance data.
- // Initialise functors and register into the CommandHandlerRegistry
- uint32_t version = 1;
+ //These variables are used to wait for the profiling service
+ u_int32_t timeout = 2000;
+ u_int32_t sleepTime = 50;
+ u_int32_t timeSlept = 0;
+
+ profiling::PacketVersionResolver packetVersionResolver;
// Create the Command Handler Registry
profiling::CommandHandlerRegistry registry;
// Update with derived functors
- gatordmock::PeriodicCounterCaptureCommandHandler counterCaptureCommandHandler(0, 4, version, true);
+ gatordmock::PeriodicCounterCaptureCommandHandler counterCaptureCommandHandler
+ (0, 4, packetVersionResolver.ResolvePacketVersion(0, 4).GetEncodedValue(), true);
+
+ gatordmock::DirectoryCaptureCommandHandler directoryCaptureCommandHandler
+ (0, 2, packetVersionResolver.ResolvePacketVersion(0, 2).GetEncodedValue(), true);
// Register different derived functors
registry.RegisterFunctor(&counterCaptureCommandHandler);
-
+ registry.RegisterFunctor(&directoryCaptureCommandHandler);
// Setup the mock service to bind to the UDS.
std::string udsNamespace = "gatord_namespace";
gatordmock::GatordMockService mockService(registry, false);
@@ -157,10 +150,18 @@ BOOST_AUTO_TEST_CASE(GatorDMockEndToEnd)
{
BOOST_FAIL("Failed to connect client");
}
+
// Give the profiling service sending thread time start executing and send the stream metadata.
- std::this_thread::sleep_for(std::chrono::milliseconds(1000));
- // We should now be in WaitingForAck state.
- BOOST_CHECK(profilingService.GetCurrentState() == profiling::ProfilingState::WaitingForAck);
+ while (profilingService.GetCurrentState() != profiling::ProfilingState::WaitingForAck)
+ {
+ if (timeSlept >= timeout)
+ {
+ BOOST_FAIL("Timeout: Profiling service did not switch to WaitingForAck state");
+ }
+ std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
+ timeSlept += sleepTime;
+ }
+
profilingService.Update();
// Read the stream metadata on the mock side.
if (!mockService.WaitForStreamMetaData())
@@ -169,15 +170,115 @@ BOOST_AUTO_TEST_CASE(GatorDMockEndToEnd)
}
// Send Ack from GatorD
mockService.SendConnectionAck();
- std::this_thread::sleep_for(std::chrono::milliseconds(1000));
- // At this point the service should be in active state.
- BOOST_ASSERT(profilingService.GetCurrentState() == profiling::ProfilingState::Active);
- // Future tests here will add counters to the ProfilingService, increment values and examine
- // PeriodicCounterCapture data received. These are yet to be integrated.
+ timeSlept = 0;
+ while (profilingService.GetCurrentState() != profiling::ProfilingState::Active)
+ {
+ if (timeSlept >= timeout)
+ {
+ BOOST_FAIL("Timeout: Profiling service did not switch to Active state");
+ }
+ std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
+ timeSlept += sleepTime;
+ }
+
+ mockService.LaunchReceivingThread();
+ mockService.SendRequestCounterDir();
+
+ timeSlept = 0;
+ while (directoryCaptureCommandHandler.GetCounterDirectoryCount() == 0)
+ {
+ if (timeSlept >= timeout)
+ {
+ BOOST_FAIL("Timeout: MockGatord did not receive counter directory packet");
+ }
+ std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
+ timeSlept += sleepTime;
+ }
+ const profiling::ICounterDirectory& serviceCounterDirectory = profilingService.GetCounterDirectory();
+ gatordmock::CounterDirectory mockCounterDirectory = directoryCaptureCommandHandler.GetCounterDirectory();
+
+ BOOST_ASSERT(serviceCounterDirectory.GetDeviceCount() == mockCounterDirectory.m_DeviceRecords.size());
+ BOOST_ASSERT(serviceCounterDirectory.GetCounterSetCount() == mockCounterDirectory.m_CounterSets.size());
+ BOOST_ASSERT(serviceCounterDirectory.GetCategoryCount() == mockCounterDirectory.m_Categories.size());
+
+ const profiling::Devices& serviceDevices = serviceCounterDirectory.GetDevices();
+
+ uint32_t deviceIndex = 0;
+ for (auto& device : serviceDevices)
+ {
+ BOOST_ASSERT(device.second->m_Name.size() ==
+ mockCounterDirectory.m_DeviceRecords[deviceIndex].m_DeviceName.size());
+
+ BOOST_CHECK(device.second->m_Name == mockCounterDirectory.m_DeviceRecords[deviceIndex].m_DeviceName);
+ BOOST_CHECK(device.second->m_Uid == mockCounterDirectory.m_DeviceRecords[deviceIndex].m_DeviceUid);
+ BOOST_CHECK(device.second->m_Cores == mockCounterDirectory.m_DeviceRecords[deviceIndex].m_DeviceCores);
+ deviceIndex++;
+ }
+
+ const profiling::CounterSets & serviceCounterSets = serviceCounterDirectory.GetCounterSets();
+ uint32_t counterSetIndex = 0;
+ for (auto& counterSet : serviceCounterSets)
+ {
+ BOOST_ASSERT(counterSet.second->m_Name.size() ==
+ mockCounterDirectory.m_CounterSets[counterSetIndex].m_CounterSetName.size());
+
+ BOOST_CHECK(counterSet.second->m_Name == mockCounterDirectory.m_CounterSets[counterSetIndex].m_CounterSetName);
+ BOOST_CHECK(counterSet.second->m_Uid == mockCounterDirectory.m_CounterSets[counterSetIndex].m_CounterSetUid);
+ BOOST_CHECK(counterSet.second->m_Count ==
+ mockCounterDirectory.m_CounterSets[counterSetIndex].m_CounterSetCount);
+ counterSetIndex++;
+ }
+
+ const profiling::Categories& serviceCategories = serviceCounterDirectory.GetCategories();
+ const std::vector<gatordmock::CategoryRecord> mockCategories = mockCounterDirectory.m_Categories;
+
+ uint32_t categoryIndex = 0;
+ for (auto& category : serviceCategories)
+ {
+ BOOST_ASSERT(category->m_Name.size() == mockCategories[categoryIndex].m_CategoryName.size());
+
+ BOOST_CHECK(category->m_Name == mockCategories[categoryIndex].m_CategoryName);
+ BOOST_CHECK(category->m_CounterSetUid == mockCategories[categoryIndex].m_CounterSet);
+ BOOST_CHECK(category->m_DeviceUid == mockCategories[categoryIndex].m_DeviceUid);
+
+ const std::vector<gatordmock::EventRecord> events = mockCategories[categoryIndex].m_EventRecords;
+ uint32_t eventIndex = 0;
+ for (uint16_t counterUid : category->m_Counters)
+ {
+ const profiling::Counter* counter = serviceCounterDirectory.GetCounter(counterUid);
+
+ BOOST_CHECK(counterUid == events[eventIndex].m_CounterUid);
+
+ BOOST_ASSERT(counter->m_Name.size() == events[eventIndex].m_CounterName.size());
+ BOOST_ASSERT(counter->m_Units.size() == events[eventIndex].m_CounterUnits.size());
+ BOOST_ASSERT(counter->m_Description.size() == events[eventIndex].m_CounterDescription.size());
+
+ BOOST_CHECK(counter->m_Name == events[eventIndex].m_CounterName);
+ BOOST_CHECK(counter->m_Units == events[eventIndex].m_CounterUnits);
+ BOOST_CHECK(counter->m_Description == events[eventIndex].m_CounterDescription);
+
+ BOOST_CHECK(counter->m_CounterSetUid == events[eventIndex].m_CounterSetUid);
+ BOOST_CHECK(counter->m_DeviceUid == events[eventIndex].m_DeviceUid);
+ BOOST_CHECK(counter->m_Uid == events[eventIndex].m_CounterUid);
+
+ BOOST_CHECK(counter->m_Multiplier == events[eventIndex].m_CounterMultiplier);
+ BOOST_CHECK(counter->m_MaxCounterUid == events[eventIndex].m_MaxCounterUid);
+ BOOST_CHECK(counter->m_Interpolation == events[eventIndex].m_CounterInterpolation);
+ BOOST_CHECK(counter->m_Class == events[eventIndex].m_CounterClass);
+
+ eventIndex++;
+ }
+ categoryIndex++;
+ }
+
+ mockService.WaitForReceivingThread();
options.m_EnableProfiling = false;
profilingService.ResetExternalProfilingOptions(options, true);
+
+ // Future tests here will add counters to the ProfilingService, increment values and examine
+ // PeriodicCounterCapture data received. These are yet to be integrated.
}
BOOST_AUTO_TEST_SUITE_END()