1 //
2 // Copyright © 2019 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5
6 #include "ProfilingMocks.hpp"
7 #include "ProfilingTestUtils.hpp"
8 #include "SendCounterPacketTests.hpp"
9
10 #include <client/src/BufferManager.hpp>
11 #include <client/src/ProfilingUtils.hpp>
12 #include <client/src/SendCounterPacket.hpp>
13
14 #include <armnn/Utils.hpp>
15
16 #include <common/include/Assert.hpp>
17 #include <common/include/Conversion.hpp>
18 #include <common/include/Constants.hpp>
19 #include <common/include/CounterDirectory.hpp>
20 #include <common/include/EncodeVersion.hpp>
21 #include <common/include/NumericCast.hpp>
22 #include <common/include/Processes.hpp>
23 #include <common/include/ProfilingException.hpp>
24
25 #include <doctest/doctest.h>
26
27 #include <chrono>
28
29 using namespace arm::pipe;
30
31 namespace
32 {
33
34 // A short delay to wait for the thread to process a packet.
35 uint16_t constexpr WAIT_UNTIL_READABLE_MS = 20;
36
SetNotConnectedProfilingState(ProfilingStateMachine & profilingStateMachine)37 void SetNotConnectedProfilingState(ProfilingStateMachine& profilingStateMachine)
38 {
39 ProfilingState currentState = profilingStateMachine.GetCurrentState();
40 switch (currentState)
41 {
42 case ProfilingState::WaitingForAck:
43 profilingStateMachine.TransitionToState(ProfilingState::Active);
44 ARMNN_FALLTHROUGH;
45 case ProfilingState::Uninitialised:
46 ARMNN_FALLTHROUGH;
47 case ProfilingState::Active:
48 profilingStateMachine.TransitionToState(ProfilingState::NotConnected);
49 ARMNN_FALLTHROUGH;
50 case ProfilingState::NotConnected:
51 return;
52 default:
53 CHECK_MESSAGE(false, "Invalid profiling state");
54 }
55 }
56
SetWaitingForAckProfilingState(ProfilingStateMachine & profilingStateMachine)57 void SetWaitingForAckProfilingState(ProfilingStateMachine& profilingStateMachine)
58 {
59 ProfilingState currentState = profilingStateMachine.GetCurrentState();
60 switch (currentState)
61 {
62 case ProfilingState::Uninitialised:
63 ARMNN_FALLTHROUGH;
64 case ProfilingState::Active:
65 profilingStateMachine.TransitionToState(ProfilingState::NotConnected);
66 ARMNN_FALLTHROUGH;
67 case ProfilingState::NotConnected:
68 profilingStateMachine.TransitionToState(ProfilingState::WaitingForAck);
69 ARMNN_FALLTHROUGH;
70 case ProfilingState::WaitingForAck:
71 return;
72 default:
73 CHECK_MESSAGE(false, "Invalid profiling state");
74 }
75 }
76
SetActiveProfilingState(ProfilingStateMachine & profilingStateMachine)77 void SetActiveProfilingState(ProfilingStateMachine& profilingStateMachine)
78 {
79 ProfilingState currentState = profilingStateMachine.GetCurrentState();
80 switch (currentState)
81 {
82 case ProfilingState::Uninitialised:
83 profilingStateMachine.TransitionToState(ProfilingState::NotConnected);
84 ARMNN_FALLTHROUGH;
85 case ProfilingState::NotConnected:
86 profilingStateMachine.TransitionToState(ProfilingState::WaitingForAck);
87 ARMNN_FALLTHROUGH;
88 case ProfilingState::WaitingForAck:
89 profilingStateMachine.TransitionToState(ProfilingState::Active);
90 ARMNN_FALLTHROUGH;
91 case ProfilingState::Active:
92 return;
93 default:
94 CHECK_MESSAGE(false, "Invalid profiling state");
95 }
96 }
97
98 } // Anonymous namespace
99
100 TEST_SUITE("SendCounterPacketTests")
101 {
102 using PacketType = MockProfilingConnection::PacketType;
103
104 TEST_CASE("MockSendCounterPacketTest")
105 {
106 MockBufferManager mockBuffer(512);
107 MockSendCounterPacket mockSendCounterPacket(mockBuffer);
108
109 mockSendCounterPacket.SendStreamMetaDataPacket();
110
111 auto packetBuffer = mockBuffer.GetReadableBuffer();
112 const char* buffer = reinterpret_cast<const char*>(packetBuffer->GetReadableData());
113
114 CHECK(strcmp(buffer, "SendStreamMetaDataPacket") == 0);
115
116 mockBuffer.MarkRead(packetBuffer);
117
118 CounterDirectory counterDirectory;
119 mockSendCounterPacket.SendCounterDirectoryPacket(counterDirectory);
120
121 packetBuffer = mockBuffer.GetReadableBuffer();
122 buffer = reinterpret_cast<const char*>(packetBuffer->GetReadableData());
123
124 CHECK(strcmp(buffer, "SendCounterDirectoryPacket") == 0);
125
126 mockBuffer.MarkRead(packetBuffer);
127
128 uint64_t timestamp = 0;
129 std::vector<CounterValue> indexValuePairs;
130
131 mockSendCounterPacket.SendPeriodicCounterCapturePacket(timestamp, indexValuePairs);
132
133 packetBuffer = mockBuffer.GetReadableBuffer();
134 buffer = reinterpret_cast<const char*>(packetBuffer->GetReadableData());
135
136 CHECK(strcmp(buffer, "SendPeriodicCounterCapturePacket") == 0);
137
138 mockBuffer.MarkRead(packetBuffer);
139
140 uint32_t capturePeriod = 0;
141 std::vector<uint16_t> selectedCounterIds;
142 mockSendCounterPacket.SendPeriodicCounterSelectionPacket(capturePeriod, selectedCounterIds);
143
144 packetBuffer = mockBuffer.GetReadableBuffer();
145 buffer = reinterpret_cast<const char*>(packetBuffer->GetReadableData());
146
147 CHECK(strcmp(buffer, "SendPeriodicCounterSelectionPacket") == 0);
148
149 mockBuffer.MarkRead(packetBuffer);
150 }
151
152 TEST_CASE("SendPeriodicCounterSelectionPacketTest")
153 {
154 // Error no space left in buffer
155 MockBufferManager mockBuffer1(10);
156 SendCounterPacket sendPacket1(mockBuffer1,
157 arm::pipe::ARMNN_SOFTWARE_INFO,
158 arm::pipe::ARMNN_SOFTWARE_VERSION,
159 arm::pipe::ARMNN_HARDWARE_VERSION);
160
161 uint32_t capturePeriod = 1000;
162 std::vector<uint16_t> selectedCounterIds;
163 CHECK_THROWS_AS(sendPacket1.SendPeriodicCounterSelectionPacket(
164 capturePeriod, selectedCounterIds),
165 BufferExhaustion);
166
167 // Packet without any counters
168 MockBufferManager mockBuffer2(512);
169 SendCounterPacket sendPacket2(mockBuffer2,
170 arm::pipe::ARMNN_SOFTWARE_INFO,
171 arm::pipe::ARMNN_SOFTWARE_VERSION,
172 arm::pipe::ARMNN_HARDWARE_VERSION);
173
174 sendPacket2.SendPeriodicCounterSelectionPacket(capturePeriod, selectedCounterIds);
175 auto readBuffer2 = mockBuffer2.GetReadableBuffer();
176
177 uint32_t headerWord0 = ReadUint32(readBuffer2, 0);
178 uint32_t headerWord1 = ReadUint32(readBuffer2, 4);
179 uint32_t period = ReadUint32(readBuffer2, 8);
180
181 CHECK(((headerWord0 >> 26) & 0x3F) == 0); // packet family
182 CHECK(((headerWord0 >> 16) & 0x3FF) == 4); // packet id
183 CHECK(headerWord1 == 4); // data lenght
184 CHECK(period == 1000); // capture period
185
186 // Full packet message
187 MockBufferManager mockBuffer3(512);
188 SendCounterPacket sendPacket3(mockBuffer3,
189 arm::pipe::ARMNN_SOFTWARE_INFO,
190 arm::pipe::ARMNN_SOFTWARE_VERSION,
191 arm::pipe::ARMNN_HARDWARE_VERSION);
192
193 selectedCounterIds.reserve(5);
194 selectedCounterIds.emplace_back(100);
195 selectedCounterIds.emplace_back(200);
196 selectedCounterIds.emplace_back(300);
197 selectedCounterIds.emplace_back(400);
198 selectedCounterIds.emplace_back(500);
199 sendPacket3.SendPeriodicCounterSelectionPacket(capturePeriod, selectedCounterIds);
200 auto readBuffer3 = mockBuffer3.GetReadableBuffer();
201
202 headerWord0 = ReadUint32(readBuffer3, 0);
203 headerWord1 = ReadUint32(readBuffer3, 4);
204 period = ReadUint32(readBuffer3, 8);
205
206 CHECK(((headerWord0 >> 26) & 0x3F) == 0); // packet family
207 CHECK(((headerWord0 >> 16) & 0x3FF) == 4); // packet id
208 CHECK(headerWord1 == 14); // data lenght
209 CHECK(period == 1000); // capture period
210
211 uint16_t counterId = 0;
212 uint32_t offset = 12;
213
214 // Counter Ids
215 for(const uint16_t& id : selectedCounterIds)
216 {
217 counterId = ReadUint16(readBuffer3, offset);
218 CHECK(counterId == id);
219 offset += 2;
220 }
221 }
222
223 TEST_CASE("SendPeriodicCounterCapturePacketTest")
224 {
225 ProfilingStateMachine profilingStateMachine;
226
227 // Error no space left in buffer
228 MockBufferManager mockBuffer1(10);
229 SendCounterPacket sendPacket1(mockBuffer1,
230 arm::pipe::ARMNN_SOFTWARE_INFO,
231 arm::pipe::ARMNN_SOFTWARE_VERSION,
232 arm::pipe::ARMNN_HARDWARE_VERSION);
233
234 auto captureTimestamp = std::chrono::steady_clock::now();
235 uint64_t time = static_cast<uint64_t >(captureTimestamp.time_since_epoch().count());
236 std::vector<CounterValue> indexValuePairs;
237
238 CHECK_THROWS_AS(sendPacket1.SendPeriodicCounterCapturePacket(time, indexValuePairs),
239 BufferExhaustion);
240
241 // Packet without any counters
242 MockBufferManager mockBuffer2(512);
243 SendCounterPacket sendPacket2(mockBuffer2,
244 arm::pipe::ARMNN_SOFTWARE_INFO,
245 arm::pipe::ARMNN_SOFTWARE_VERSION,
246 arm::pipe::ARMNN_HARDWARE_VERSION);
247
248 sendPacket2.SendPeriodicCounterCapturePacket(time, indexValuePairs);
249 auto readBuffer2 = mockBuffer2.GetReadableBuffer();
250
251 uint32_t headerWord0 = ReadUint32(readBuffer2, 0);
252 uint32_t headerWord1 = ReadUint32(readBuffer2, 4);
253 uint64_t readTimestamp = ReadUint64(readBuffer2, 8);
254
255 CHECK(((headerWord0 >> 26) & 0x0000003F) == 3); // packet family
256 CHECK(((headerWord0 >> 19) & 0x0000007F) == 0); // packet class
257 CHECK(((headerWord0 >> 16) & 0x00000007) == 0); // packet type
258 CHECK(headerWord1 == 8); // data length
259 CHECK(time == readTimestamp); // capture period
260
261 // Full packet message
262 MockBufferManager mockBuffer3(512);
263 SendCounterPacket sendPacket3(mockBuffer3,
264 arm::pipe::ARMNN_SOFTWARE_INFO,
265 arm::pipe::ARMNN_SOFTWARE_VERSION,
266 arm::pipe::ARMNN_HARDWARE_VERSION);
267
268 indexValuePairs.reserve(5);
269 indexValuePairs.emplace_back(CounterValue{0, 100});
270 indexValuePairs.emplace_back(CounterValue{1, 200});
271 indexValuePairs.emplace_back(CounterValue{2, 300});
272 indexValuePairs.emplace_back(CounterValue{3, 400});
273 indexValuePairs.emplace_back(CounterValue{4, 500});
274 sendPacket3.SendPeriodicCounterCapturePacket(time, indexValuePairs);
275 auto readBuffer3 = mockBuffer3.GetReadableBuffer();
276
277 headerWord0 = ReadUint32(readBuffer3, 0);
278 headerWord1 = ReadUint32(readBuffer3, 4);
279 uint64_t readTimestamp2 = ReadUint64(readBuffer3, 8);
280
281 CHECK(((headerWord0 >> 26) & 0x0000003F) == 3); // packet family
282 CHECK(((headerWord0 >> 19) & 0x0000007F) == 0); // packet class
283 CHECK(((headerWord0 >> 16) & 0x00000007) == 0); // packet type
284 CHECK(headerWord1 == 38); // data length
285 CHECK(time == readTimestamp2); // capture period
286
287 uint16_t counterIndex = 0;
288 uint32_t counterValue = 100;
289 uint32_t offset = 16;
290
291 // Counter Ids
292 for (auto it = indexValuePairs.begin(), end = indexValuePairs.end(); it != end; ++it)
293 {
294 // Check Counter Index
295 uint16_t readIndex = ReadUint16(readBuffer3, offset);
296 CHECK(counterIndex == readIndex);
297 counterIndex++;
298 offset += 2;
299
300 // Check Counter Value
301 uint32_t readValue = ReadUint32(readBuffer3, offset);
302 CHECK(counterValue == readValue);
303 counterValue += 100;
304 offset += 4;
305 }
306
307 }
308
309 TEST_CASE("SendStreamMetaDataPacketTest")
310 {
311 uint32_t sizeUint32 = arm::pipe::numeric_cast<uint32_t>(sizeof(uint32_t));
312
313 // Error no space left in buffer
314 MockBufferManager mockBuffer1(10);
315 SendCounterPacket sendPacket1(mockBuffer1,
316 arm::pipe::ARMNN_SOFTWARE_INFO,
317 arm::pipe::ARMNN_SOFTWARE_VERSION,
318 arm::pipe::ARMNN_HARDWARE_VERSION);
319 CHECK_THROWS_AS(sendPacket1.SendStreamMetaDataPacket(), BufferExhaustion);
320
321 // Full metadata packet
322
323 std::string processName = GetProcessName().substr(0, 60);
324
325 uint32_t infoSize = arm::pipe::numeric_cast<uint32_t>(arm::pipe::ARMNN_SOFTWARE_INFO.size()) + 1;
326 uint32_t hardwareVersionSize = arm::pipe::numeric_cast<uint32_t>(arm::pipe::ARMNN_HARDWARE_VERSION.size()) + 1;
327 uint32_t softwareVersionSize = arm::pipe::numeric_cast<uint32_t>(arm::pipe::ARMNN_SOFTWARE_VERSION.size()) + 1;
328 uint32_t processNameSize = arm::pipe::numeric_cast<uint32_t>(processName.size()) + 1;
329
330 // Supported Packets
331 // Packet Encoding version 1.0.0
332 // Control packet family
333 // Stream metadata packet (packet family=0; packet id=0)
334 // Connection Acknowledged packet ( packet family=0, packet id=1) Version 1.0.0
335 // Counter Directory packet (packet family=0; packet id=2) Version 1.0.0
336 // Request Counter Directory packet ( packet family=0, packet id=3) Version 1.0.0
337 // Periodic Counter Selection packet ( packet family=0, packet id=4) Version 1.0.0
338 // Per Job Counter Selection packet ( packet family=0, packet id=5) Version 1.0.0
339 // Activate Timeline Reporting (packet family = 0, packet id = 6) Version 1.0.0
340 // Deactivate Timeline Reporting (packet family = 0, packet id = 7) Version 1.0.0
341 // Counter Packet Family
342 // Periodic Counter Capture (packet_family = 3, packet_class = 0, packet_type = 0) Version 1.0.0
343 // Per-Job Counter Capture (packet_family = 3, packet_class = 1, packet_type = 0,1) Version 1.0.0
344 // Timeline Packet Family
345 // Timeline Message Directory (packet_family = 1, packet_class = 0, packet_type = 0) Version 1.0.0
346 // Timeline Message (packet_family = 1, packet_class = 0, packet_type = 1) Version 1.0.0
347 std::vector<std::pair<uint32_t, uint32_t>> packetVersions;
348 packetVersions.push_back(std::make_pair(ConstructHeader(0, 0), arm::pipe::EncodeVersion(1, 0, 0)));
349 packetVersions.push_back(std::make_pair(ConstructHeader(0, 1), arm::pipe::EncodeVersion(1, 0, 0)));
350 packetVersions.push_back(std::make_pair(ConstructHeader(0, 2), arm::pipe::EncodeVersion(1, 0, 0)));
351 packetVersions.push_back(std::make_pair(ConstructHeader(0, 3), arm::pipe::EncodeVersion(1, 0, 0)));
352 packetVersions.push_back(std::make_pair(ConstructHeader(0, 4), arm::pipe::EncodeVersion(1, 0, 0)));
353 packetVersions.push_back(std::make_pair(ConstructHeader(0, 5), arm::pipe::EncodeVersion(1, 0, 0)));
354 packetVersions.push_back(std::make_pair(ConstructHeader(0, 6), arm::pipe::EncodeVersion(1, 0, 0)));
355 packetVersions.push_back(std::make_pair(ConstructHeader(0, 7), arm::pipe::EncodeVersion(1, 0, 0)));
356 packetVersions.push_back(std::make_pair(ConstructHeader(3, 0, 0), arm::pipe::EncodeVersion(1, 0, 0)));
357 packetVersions.push_back(std::make_pair(ConstructHeader(3, 1, 0), arm::pipe::EncodeVersion(1, 0, 0)));
358 packetVersions.push_back(std::make_pair(ConstructHeader(3, 1, 1), arm::pipe::EncodeVersion(1, 0, 0)));
359 packetVersions.push_back(std::make_pair(ConstructHeader(1, 0, 0), arm::pipe::EncodeVersion(1, 0, 0)));
360 packetVersions.push_back(std::make_pair(ConstructHeader(1, 0, 1), arm::pipe::EncodeVersion(1, 0, 0)));
361
362 uint32_t packetEntries = static_cast<uint32_t>(packetVersions.size());
363
364 MockBufferManager mockBuffer2(512);
365 SendCounterPacket sendPacket2(mockBuffer2,
366 arm::pipe::ARMNN_SOFTWARE_INFO,
367 arm::pipe::ARMNN_SOFTWARE_VERSION,
368 arm::pipe::ARMNN_HARDWARE_VERSION);
369 sendPacket2.SendStreamMetaDataPacket();
370 auto readBuffer2 = mockBuffer2.GetReadableBuffer();
371
372 uint32_t headerWord0 = ReadUint32(readBuffer2, 0);
373 uint32_t headerWord1 = ReadUint32(readBuffer2, sizeUint32);
374
375 CHECK(((headerWord0 >> 26) & 0x3F) == 0); // packet family
376 CHECK(((headerWord0 >> 16) & 0x3FF) == 0); // packet id
377
378 uint32_t totalLength = arm::pipe::numeric_cast<uint32_t>(2 * sizeUint32 +
379 10 * sizeUint32 + infoSize +
380 hardwareVersionSize + softwareVersionSize +
381 processNameSize + sizeUint32 +
382 2 * packetEntries * sizeUint32);
383
384 CHECK(headerWord1 == totalLength - (2 * sizeUint32)); // data length
385
386 uint32_t offset = sizeUint32 * 2;
387 CHECK(ReadUint32(readBuffer2, offset) == arm::pipe::PIPE_MAGIC); // pipe_magic
388 offset += sizeUint32;
389 CHECK(ReadUint32(readBuffer2, offset) == arm::pipe::EncodeVersion(1, 0, 0)); // stream_metadata_version
390 offset += sizeUint32;
391 CHECK(ReadUint32(readBuffer2, offset) == MAX_METADATA_PACKET_LENGTH); // max_data_len
392 offset += sizeUint32;
393 int pid = arm::pipe::GetCurrentProcessId();
394 CHECK(ReadUint32(readBuffer2, offset) == arm::pipe::numeric_cast<uint32_t>(pid));
395 offset += sizeUint32;
396 uint32_t poolOffset = 10 * sizeUint32;
397 CHECK(ReadUint32(readBuffer2, offset) == poolOffset); // offset_info
398 offset += sizeUint32;
399 poolOffset += infoSize;
400 CHECK(ReadUint32(readBuffer2, offset) == poolOffset); // offset_hw_version
401 offset += sizeUint32;
402 poolOffset += hardwareVersionSize;
403 CHECK(ReadUint32(readBuffer2, offset) == poolOffset); // offset_sw_version
404 offset += sizeUint32;
405 poolOffset += softwareVersionSize;
406 CHECK(ReadUint32(readBuffer2, offset) == poolOffset); // offset_process_name
407 offset += sizeUint32;
408 poolOffset += processNameSize;
409 CHECK(ReadUint32(readBuffer2, offset) == poolOffset); // offset_packet_version_table
410 offset += sizeUint32;
411 CHECK(ReadUint32(readBuffer2, offset) == 0); // reserved
412
413 const unsigned char* readData2 = readBuffer2->GetReadableData();
414
415 offset += sizeUint32;
416 if (infoSize)
417 {
418 CHECK(strcmp(reinterpret_cast<const char *>(&readData2[offset]),
419 arm::pipe::ARMNN_SOFTWARE_INFO.c_str()) == 0);
420 offset += infoSize;
421 }
422
423 if (hardwareVersionSize)
424 {
425 CHECK(strcmp(reinterpret_cast<const char *>(&readData2[offset]),
426 arm::pipe::ARMNN_HARDWARE_VERSION.c_str()) == 0);
427 offset += hardwareVersionSize;
428 }
429
430 if (softwareVersionSize)
431 {
432 CHECK(strcmp(reinterpret_cast<const char *>(&readData2[offset]),
433 arm::pipe::ARMNN_SOFTWARE_VERSION.c_str()) == 0);
434 offset += softwareVersionSize;
435 }
436
437 if (processNameSize)
438 {
439 CHECK(strcmp(reinterpret_cast<const char *>(&readData2[offset]), GetProcessName().c_str()) == 0);
440 offset += processNameSize;
441 }
442
443 if (packetEntries)
444 {
445 uint32_t numberOfEntries = ReadUint32(readBuffer2, offset);
446 CHECK((numberOfEntries >> 16) == packetEntries);
447 offset += sizeUint32;
448 for (std::pair<uint32_t, uint32_t>& packetVersion : packetVersions)
449 {
450 uint32_t readPacketId = ReadUint32(readBuffer2, offset);
451 CHECK(packetVersion.first == readPacketId);
452 offset += sizeUint32;
453 uint32_t readVersion = ReadUint32(readBuffer2, offset);
454 CHECK(packetVersion.second == readVersion);
455 offset += sizeUint32;
456 }
457 }
458
459 CHECK(offset == totalLength);
460 }
461
462 TEST_CASE("CreateDeviceRecordTest")
463 {
464 MockBufferManager mockBuffer(0);
465 SendCounterPacketTest sendCounterPacketTest(mockBuffer);
466
467 // Create a device for testing
468 uint16_t deviceUid = 27;
469 const std::string deviceName = "some_device";
470 uint16_t deviceCores = 3;
471 const DevicePtr device = std::make_unique<Device>(deviceUid, deviceName, deviceCores);
472
473 // Create a device record
474 SendCounterPacket::DeviceRecord deviceRecord;
475 std::string errorMessage;
476 bool result = sendCounterPacketTest.CreateDeviceRecordTest(device, deviceRecord, errorMessage);
477
478 CHECK(result);
479 CHECK(errorMessage.empty());
480 CHECK(deviceRecord.size() == 6); // Size in words: header [2] + device name [4]
481
482 uint16_t deviceRecordWord0[]
483 {
484 static_cast<uint16_t>(deviceRecord[0] >> 16),
485 static_cast<uint16_t>(deviceRecord[0])
486 };
487 CHECK(deviceRecordWord0[0] == deviceUid); // uid
488 CHECK(deviceRecordWord0[1] == deviceCores); // cores
489 CHECK(deviceRecord[1] == 8); // name_offset
490 CHECK(deviceRecord[2] == deviceName.size() + 1); // The length of the SWTrace string (name)
491 CHECK(std::memcmp(deviceRecord.data() + 3, deviceName.data(), deviceName.size()) == 0); // name
492 }
493
494 TEST_CASE("CreateInvalidDeviceRecordTest")
495 {
496 MockBufferManager mockBuffer(0);
497 SendCounterPacketTest sendCounterPacketTest(mockBuffer);
498
499 // Create a device for testing
500 uint16_t deviceUid = 27;
501 const std::string deviceName = "some€£invalid‡device";
502 uint16_t deviceCores = 3;
503 const DevicePtr device = std::make_unique<Device>(deviceUid, deviceName, deviceCores);
504
505 // Create a device record
506 SendCounterPacket::DeviceRecord deviceRecord;
507 std::string errorMessage;
508 bool result = sendCounterPacketTest.CreateDeviceRecordTest(device, deviceRecord, errorMessage);
509
510 CHECK(!result);
511 CHECK(!errorMessage.empty());
512 CHECK(deviceRecord.empty());
513 }
514
515 TEST_CASE("CreateCounterSetRecordTest")
516 {
517 MockBufferManager mockBuffer(0);
518 SendCounterPacketTest sendCounterPacketTest(mockBuffer);
519
520 // Create a counter set for testing
521 uint16_t counterSetUid = 27;
522 const std::string counterSetName = "some_counter_set";
523 uint16_t counterSetCount = 3421;
524 const CounterSetPtr counterSet = std::make_unique<CounterSet>(counterSetUid, counterSetName, counterSetCount);
525
526 // Create a counter set record
527 SendCounterPacket::CounterSetRecord counterSetRecord;
528 std::string errorMessage;
529 bool result = sendCounterPacketTest.CreateCounterSetRecordTest(counterSet, counterSetRecord, errorMessage);
530
531 CHECK(result);
532 CHECK(errorMessage.empty());
533 CHECK(counterSetRecord.size() == 8); // Size in words: header [2] + counter set name [6]
534
535 uint16_t counterSetRecordWord0[]
536 {
537 static_cast<uint16_t>(counterSetRecord[0] >> 16),
538 static_cast<uint16_t>(counterSetRecord[0])
539 };
540 CHECK(counterSetRecordWord0[0] == counterSetUid); // uid
541 CHECK(counterSetRecordWord0[1] == counterSetCount); // cores
542 CHECK(counterSetRecord[1] == 8); // name_offset
543 CHECK(counterSetRecord[2] == counterSetName.size() + 1); // The length of the SWTrace string (name)
544 CHECK(std::memcmp(counterSetRecord.data() + 3, counterSetName.data(), counterSetName.size()) == 0); // name
545 }
546
547 TEST_CASE("CreateInvalidCounterSetRecordTest")
548 {
549 MockBufferManager mockBuffer(0);
550 SendCounterPacketTest sendCounterPacketTest(mockBuffer);
551
552 // Create a counter set for testing
553 uint16_t counterSetUid = 27;
554 const std::string counterSetName = "some invalid_counter€£set";
555 uint16_t counterSetCount = 3421;
556 const CounterSetPtr counterSet = std::make_unique<CounterSet>(counterSetUid, counterSetName, counterSetCount);
557
558 // Create a counter set record
559 SendCounterPacket::CounterSetRecord counterSetRecord;
560 std::string errorMessage;
561 bool result = sendCounterPacketTest.CreateCounterSetRecordTest(counterSet, counterSetRecord, errorMessage);
562
563 CHECK(!result);
564 CHECK(!errorMessage.empty());
565 CHECK(counterSetRecord.empty());
566 }
567
568 TEST_CASE("CreateEventRecordTest")
569 {
570 MockBufferManager mockBuffer(0);
571 SendCounterPacketTest sendCounterPacketTest(mockBuffer);
572
573 // Create a counter for testing
574 uint16_t counterUid = 7256;
575 uint16_t maxCounterUid = 132;
576 uint16_t deviceUid = 132;
577 uint16_t counterSetUid = 4497;
578 uint16_t counterClass = 1;
579 uint16_t counterInterpolation = 1;
580 double counterMultiplier = 1234.567f;
581 const std::string counterName = "some_valid_counter";
582 const std::string counterDescription = "a_counter_for_testing";
583 const std::string counterUnits = "Mrads2";
584 const CounterPtr counter = std::make_unique<Counter>(armnn::profiling::BACKEND_ID,
585 counterUid,
586 maxCounterUid,
587 counterClass,
588 counterInterpolation,
589 counterMultiplier,
590 counterName,
591 counterDescription,
592 counterUnits,
593 deviceUid,
594 counterSetUid);
595 ARM_PIPE_ASSERT(counter);
596
597 // Create an event record
598 SendCounterPacket::EventRecord eventRecord;
599 std::string errorMessage;
600 bool result = sendCounterPacketTest.CreateEventRecordTest(counter, eventRecord, errorMessage);
601
602 CHECK(result);
603 CHECK(errorMessage.empty());
604 CHECK(eventRecord.size() == 24); // Size in words: header [8] + counter name [6] + description [7] + units [3]
605
606 uint16_t eventRecordWord0[]
607 {
608 static_cast<uint16_t>(eventRecord[0] >> 16),
609 static_cast<uint16_t>(eventRecord[0])
610 };
611 uint16_t eventRecordWord1[]
612 {
613 static_cast<uint16_t>(eventRecord[1] >> 16),
614 static_cast<uint16_t>(eventRecord[1])
615 };
616 uint16_t eventRecordWord2[]
617 {
618 static_cast<uint16_t>(eventRecord[2] >> 16),
619 static_cast<uint16_t>(eventRecord[2])
620 };
621 uint32_t eventRecordWord34[]
622 {
623 eventRecord[3],
624 eventRecord[4]
625 };
626
627 CHECK(eventRecordWord0[0] == maxCounterUid); // max_counter_uid
628 CHECK(eventRecordWord0[1] == counterUid); // counter_uid
629 CHECK(eventRecordWord1[0] == deviceUid); // device
630
631 CHECK(eventRecordWord1[1] == counterSetUid); // counter_set
632 CHECK(eventRecordWord2[0] == counterClass); // class
633 CHECK(eventRecordWord2[1] == counterInterpolation); // interpolation
634 CHECK(std::memcmp(eventRecordWord34, &counterMultiplier, sizeof(counterMultiplier)) == 0); // multiplier
635
636 ARM_PIPE_NO_CONVERSION_WARN_BEGIN
637 uint32_t eventRecordBlockSize = 8u * sizeof(uint32_t);
638 uint32_t counterNameOffset = eventRecordBlockSize; // The name is the first item in pool
639 uint32_t counterDescriptionOffset = counterNameOffset + // Counter name offset
640 4u + // Counter name length (uint32_t)
641 counterName.size() + // 18u
642 1u + // Null-terminator
643 1u; // Rounding to the next word
644
645 size_t counterUnitsOffset = counterDescriptionOffset + // Counter description offset
646 4u + // Counter description length (uint32_t)
647 counterDescription.size() + // 21u
648 1u + // Null-terminator
649 2u; // Rounding to the next word
650
651 ARM_PIPE_NO_CONVERSION_WARN_END
652
653 CHECK(eventRecord[5] == counterNameOffset); // name_offset
654 CHECK(eventRecord[6] == counterDescriptionOffset); // description_offset
655 CHECK(eventRecord[7] == counterUnitsOffset); // units_offset
656
657 // Offsets are relative to the start of the eventRecord
658 auto eventRecordPool = reinterpret_cast<unsigned char*>(eventRecord.data());
659 size_t uint32_t_size = sizeof(uint32_t);
660
661 // The length of the SWTrace string (name)
662 CHECK(eventRecordPool[counterNameOffset] == counterName.size() + 1);
663 // The counter name
664 CHECK(std::memcmp(eventRecordPool +
665 counterNameOffset + // Offset
666 uint32_t_size /* The length of the name */,
667 counterName.data(),
668 counterName.size()) == 0); // name
669 // The null-terminator at the end of the name
670 CHECK(eventRecordPool[counterNameOffset + uint32_t_size + counterName.size()] == '\0');
671
672 // The length of the SWTrace string (description)
673 CHECK(eventRecordPool[counterDescriptionOffset] == counterDescription.size() + 1);
674 // The counter description
675 CHECK(std::memcmp(eventRecordPool +
676 counterDescriptionOffset + // Offset
677 uint32_t_size /* The length of the description */,
678 counterDescription.data(),
679 counterDescription.size()) == 0); // description
680 // The null-terminator at the end of the description
681 CHECK(eventRecordPool[counterDescriptionOffset + uint32_t_size + counterDescription.size()] == '\0');
682
683 // The length of the SWTrace namestring (units)
684 CHECK(eventRecordPool[counterUnitsOffset] == counterUnits.size() + 1);
685 // The counter units
686 CHECK(std::memcmp(eventRecordPool +
687 counterUnitsOffset + // Offset
688 uint32_t_size /* The length of the units */,
689 counterUnits.data(),
690 counterUnits.size()) == 0); // units
691 // The null-terminator at the end of the units
692 CHECK(eventRecordPool[counterUnitsOffset + uint32_t_size + counterUnits.size()] == '\0');
693 }
694
695 TEST_CASE("CreateEventRecordNoUnitsTest")
696 {
697 MockBufferManager mockBuffer(0);
698 SendCounterPacketTest sendCounterPacketTest(mockBuffer);
699
700 // Create a counter for testing
701 uint16_t counterUid = 44312;
702 uint16_t maxCounterUid = 345;
703 uint16_t deviceUid = 101;
704 uint16_t counterSetUid = 34035;
705 uint16_t counterClass = 0;
706 uint16_t counterInterpolation = 1;
707 double counterMultiplier = 4435.0023f;
708 const std::string counterName = "some_valid_counter";
709 const std::string counterDescription = "a_counter_for_testing";
710 const CounterPtr counter = std::make_unique<Counter>(armnn::profiling::BACKEND_ID,
711 counterUid,
712 maxCounterUid,
713 counterClass,
714 counterInterpolation,
715 counterMultiplier,
716 counterName,
717 counterDescription,
718 "",
719 deviceUid,
720 counterSetUid);
721 ARM_PIPE_ASSERT(counter);
722
723 // Create an event record
724 SendCounterPacket::EventRecord eventRecord;
725 std::string errorMessage;
726 bool result = sendCounterPacketTest.CreateEventRecordTest(counter, eventRecord, errorMessage);
727
728 CHECK(result);
729 CHECK(errorMessage.empty());
730 CHECK(eventRecord.size() == 21); // Size in words: header [8] + counter name [6] + description [7]
731
732 uint16_t eventRecordWord0[]
733 {
734 static_cast<uint16_t>(eventRecord[0] >> 16),
735 static_cast<uint16_t>(eventRecord[0])
736 };
737 uint16_t eventRecordWord1[]
738 {
739 static_cast<uint16_t>(eventRecord[1] >> 16),
740 static_cast<uint16_t>(eventRecord[1])
741 };
742 uint16_t eventRecordWord2[]
743 {
744 static_cast<uint16_t>(eventRecord[2] >> 16),
745 static_cast<uint16_t>(eventRecord[2])
746 };
747 uint32_t eventRecordWord34[]
748 {
749 eventRecord[3],
750 eventRecord[4]
751 };
752 CHECK(eventRecordWord0[0] == maxCounterUid); // max_counter_uid
753 CHECK(eventRecordWord0[1] == counterUid); // counter_uid
754 CHECK(eventRecordWord1[0] == deviceUid); // device
755 CHECK(eventRecordWord1[1] == counterSetUid); // counter_set
756 CHECK(eventRecordWord2[0] == counterClass); // class
757 CHECK(eventRecordWord2[1] == counterInterpolation); // interpolation
758 CHECK(std::memcmp(eventRecordWord34, &counterMultiplier, sizeof(counterMultiplier)) == 0); // multiplier
759
760 ARM_PIPE_NO_CONVERSION_WARN_BEGIN
761 uint32_t eventRecordBlockSize = 8u * sizeof(uint32_t);
762 uint32_t counterNameOffset = eventRecordBlockSize; // The name is the first item in pool
763 uint32_t counterDescriptionOffset = counterNameOffset + // Counter name offset
764 4u + // Counter name length (uint32_t)
765 counterName.size() + // 18u
766 1u + // Null-terminator
767 1u; // Rounding to the next word
768 ARM_PIPE_NO_CONVERSION_WARN_END
769
770 CHECK(eventRecord[5] == counterNameOffset); // name_offset
771 CHECK(eventRecord[6] == counterDescriptionOffset); // description_offset
772 CHECK(eventRecord[7] == 0); // units_offset
773
774 // Offsets are relative to the start of the eventRecord
775 auto eventRecordPool = reinterpret_cast<unsigned char*>(eventRecord.data());
776 size_t uint32_t_size = sizeof(uint32_t);
777
778 // The length of the SWTrace string (name)
779 CHECK(eventRecordPool[counterNameOffset] == counterName.size() + 1);
780 // The counter name
781 CHECK(std::memcmp(eventRecordPool +
782 counterNameOffset + // Offset
783 uint32_t_size, // The length of the name
784 counterName.data(),
785 counterName.size()) == 0); // name
786 // The null-terminator at the end of the name
787 CHECK(eventRecordPool[counterNameOffset + uint32_t_size + counterName.size()] == '\0');
788
789 // The length of the SWTrace string (description)
790 CHECK(eventRecordPool[counterDescriptionOffset] == counterDescription.size() + 1);
791 // The counter description
792 CHECK(std::memcmp(eventRecordPool +
793 counterDescriptionOffset + // Offset
794 uint32_t_size, // The length of the description
795 counterDescription.data(),
796 counterDescription.size()) == 0); // description
797 // The null-terminator at the end of the description
798 CHECK(eventRecordPool[counterDescriptionOffset + uint32_t_size + counterDescription.size()] == '\0');
799 }
800
801 TEST_CASE("CreateInvalidEventRecordTest1")
802 {
803 MockBufferManager mockBuffer(0);
804 SendCounterPacketTest sendCounterPacketTest(mockBuffer);
805
806 // Create a counter for testing
807 uint16_t counterUid = 7256;
808 uint16_t maxCounterUid = 132;
809 uint16_t deviceUid = 132;
810 uint16_t counterSetUid = 4497;
811 uint16_t counterClass = 1;
812 uint16_t counterInterpolation = 1;
813 double counterMultiplier = 1234.567f;
814 const std::string counterName = "some_invalid_counter £££"; // Invalid name
815 const std::string counterDescription = "a_counter_for_testing";
816 const std::string counterUnits = "Mrads2";
817 const CounterPtr counter = std::make_unique<Counter>(armnn::profiling::BACKEND_ID,
818 counterUid,
819 maxCounterUid,
820 counterClass,
821 counterInterpolation,
822 counterMultiplier,
823 counterName,
824 counterDescription,
825 counterUnits,
826 deviceUid,
827 counterSetUid);
828 ARM_PIPE_ASSERT(counter);
829
830 // Create an event record
831 SendCounterPacket::EventRecord eventRecord;
832 std::string errorMessage;
833 bool result = sendCounterPacketTest.CreateEventRecordTest(counter, eventRecord, errorMessage);
834
835 CHECK(!result);
836 CHECK(!errorMessage.empty());
837 CHECK(eventRecord.empty());
838 }
839
840 TEST_CASE("CreateInvalidEventRecordTest2")
841 {
842 MockBufferManager mockBuffer(0);
843 SendCounterPacketTest sendCounterPacketTest(mockBuffer);
844
845 // Create a counter for testing
846 uint16_t counterUid = 7256;
847 uint16_t maxCounterUid = 132;
848 uint16_t deviceUid = 132;
849 uint16_t counterSetUid = 4497;
850 uint16_t counterClass = 1;
851 uint16_t counterInterpolation = 1;
852 double counterMultiplier = 1234.567f;
853 const std::string counterName = "some_invalid_counter";
854 const std::string counterDescription = "an invalid d€scription"; // Invalid description
855 const std::string counterUnits = "Mrads2";
856 const CounterPtr counter = std::make_unique<Counter>(armnn::profiling::BACKEND_ID,
857 counterUid,
858 maxCounterUid,
859 counterClass,
860 counterInterpolation,
861 counterMultiplier,
862 counterName,
863 counterDescription,
864 counterUnits,
865 deviceUid,
866 counterSetUid);
867 ARM_PIPE_ASSERT(counter);
868
869 // Create an event record
870 SendCounterPacket::EventRecord eventRecord;
871 std::string errorMessage;
872 bool result = sendCounterPacketTest.CreateEventRecordTest(counter, eventRecord, errorMessage);
873
874 CHECK(!result);
875 CHECK(!errorMessage.empty());
876 CHECK(eventRecord.empty());
877 }
878
879 TEST_CASE("CreateInvalidEventRecordTest3")
880 {
881 MockBufferManager mockBuffer(0);
882 SendCounterPacketTest sendCounterPacketTest(mockBuffer);
883
884 // Create a counter for testing
885 uint16_t counterUid = 7256;
886 uint16_t maxCounterUid = 132;
887 uint16_t deviceUid = 132;
888 uint16_t counterSetUid = 4497;
889 uint16_t counterClass = 1;
890 uint16_t counterInterpolation = 1;
891 double counterMultiplier = 1234.567f;
892 const std::string counterName = "some_invalid_counter";
893 const std::string counterDescription = "a valid description";
894 const std::string counterUnits = "Mrad s2"; // Invalid units
895 const CounterPtr counter = std::make_unique<Counter>(armnn::profiling::BACKEND_ID,
896 counterUid,
897 maxCounterUid,
898 counterClass,
899 counterInterpolation,
900 counterMultiplier,
901 counterName,
902 counterDescription,
903 counterUnits,
904 deviceUid,
905 counterSetUid);
906 ARM_PIPE_ASSERT(counter);
907
908 // Create an event record
909 SendCounterPacket::EventRecord eventRecord;
910 std::string errorMessage;
911 bool result = sendCounterPacketTest.CreateEventRecordTest(counter, eventRecord, errorMessage);
912
913 CHECK(!result);
914 CHECK(!errorMessage.empty());
915 CHECK(eventRecord.empty());
916 }
917
918 TEST_CASE("CreateCategoryRecordTest")
919 {
920 MockBufferManager mockBuffer(0);
921 SendCounterPacketTest sendCounterPacketTest(mockBuffer);
922
923 // Create a category for testing
924 const std::string categoryName = "some_category";
925 const CategoryPtr category = std::make_unique<Category>(categoryName);
926 ARM_PIPE_ASSERT(category);
927 category->m_Counters = { 11u, 23u, 5670u };
928
929 // Create a collection of counters
930 Counters counters;
931 counters.insert(std::make_pair<uint16_t, CounterPtr>(11,
932 CounterPtr(new Counter(armnn::profiling::BACKEND_ID,
933 0,
934 11,
935 0,
936 0,
937 534.0003f,
938 "counter1",
939 "the first counter",
940 "millipi2",
941 0,
942 0))));
943 counters.insert(std::make_pair<uint16_t, CounterPtr>(23,
944 CounterPtr(new Counter(armnn::profiling::BACKEND_ID,
945 1,
946 23,
947 0,
948 1,
949 534.0003f,
950 "this is counter 2",
951 "the second counter",
952 "",
953 0,
954 0))));
955 counters.insert(std::make_pair<uint16_t, CounterPtr>(5670,
956 CounterPtr(new Counter(armnn::profiling::BACKEND_ID,
957 2,
958 5670,
959 0,
960 0,
961 534.0003f,
962 "and this is number 3",
963 "the third counter",
964 "blah_per_second",
965 0,
966 0))));
967 Counter* counter1 = counters.find(11)->second.get();
968 Counter* counter2 = counters.find(23)->second.get();
969 Counter* counter3 = counters.find(5670)->second.get();
970 ARM_PIPE_ASSERT(counter1);
971 ARM_PIPE_ASSERT(counter2);
972 ARM_PIPE_ASSERT(counter3);
973 uint16_t categoryEventCount = armnn::numeric_cast<uint16_t>(counters.size());
974
975 // Create a category record
976 SendCounterPacket::CategoryRecord categoryRecord;
977 std::string errorMessage;
978 bool result = sendCounterPacketTest.CreateCategoryRecordTest(category, counters, categoryRecord, errorMessage);
979
980 CHECK(result);
981 CHECK(errorMessage.empty());
982 CHECK(categoryRecord.size() == 79); // Size in words: header [3] + event pointer table [3] +
983 // category name [5] + event records [68 = 22 + 20 + 26]
984
985 uint16_t categoryRecordWord1[]
986 {
987 static_cast<uint16_t>(categoryRecord[0] >> 16),
988 static_cast<uint16_t>(categoryRecord[0])
989 };
990 CHECK(categoryRecordWord1[0] == categoryEventCount); // event_count
991 CHECK(categoryRecordWord1[1] == 0); // reserved
992
993 size_t uint32_t_size = sizeof(uint32_t);
994
995 ARM_PIPE_NO_CONVERSION_WARN_BEGIN
996 uint32_t categoryRecordBlockSize = 3u * uint32_t_size;
997 uint32_t eventPointerTableOffset = categoryRecordBlockSize; // The event pointer table is the first item in pool
998 uint32_t categoryNameOffset = eventPointerTableOffset + // Event pointer table offset
999 categoryEventCount * uint32_t_size; // The size of the event pointer table
1000 ARM_PIPE_NO_CONVERSION_WARN_END
1001
1002 CHECK(categoryRecord[1] == eventPointerTableOffset); // event_pointer_table_offset
1003 CHECK(categoryRecord[2] == categoryNameOffset); // name_offset
1004 // Offsets are relative to the start of the category record
1005 auto categoryRecordPool = reinterpret_cast<unsigned char*>(categoryRecord.data());
1006
1007 // The event pointer table
1008 uint32_t eventRecord0Offset = categoryRecordPool[eventPointerTableOffset + 0 * uint32_t_size];
1009 uint32_t eventRecord1Offset = categoryRecordPool[eventPointerTableOffset + 1 * uint32_t_size];
1010 uint32_t eventRecord2Offset = categoryRecordPool[eventPointerTableOffset + 2 * uint32_t_size];
1011 CHECK(eventRecord0Offset == 32);
1012 CHECK(eventRecord1Offset == 120);
1013 CHECK(eventRecord2Offset == 200);
1014
1015 // The length of the SWTrace namestring (name)
1016 CHECK(categoryRecordPool[categoryNameOffset] == categoryName.size() + 1);
1017 // The category name
1018 CHECK(std::memcmp(categoryRecordPool +
1019 categoryNameOffset + // Offset
1020 uint32_t_size, // The length of the name
1021 categoryName.data(),
1022 categoryName.size()) == 0); // name
1023 // The null-terminator at the end of the name
1024 CHECK(categoryRecordPool[categoryNameOffset + uint32_t_size + categoryName.size()] == '\0');
1025
1026 // For brevity, checking only the UIDs, max counter UIDs and names of the counters in the event records,
1027 // as the event records already have a number of unit tests dedicated to them
1028
1029 // Counter1 UID and max counter UID
1030 uint16_t eventRecord0Word0[2] = { 0u, 0u };
1031 std::memcpy(eventRecord0Word0, categoryRecordPool + categoryRecordBlockSize + eventRecord0Offset,
1032 sizeof(eventRecord0Word0));
1033 CHECK(eventRecord0Word0[0] == counter1->m_Uid);
1034 CHECK(eventRecord0Word0[1] == counter1->m_MaxCounterUid);
1035
1036 // Counter1 name
1037 uint32_t counter1NameOffset = 0;
1038 std::memcpy(&counter1NameOffset, categoryRecordPool + eventRecord0Offset + 5u * uint32_t_size, uint32_t_size);
1039 CHECK(counter1NameOffset == 0);
1040 // The length of the SWTrace string (name)
1041 CHECK(categoryRecordPool[eventRecord0Offset + // Offset to the event record
1042 categoryRecordBlockSize + // Offset to the end of the category record block
1043 8u * uint32_t_size + // Offset to the event record pool
1044 counter1NameOffset // Offset to the name of the counter
1045 ] == counter1->m_Name.size() + 1); // The length of the name including the
1046 // null-terminator
1047 // The counter1 name
1048 CHECK(std::memcmp(categoryRecordPool + // The beginning of the category pool
1049 categoryRecordBlockSize + // Offset to the end of the category record block
1050 eventRecord0Offset + // Offset to the event record
1051 8u * uint32_t_size + // Offset to the event record pool
1052 counter1NameOffset + // Offset to the name of the counter
1053 uint32_t_size, // The length of the name
1054 counter1->m_Name.data(),
1055 counter1->m_Name.size()) == 0); // name
1056 // The null-terminator at the end of the counter1 name
1057 CHECK(categoryRecordPool[eventRecord0Offset + // Offset to the event record
1058 categoryRecordBlockSize + // Offset to the end of the category record block
1059 8u * uint32_t_size + // Offset to the event record pool
1060 counter1NameOffset + // Offset to the name of the counter
1061 uint32_t_size + // The length of the name
1062 counter1->m_Name.size() // The name of the counter
1063 ] == '\0');
1064
1065 // Counter2 name
1066 uint32_t counter2NameOffset = 0;
1067 std::memcpy(&counter2NameOffset, categoryRecordPool +
1068 categoryRecordBlockSize +
1069 eventRecord1Offset +
1070 5u * uint32_t_size,
1071 uint32_t_size);
1072 CHECK(counter2NameOffset == 8u * uint32_t_size );
1073 // The length of the SWTrace string (name)
1074
1075 CHECK(categoryRecordPool[eventRecord1Offset + // Offset to the event record
1076 categoryRecordBlockSize +
1077 counter2NameOffset // Offset to the name of the counter
1078 ] == counter2->m_Name.size() + 1); // The length of the name including the
1079 // null-terminator
1080 // The counter2 name
1081 CHECK(std::memcmp(categoryRecordPool + // The beginning of the category pool
1082 categoryRecordBlockSize + // Offset to the end of the category record block
1083 eventRecord1Offset + // Offset to the event record
1084 counter2NameOffset + // Offset to the name of the counter
1085 uint32_t_size, // The length of the name
1086 counter2->m_Name.data(),
1087 counter2->m_Name.size()) == 0); // name
1088
1089
1090 // The null-terminator at the end of the counter2 name
1091 CHECK(categoryRecordPool[eventRecord1Offset + // Offset to the event record
1092 categoryRecordBlockSize + // Offset to the end of the category record block
1093 counter2NameOffset + // Offset to the name of the counter
1094 uint32_t_size + // The length of the name
1095 counter2->m_Name.size() // The name of the counter
1096 ] == '\0');
1097
1098 // Counter3 name
1099 uint32_t counter3NameOffset = 0;
1100 std::memcpy(&counter3NameOffset, categoryRecordPool + eventRecord2Offset + 5u * uint32_t_size, uint32_t_size);
1101 CHECK(counter3NameOffset == 0);
1102 // The length of the SWTrace string (name)
1103 CHECK(categoryRecordPool[eventRecord2Offset + // Offset to the event record
1104 categoryRecordBlockSize +
1105 8u * uint32_t_size + // Offset to the event record pool
1106 counter3NameOffset // Offset to the name of the counter
1107 ] == counter3->m_Name.size() + 1); // The length of the name including the
1108 // null-terminator
1109 // The counter3 name
1110 CHECK(std::memcmp(categoryRecordPool + // The beginning of the category pool
1111 categoryRecordBlockSize +
1112 eventRecord2Offset + // Offset to the event record
1113 8u * uint32_t_size + // Offset to the event record pool
1114 counter3NameOffset + // Offset to the name of the counter
1115 uint32_t_size, // The length of the name
1116 counter3->m_Name.data(),
1117 counter3->m_Name.size()) == 0); // name
1118 // The null-terminator at the end of the counter3 name
1119 CHECK(categoryRecordPool[eventRecord2Offset + // Offset to the event record
1120 categoryRecordBlockSize +
1121 8u * uint32_t_size + // Offset to the event record pool
1122 counter3NameOffset + // Offset to the name of the counter
1123 uint32_t_size + // The length of the name
1124 counter3->m_Name.size() // The name of the counter
1125 ] == '\0');
1126 }
1127
1128 TEST_CASE("CreateInvalidCategoryRecordTest1")
1129 {
1130 MockBufferManager mockBuffer(0);
1131 SendCounterPacketTest sendCounterPacketTest(mockBuffer);
1132
1133 // Create a category for testing
1134 const std::string categoryName = "some invalid category";
1135 const CategoryPtr category = std::make_unique<Category>(categoryName);
1136 CHECK(category);
1137
1138 // Create a category record
1139 Counters counters;
1140 SendCounterPacket::CategoryRecord categoryRecord;
1141 std::string errorMessage;
1142 bool result = sendCounterPacketTest.CreateCategoryRecordTest(category, counters, categoryRecord, errorMessage);
1143
1144 CHECK(!result);
1145 CHECK(!errorMessage.empty());
1146 CHECK(categoryRecord.empty());
1147 }
1148
1149 TEST_CASE("CreateInvalidCategoryRecordTest2")
1150 {
1151 MockBufferManager mockBuffer(0);
1152 SendCounterPacketTest sendCounterPacketTest(mockBuffer);
1153
1154 // Create a category for testing
1155 const std::string categoryName = "some_category";
1156 const CategoryPtr category = std::make_unique<Category>(categoryName);
1157 CHECK(category);
1158 category->m_Counters = { 11u, 23u, 5670u };
1159
1160 // Create a collection of counters
1161 Counters counters;
1162 counters.insert(std::make_pair<uint16_t, CounterPtr>(11,
1163 CounterPtr(new Counter(armnn::profiling::BACKEND_ID,
1164 11,
1165 1234,
1166 0,
1167 1,
1168 534.0003f,
1169 "count€r1", // Invalid name
1170 "the first counter",
1171 "millipi2",
1172 0,
1173 0))));
1174
1175 Counter* counter1 = counters.find(11)->second.get();
1176 CHECK(counter1);
1177
1178 // Create a category record
1179 SendCounterPacket::CategoryRecord categoryRecord;
1180 std::string errorMessage;
1181 bool result = sendCounterPacketTest.CreateCategoryRecordTest(category, counters, categoryRecord, errorMessage);
1182
1183 CHECK(!result);
1184 CHECK(!errorMessage.empty());
1185 CHECK(categoryRecord.empty());
1186 }
1187
1188 TEST_CASE("SendCounterDirectoryPacketTest1")
1189 {
1190 // The counter directory used for testing
1191 CounterDirectory counterDirectory;
1192
1193 // Register a device
1194 const std::string device1Name = "device1";
1195 const Device* device1 = nullptr;
1196 CHECK_NOTHROW(device1 = counterDirectory.RegisterDevice(device1Name, 3));
1197 CHECK(counterDirectory.GetDeviceCount() == 1);
1198 CHECK(device1);
1199
1200 // Register a device
1201 const std::string device2Name = "device2";
1202 const Device* device2 = nullptr;
1203 CHECK_NOTHROW(device2 = counterDirectory.RegisterDevice(device2Name));
1204 CHECK(counterDirectory.GetDeviceCount() == 2);
1205 CHECK(device2);
1206
1207 // Buffer with not enough space
1208 MockBufferManager mockBuffer(10);
1209 SendCounterPacket sendCounterPacket(mockBuffer,
1210 arm::pipe::ARMNN_SOFTWARE_INFO,
1211 arm::pipe::ARMNN_SOFTWARE_VERSION,
1212 arm::pipe::ARMNN_HARDWARE_VERSION);
1213 CHECK_THROWS_AS(sendCounterPacket.SendCounterDirectoryPacket(counterDirectory),
1214 BufferExhaustion);
1215 }
1216
1217 TEST_CASE("SendCounterDirectoryPacketTest2")
1218 {
1219 // The counter directory used for testing
1220 CounterDirectory counterDirectory;
1221
1222 // Register a device
1223 const std::string device1Name = "device1";
1224 const Device* device1 = nullptr;
1225 CHECK_NOTHROW(device1 = counterDirectory.RegisterDevice(device1Name, 3));
1226 CHECK(counterDirectory.GetDeviceCount() == 1);
1227 CHECK(device1);
1228
1229 // Register a device
1230 const std::string device2Name = "device2";
1231 const Device* device2 = nullptr;
1232 CHECK_NOTHROW(device2 = counterDirectory.RegisterDevice(device2Name));
1233 CHECK(counterDirectory.GetDeviceCount() == 2);
1234 CHECK(device2);
1235
1236 // Register a counter set
1237 const std::string counterSet1Name = "counterset1";
1238 const CounterSet* counterSet1 = nullptr;
1239 CHECK_NOTHROW(counterSet1 = counterDirectory.RegisterCounterSet(counterSet1Name));
1240 CHECK(counterDirectory.GetCounterSetCount() == 1);
1241 CHECK(counterSet1);
1242
1243 // Register a category associated to "device1" and "counterset1"
1244 const std::string category1Name = "category1";
1245 const Category* category1 = nullptr;
1246 CHECK_NOTHROW(category1 = counterDirectory.RegisterCategory(category1Name));
1247 CHECK(counterDirectory.GetCategoryCount() == 1);
1248 CHECK(category1);
1249
1250 // Register a category not associated to "device2" but no counter set
1251 const std::string category2Name = "category2";
1252 const Category* category2 = nullptr;
1253 CHECK_NOTHROW(category2 = counterDirectory.RegisterCategory(category2Name));
1254 CHECK(counterDirectory.GetCategoryCount() == 2);
1255 CHECK(category2);
1256
1257 uint16_t numberOfCores = 4;
1258
1259 // Register a counter associated to "category1"
1260 const Counter* counter1 = nullptr;
1261 CHECK_NOTHROW(counter1 = counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1262 0,
1263 category1Name,
1264 0,
1265 1,
1266 123.45f,
1267 "counter1",
1268 "counter1description",
1269 std::string("counter1units"),
1270 numberOfCores));
1271 CHECK(counterDirectory.GetCounterCount() == 4);
1272 CHECK(counter1);
1273
1274 // Register a counter associated to "category1"
1275 const Counter* counter2 = nullptr;
1276 CHECK_NOTHROW(counter2 = counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1277 4,
1278 category1Name,
1279 1,
1280 0,
1281 330.1245656765f,
1282 "counter2",
1283 "counter2description",
1284 std::string("counter2units"),
1285 arm::pipe::EmptyOptional(),
1286 device2->m_Uid,
1287 0));
1288 CHECK(counterDirectory.GetCounterCount() == 5);
1289 CHECK(counter2);
1290
1291 // Register a counter associated to "category2"
1292 const Counter* counter3 = nullptr;
1293 CHECK_NOTHROW(counter3 = counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1294 5,
1295 category2Name,
1296 1,
1297 1,
1298 0.0000045399f,
1299 "counter3",
1300 "counter3description",
1301 arm::pipe::EmptyOptional(),
1302 numberOfCores,
1303 device2->m_Uid,
1304 counterSet1->m_Uid));
1305 CHECK(counterDirectory.GetCounterCount() == 9);
1306 CHECK(counter3);
1307
1308 // Buffer with enough space
1309 MockBufferManager mockBuffer(1024);
1310 SendCounterPacket sendCounterPacket(mockBuffer,
1311 arm::pipe::ARMNN_SOFTWARE_INFO,
1312 arm::pipe::ARMNN_SOFTWARE_VERSION,
1313 arm::pipe::ARMNN_HARDWARE_VERSION);
1314 CHECK_NOTHROW(sendCounterPacket.SendCounterDirectoryPacket(counterDirectory));
1315
1316 // Get the readable buffer
1317 auto readBuffer = mockBuffer.GetReadableBuffer();
1318
1319 // Check the packet header
1320 const uint32_t packetHeaderWord0 = ReadUint32(readBuffer, 0);
1321 const uint32_t packetHeaderWord1 = ReadUint32(readBuffer, 4);
1322 CHECK(((packetHeaderWord0 >> 26) & 0x3F) == 0); // packet_family
1323 CHECK(((packetHeaderWord0 >> 16) & 0x3FF) == 2); // packet_id
1324 CHECK(packetHeaderWord1 == 432); // data_length
1325
1326 // Check the body header
1327 const uint32_t bodyHeaderWord0 = ReadUint32(readBuffer, 8);
1328 const uint32_t bodyHeaderWord1 = ReadUint32(readBuffer, 12);
1329 const uint32_t bodyHeaderWord2 = ReadUint32(readBuffer, 16);
1330 const uint32_t bodyHeaderWord3 = ReadUint32(readBuffer, 20);
1331 const uint32_t bodyHeaderWord4 = ReadUint32(readBuffer, 24);
1332 const uint32_t bodyHeaderWord5 = ReadUint32(readBuffer, 28);
1333 const uint16_t deviceRecordCount = static_cast<uint16_t>(bodyHeaderWord0 >> 16);
1334 const uint16_t counterSetRecordCount = static_cast<uint16_t>(bodyHeaderWord2 >> 16);
1335 const uint16_t categoryRecordCount = static_cast<uint16_t>(bodyHeaderWord4 >> 16);
1336 CHECK(deviceRecordCount == 2); // device_records_count
1337 CHECK(bodyHeaderWord1 == bodyHeaderSize * 4); // device_records_pointer_table_offset
1338 CHECK(counterSetRecordCount == 1); // counter_set_count
1339 CHECK(bodyHeaderWord3 == 8 + bodyHeaderSize * 4); // counter_set_pointer_table_offset
1340 CHECK(categoryRecordCount == 2); // categories_count
1341 CHECK(bodyHeaderWord5 == 12 + bodyHeaderSize * 4); // categories_pointer_table_offset
1342
1343 // Check the device records pointer table
1344 const uint32_t deviceRecordOffset0 = ReadUint32(readBuffer, 32);
1345 const uint32_t deviceRecordOffset1 = ReadUint32(readBuffer, 36);
1346 CHECK(deviceRecordOffset0 == 20); // Device record offset for "device1"
1347 CHECK(deviceRecordOffset1 == 40); // Device record offset for "device2"
1348
1349 // Check the counter set pointer table
1350 const uint32_t counterSetRecordOffset0 = ReadUint32(readBuffer, 40);
1351 CHECK(counterSetRecordOffset0 == 52); // Counter set record offset for "counterset1"
1352
1353 // Check the category pointer table
1354 const uint32_t categoryRecordOffset0 = ReadUint32(readBuffer, 44);
1355 const uint32_t categoryRecordOffset1 = ReadUint32(readBuffer, 48);
1356 CHECK(categoryRecordOffset0 == 72); // Category record offset for "category1"
1357 CHECK(categoryRecordOffset1 == 176); // Category record offset for "category2"
1358
1359 // Get the device record pool offset
1360 const uint32_t uint32_t_size = sizeof(uint32_t);
1361 const uint32_t packetHeaderSize = 2u * uint32_t_size;
1362
1363 // Device record structure/collection used for testing
1364 struct DeviceRecord
1365 {
1366 uint16_t uid;
1367 uint16_t cores;
1368 uint32_t name_offset;
1369 uint32_t name_length;
1370 std::string name;
1371 };
1372 std::vector<DeviceRecord> deviceRecords;
1373 const uint32_t deviceRecordsPointerTableOffset = packetHeaderSize +
1374 bodyHeaderWord1; // device_records_pointer_table_offset
1375
1376 const unsigned char* readData = readBuffer->GetReadableData();
1377
1378 uint32_t offset = 0;
1379 std::vector<uint32_t> data(800);
1380
1381 for (uint32_t i = 0; i < 800; i+=uint32_t_size)
1382 {
1383 data[i] = ReadUint32(readBuffer, offset);
1384 offset += uint32_t_size;
1385 }
1386
1387 std::vector<uint32_t> deviceRecordOffsets(deviceRecordCount);
1388 offset = deviceRecordsPointerTableOffset;
1389 for (uint32_t i = 0; i < deviceRecordCount; ++i)
1390 {
1391 // deviceRecordOffset is relative to the start of the deviceRecordsPointerTable
1392 deviceRecordOffsets[i] = ReadUint32(readBuffer, offset) + deviceRecordsPointerTableOffset;
1393 offset += uint32_t_size;
1394 }
1395
1396 for (uint32_t i = 0; i < deviceRecordCount; i++)
1397 {
1398 // Collect the data for the device record
1399 const uint32_t deviceRecordWord0 = ReadUint32(readBuffer, deviceRecordOffsets[i] + 0 * uint32_t_size);
1400 const uint32_t deviceRecordWord1 = ReadUint32(readBuffer, deviceRecordOffsets[i] + 1 * uint32_t_size);
1401 DeviceRecord deviceRecord;
1402 deviceRecord.uid = static_cast<uint16_t>(deviceRecordWord0 >> 16); // uid
1403 deviceRecord.cores = static_cast<uint16_t>(deviceRecordWord0); // cores
1404 deviceRecord.name_offset = deviceRecordWord1; // name_offset
1405
1406 uint32_t deviceRecordPoolOffset = deviceRecordOffsets[i] + // Packet body offset
1407 deviceRecord.name_offset; // Device name offset
1408 uint32_t deviceRecordNameLength = ReadUint32(readBuffer, deviceRecordPoolOffset);
1409 deviceRecord.name_length = deviceRecordNameLength; // name_length
1410 unsigned char deviceRecordNameNullTerminator = // name null-terminator
1411 ReadUint8(readBuffer, deviceRecordPoolOffset + uint32_t_size + deviceRecordNameLength - 1);
1412 CHECK(deviceRecordNameNullTerminator == '\0');
1413 std::vector<unsigned char> deviceRecordNameBuffer(deviceRecord.name_length - 1);
1414 std::memcpy(deviceRecordNameBuffer.data(),
1415 readData + deviceRecordPoolOffset + uint32_t_size, deviceRecordNameBuffer.size());
1416 deviceRecord.name.assign(deviceRecordNameBuffer.begin(), deviceRecordNameBuffer.end()); // name
1417
1418 deviceRecords.push_back(deviceRecord);
1419 }
1420
1421 // Check that the device records are correct
1422 CHECK(deviceRecords.size() == 2);
1423 for (const DeviceRecord& deviceRecord : deviceRecords)
1424 {
1425 const Device* device = counterDirectory.GetDevice(deviceRecord.uid);
1426 CHECK(device);
1427 CHECK(device->m_Uid == deviceRecord.uid);
1428 CHECK(device->m_Cores == deviceRecord.cores);
1429 CHECK(device->m_Name == deviceRecord.name);
1430 }
1431
1432
1433 // Counter set record structure/collection used for testing
1434 struct CounterSetRecord
1435 {
1436 uint16_t uid;
1437 uint16_t count;
1438 uint32_t name_offset;
1439 uint32_t name_length;
1440 std::string name;
1441 };
1442 std::vector<CounterSetRecord> counterSetRecords;
1443 const uint32_t counterSetRecordsPointerTableOffset = 2u * uint32_t_size + // packet_header
1444 bodyHeaderWord3; // counter_set_pointer_table_offset
1445
1446 offset = counterSetRecordsPointerTableOffset;
1447 std::vector<uint32_t> counterSetRecordOffsets(counterSetRecordCount);
1448
1449 for (uint32_t i = 0; i < counterSetRecordCount; ++i)
1450 {
1451 // counterSetRecordOffset is relative to the start of the dcounterSetRecordsPointerTable
1452 counterSetRecordOffsets[i] = ReadUint32(readBuffer, offset) + counterSetRecordsPointerTableOffset;
1453 offset += uint32_t_size;
1454 }
1455
1456 for (uint32_t i = 0; i < counterSetRecordCount; i++)
1457 {
1458 // Collect the data for the counter set record
1459 const uint32_t counterSetRecordWord0 = ReadUint32(readBuffer, counterSetRecordOffsets[i] + 0 * uint32_t_size);
1460 const uint32_t counterSetRecordWord1 = ReadUint32(readBuffer, counterSetRecordOffsets[i] + 1 * uint32_t_size);
1461 CounterSetRecord counterSetRecord;
1462 counterSetRecord.uid = static_cast<uint16_t>(counterSetRecordWord0 >> 16); // uid
1463 counterSetRecord.count = static_cast<uint16_t>(counterSetRecordWord0); // count
1464 counterSetRecord.name_offset = counterSetRecordWord1; // name_offset
1465
1466 uint32_t counterSetRecordPoolOffset = counterSetRecordOffsets[i] + // Packet body offset
1467 counterSetRecord.name_offset; // Counter set name offset
1468 uint32_t counterSetRecordNameLength = ReadUint32(readBuffer, counterSetRecordPoolOffset);
1469 counterSetRecord.name_length = counterSetRecordNameLength; // name_length
1470 unsigned char counterSetRecordNameNullTerminator = // name null-terminator
1471 ReadUint8(readBuffer, counterSetRecordPoolOffset + uint32_t_size + counterSetRecordNameLength - 1);
1472 CHECK(counterSetRecordNameNullTerminator == '\0');
1473 std::vector<unsigned char> counterSetRecordNameBuffer(counterSetRecord.name_length - 1);
1474 std::memcpy(counterSetRecordNameBuffer.data(),
1475 readData + counterSetRecordPoolOffset + uint32_t_size, counterSetRecordNameBuffer.size());
1476 counterSetRecord.name.assign(counterSetRecordNameBuffer.begin(), counterSetRecordNameBuffer.end()); // name
1477
1478 counterSetRecords.push_back(counterSetRecord);
1479 }
1480
1481 // Check that the counter set records are correct
1482 CHECK(counterSetRecords.size() == 1);
1483 for (const CounterSetRecord& counterSetRecord : counterSetRecords)
1484 {
1485 const CounterSet* counterSet = counterDirectory.GetCounterSet(counterSetRecord.uid);
1486 CHECK(counterSet);
1487 CHECK(counterSet->m_Uid == counterSetRecord.uid);
1488 CHECK(counterSet->m_Count == counterSetRecord.count);
1489 CHECK(counterSet->m_Name == counterSetRecord.name);
1490 }
1491
1492 // Event record structure/collection used for testing
1493 struct EventRecord
1494 {
1495 uint16_t counter_uid;
1496 uint16_t max_counter_uid;
1497 uint16_t device;
1498 uint16_t counter_set;
1499 uint16_t counter_class;
1500 uint16_t interpolation;
1501 double multiplier;
1502 uint32_t name_offset;
1503 uint32_t name_length;
1504 std::string name;
1505 uint32_t description_offset;
1506 uint32_t description_length;
1507 std::string description;
1508 uint32_t units_offset;
1509 uint32_t units_length;
1510 std::string units;
1511 };
1512 // Category record structure/collection used for testing
1513 struct CategoryRecord
1514 {
1515 uint16_t event_count;
1516 uint32_t event_pointer_table_offset;
1517 uint32_t name_offset;
1518 uint32_t name_length;
1519 std::string name;
1520 std::vector<uint32_t> event_pointer_table;
1521 std::vector<EventRecord> event_records;
1522 };
1523 std::vector<CategoryRecord> categoryRecords;
1524 const uint32_t categoryRecordsPointerTableOffset = 2u * uint32_t_size + // packet_header
1525 bodyHeaderWord5; // categories_pointer_table_offset
1526
1527 offset = categoryRecordsPointerTableOffset;
1528 std::vector<uint32_t> categoryRecordOffsets(categoryRecordCount);
1529 for (uint32_t i = 0; i < categoryRecordCount; ++i)
1530 {
1531 // categoryRecordOffset is relative to the start of the categoryRecordsPointerTable
1532 categoryRecordOffsets[i] = ReadUint32(readBuffer, offset) + categoryRecordsPointerTableOffset;
1533 offset += uint32_t_size;
1534 }
1535
1536 for (uint32_t i = 0; i < categoryRecordCount; i++)
1537 {
1538 // Collect the data for the category record
1539 const uint32_t categoryRecordWord1 = ReadUint32(readBuffer, categoryRecordOffsets[i] + 0 * uint32_t_size);
1540 const uint32_t categoryRecordWord2 = ReadUint32(readBuffer, categoryRecordOffsets[i] + 1 * uint32_t_size);
1541 const uint32_t categoryRecordWord3 = ReadUint32(readBuffer, categoryRecordOffsets[i] + 2 * uint32_t_size);
1542 CategoryRecord categoryRecord;
1543 categoryRecord.event_count = static_cast<uint16_t>(categoryRecordWord1 >> 16); // event_count
1544 categoryRecord.event_pointer_table_offset = categoryRecordWord2; // event_pointer_table_offset
1545 categoryRecord.name_offset = categoryRecordWord3; // name_offset
1546
1547 uint32_t categoryRecordNameLength = ReadUint32(readBuffer,
1548 categoryRecordOffsets[i] + categoryRecord.name_offset);
1549 categoryRecord.name_length = categoryRecordNameLength; // name_length
1550 unsigned char categoryRecordNameNullTerminator =
1551 ReadUint8(readBuffer,
1552 categoryRecordOffsets[i] +
1553 categoryRecord.name_offset +
1554 uint32_t_size +
1555 categoryRecordNameLength - 1); // name null-terminator
1556 CHECK(categoryRecordNameNullTerminator == '\0');
1557 std::vector<unsigned char> categoryRecordNameBuffer(categoryRecord.name_length - 1);
1558 std::memcpy(categoryRecordNameBuffer.data(),
1559 readData +
1560 categoryRecordOffsets[i] +
1561 categoryRecord.name_offset +
1562 uint32_t_size,
1563 categoryRecordNameBuffer.size());
1564 categoryRecord.name.assign(categoryRecordNameBuffer.begin(), categoryRecordNameBuffer.end()); // name
1565
1566 categoryRecord.event_pointer_table.resize(categoryRecord.event_count);
1567 offset = categoryRecordOffsets[i] + categoryRecord.event_pointer_table_offset;
1568 for (uint32_t eventOffsetIndex = 0; eventOffsetIndex < categoryRecord.event_count; ++eventOffsetIndex)
1569 {
1570 // eventRecordOffset is relative to the start of the event pointer table
1571 categoryRecord.event_pointer_table[eventOffsetIndex] = ReadUint32(readBuffer, offset) +
1572 categoryRecordOffsets[i] +
1573 categoryRecord.event_pointer_table_offset;
1574 offset += uint32_t_size;
1575 }
1576
1577 for (uint32_t eventIndex = 0; eventIndex < categoryRecord.event_count; eventIndex++)
1578 {
1579 const uint32_t eventOffset = categoryRecord.event_pointer_table[eventIndex];
1580 // Collect the data for the event record
1581 const uint32_t eventRecordWord0 = ReadUint32(readBuffer, eventOffset + 0 * uint32_t_size);
1582 const uint32_t eventRecordWord1 = ReadUint32(readBuffer, eventOffset + 1 * uint32_t_size);
1583 const uint32_t eventRecordWord2 = ReadUint32(readBuffer, eventOffset + 2 * uint32_t_size);
1584 const uint64_t eventRecordWord34 = ReadUint64(readBuffer, eventOffset + 3 * uint32_t_size);
1585 const uint32_t eventRecordWord5 = ReadUint32(readBuffer, eventOffset + 5 * uint32_t_size);
1586 const uint32_t eventRecordWord6 = ReadUint32(readBuffer, eventOffset + 6 * uint32_t_size);
1587 const uint32_t eventRecordWord7 = ReadUint32(readBuffer, eventOffset + 7 * uint32_t_size);
1588
1589 EventRecord eventRecord;
1590 eventRecord.counter_uid = static_cast<uint16_t>(eventRecordWord0); // counter_uid
1591 eventRecord.max_counter_uid = static_cast<uint16_t>(eventRecordWord0 >> 16); // max_counter_uid
1592 eventRecord.device = static_cast<uint16_t>(eventRecordWord1 >> 16); // device
1593 eventRecord.counter_set = static_cast<uint16_t>(eventRecordWord1); // counter_set
1594 eventRecord.counter_class = static_cast<uint16_t>(eventRecordWord2 >> 16); // class
1595 eventRecord.interpolation = static_cast<uint16_t>(eventRecordWord2); // interpolation
1596 std::memcpy(&eventRecord.multiplier, &eventRecordWord34, sizeof(eventRecord.multiplier)); // multiplier
1597 eventRecord.name_offset = static_cast<uint32_t>(eventRecordWord5); // name_offset
1598 eventRecord.description_offset = static_cast<uint32_t>(eventRecordWord6); // description_offset
1599 eventRecord.units_offset = static_cast<uint32_t>(eventRecordWord7); // units_offset
1600
1601 uint32_t eventRecordNameLength = ReadUint32(readBuffer, eventOffset + eventRecord.name_offset);
1602 eventRecord.name_length = eventRecordNameLength; // name_length
1603 unsigned char eventRecordNameNullTerminator =
1604 ReadUint8(readBuffer,
1605 eventOffset +
1606 eventRecord.name_offset +
1607 uint32_t_size +
1608 eventRecordNameLength - 1); // name null-terminator
1609 CHECK(eventRecordNameNullTerminator == '\0');
1610 std::vector<unsigned char> eventRecordNameBuffer(eventRecord.name_length - 1);
1611 std::memcpy(eventRecordNameBuffer.data(),
1612 readData +
1613 eventOffset +
1614 eventRecord.name_offset +
1615 uint32_t_size,
1616 eventRecordNameBuffer.size());
1617 eventRecord.name.assign(eventRecordNameBuffer.begin(), eventRecordNameBuffer.end()); // name
1618
1619 uint32_t eventRecordDescriptionLength = ReadUint32(readBuffer,
1620 eventOffset + eventRecord.description_offset);
1621 eventRecord.description_length = eventRecordDescriptionLength; // description_length
1622 unsigned char eventRecordDescriptionNullTerminator =
1623 ReadUint8(readBuffer,
1624 eventOffset +
1625 eventRecord.description_offset +
1626 uint32_t_size +
1627 eventRecordDescriptionLength - 1); // description null-terminator
1628 CHECK(eventRecordDescriptionNullTerminator == '\0');
1629 std::vector<unsigned char> eventRecordDescriptionBuffer(eventRecord.description_length - 1);
1630 std::memcpy(eventRecordDescriptionBuffer.data(),
1631 readData +
1632 eventOffset +
1633 eventRecord.description_offset +
1634 uint32_t_size,
1635 eventRecordDescriptionBuffer.size());
1636 eventRecord.description.assign(eventRecordDescriptionBuffer.begin(),
1637 eventRecordDescriptionBuffer.end()); // description
1638
1639 if (eventRecord.units_offset > 0)
1640 {
1641 uint32_t eventRecordUnitsLength = ReadUint32(readBuffer,
1642 eventOffset + eventRecord.units_offset);
1643 eventRecord.units_length = eventRecordUnitsLength; // units_length
1644 unsigned char eventRecordUnitsNullTerminator =
1645 ReadUint8(readBuffer,
1646 eventOffset +
1647 eventRecord.units_offset +
1648 uint32_t_size +
1649 eventRecordUnitsLength - 1); // units null-terminator
1650 CHECK(eventRecordUnitsNullTerminator == '\0');
1651 std::vector<unsigned char> eventRecordUnitsBuffer(eventRecord.units_length - 1);
1652 std::memcpy(eventRecordUnitsBuffer.data(),
1653 readData +
1654 eventOffset +
1655 eventRecord.units_offset +
1656 uint32_t_size,
1657 eventRecordUnitsBuffer.size());
1658 eventRecord.units.assign(eventRecordUnitsBuffer.begin(), eventRecordUnitsBuffer.end()); // units
1659 }
1660
1661 categoryRecord.event_records.push_back(eventRecord);
1662 }
1663
1664 categoryRecords.push_back(categoryRecord);
1665 }
1666
1667 // Check that the category records are correct
1668 CHECK(categoryRecords.size() == 2);
1669 for (const CategoryRecord& categoryRecord : categoryRecords)
1670 {
1671 const Category* category = counterDirectory.GetCategory(categoryRecord.name);
1672 CHECK(category);
1673 CHECK(category->m_Name == categoryRecord.name);
1674 CHECK(category->m_Counters.size() == categoryRecord.event_count + static_cast<size_t>(numberOfCores) -1);
1675 CHECK(category->m_Counters.size() == categoryRecord.event_count + static_cast<size_t>(numberOfCores) -1);
1676
1677 // Check that the event records are correct
1678 for (const EventRecord& eventRecord : categoryRecord.event_records)
1679 {
1680 const Counter* counter = counterDirectory.GetCounter(eventRecord.counter_uid);
1681 CHECK(counter);
1682 CHECK(counter->m_MaxCounterUid == eventRecord.max_counter_uid);
1683 CHECK(counter->m_DeviceUid == eventRecord.device);
1684 CHECK(counter->m_CounterSetUid == eventRecord.counter_set);
1685 CHECK(counter->m_Class == eventRecord.counter_class);
1686 CHECK(counter->m_Interpolation == eventRecord.interpolation);
1687 CHECK(counter->m_Multiplier == eventRecord.multiplier);
1688 CHECK(counter->m_Name == eventRecord.name);
1689 CHECK(counter->m_Description == eventRecord.description);
1690 CHECK(counter->m_Units == eventRecord.units);
1691 }
1692 }
1693 }
1694
1695 TEST_CASE("SendCounterDirectoryPacketTest3")
1696 {
1697 // Using a mock counter directory that allows to register invalid objects
1698 MockCounterDirectory counterDirectory;
1699
1700 // Register an invalid device
1701 const std::string deviceName = "inv@lid dev!c€";
1702 const Device* device = nullptr;
1703 CHECK_NOTHROW(device = counterDirectory.RegisterDevice(deviceName, 3));
1704 CHECK(counterDirectory.GetDeviceCount() == 1);
1705 CHECK(device);
1706
1707 // Buffer with enough space
1708 MockBufferManager mockBuffer(1024);
1709 SendCounterPacket sendCounterPacket(mockBuffer,
1710 arm::pipe::ARMNN_SOFTWARE_INFO,
1711 arm::pipe::ARMNN_SOFTWARE_VERSION,
1712 arm::pipe::ARMNN_HARDWARE_VERSION);
1713 CHECK_THROWS_AS(sendCounterPacket.SendCounterDirectoryPacket(counterDirectory), arm::pipe::ProfilingException);
1714 }
1715
1716 TEST_CASE("SendCounterDirectoryPacketTest4")
1717 {
1718 // Using a mock counter directory that allows to register invalid objects
1719 MockCounterDirectory counterDirectory;
1720
1721 // Register an invalid counter set
1722 const std::string counterSetName = "inv@lid count€rs€t";
1723 const CounterSet* counterSet = nullptr;
1724 CHECK_NOTHROW(counterSet = counterDirectory.RegisterCounterSet(counterSetName));
1725 CHECK(counterDirectory.GetCounterSetCount() == 1);
1726 CHECK(counterSet);
1727
1728 // Buffer with enough space
1729 MockBufferManager mockBuffer(1024);
1730 SendCounterPacket sendCounterPacket(mockBuffer,
1731 arm::pipe::ARMNN_SOFTWARE_INFO,
1732 arm::pipe::ARMNN_SOFTWARE_VERSION,
1733 arm::pipe::ARMNN_HARDWARE_VERSION);
1734 CHECK_THROWS_AS(sendCounterPacket.SendCounterDirectoryPacket(counterDirectory), arm::pipe::ProfilingException);
1735 }
1736
1737 TEST_CASE("SendCounterDirectoryPacketTest5")
1738 {
1739 // Using a mock counter directory that allows to register invalid objects
1740 MockCounterDirectory counterDirectory;
1741
1742 // Register an invalid category
1743 const std::string categoryName = "c@t€gory";
1744 const Category* category = nullptr;
1745 CHECK_NOTHROW(category = counterDirectory.RegisterCategory(categoryName));
1746 CHECK(counterDirectory.GetCategoryCount() == 1);
1747 CHECK(category);
1748
1749 // Buffer with enough space
1750 MockBufferManager mockBuffer(1024);
1751 SendCounterPacket sendCounterPacket(mockBuffer,
1752 arm::pipe::ARMNN_SOFTWARE_INFO,
1753 arm::pipe::ARMNN_SOFTWARE_VERSION,
1754 arm::pipe::ARMNN_HARDWARE_VERSION);
1755 CHECK_THROWS_AS(sendCounterPacket.SendCounterDirectoryPacket(counterDirectory), arm::pipe::ProfilingException);
1756 }
1757
1758 TEST_CASE("SendCounterDirectoryPacketTest6")
1759 {
1760 // Using a mock counter directory that allows to register invalid objects
1761 MockCounterDirectory counterDirectory;
1762
1763 // Register an invalid device
1764 const std::string deviceName = "inv@lid dev!c€";
1765 const Device* device = nullptr;
1766 CHECK_NOTHROW(device = counterDirectory.RegisterDevice(deviceName, 3));
1767 CHECK(counterDirectory.GetDeviceCount() == 1);
1768 CHECK(device);
1769
1770 // Register an invalid counter set
1771 const std::string counterSetName = "inv@lid count€rs€t";
1772 const CounterSet* counterSet = nullptr;
1773 CHECK_NOTHROW(counterSet = counterDirectory.RegisterCounterSet(counterSetName));
1774 CHECK(counterDirectory.GetCounterSetCount() == 1);
1775 CHECK(counterSet);
1776
1777 // Register an invalid category associated to an invalid device and an invalid counter set
1778 const std::string categoryName = "c@t€gory";
1779 const Category* category = nullptr;
1780 CHECK_NOTHROW(category = counterDirectory.RegisterCategory(categoryName));
1781 CHECK(counterDirectory.GetCategoryCount() == 1);
1782 CHECK(category);
1783
1784 // Buffer with enough space
1785 MockBufferManager mockBuffer(1024);
1786 SendCounterPacket sendCounterPacket(mockBuffer,
1787 arm::pipe::ARMNN_SOFTWARE_INFO,
1788 arm::pipe::ARMNN_SOFTWARE_VERSION,
1789 arm::pipe::ARMNN_HARDWARE_VERSION);
1790 CHECK_THROWS_AS(sendCounterPacket.SendCounterDirectoryPacket(counterDirectory), arm::pipe::ProfilingException);
1791 }
1792
1793 TEST_CASE("SendCounterDirectoryPacketTest7")
1794 {
1795 // Using a mock counter directory that allows to register invalid objects
1796 MockCounterDirectory counterDirectory;
1797
1798 // Register an valid device
1799 const std::string deviceName = "valid device";
1800 const Device* device = nullptr;
1801 CHECK_NOTHROW(device = counterDirectory.RegisterDevice(deviceName, 3));
1802 CHECK(counterDirectory.GetDeviceCount() == 1);
1803 CHECK(device);
1804
1805 // Register an valid counter set
1806 const std::string counterSetName = "valid counterset";
1807 const CounterSet* counterSet = nullptr;
1808 CHECK_NOTHROW(counterSet = counterDirectory.RegisterCounterSet(counterSetName));
1809 CHECK(counterDirectory.GetCounterSetCount() == 1);
1810 CHECK(counterSet);
1811
1812 // Register an valid category associated to a valid device and a valid counter set
1813 const std::string categoryName = "category";
1814 const Category* category = nullptr;
1815 CHECK_NOTHROW(category = counterDirectory.RegisterCategory(categoryName));
1816 CHECK(counterDirectory.GetCategoryCount() == 1);
1817 CHECK(category);
1818
1819 // Register an invalid counter associated to a valid category
1820 const Counter* counter = nullptr;
1821 CHECK_NOTHROW(counter = counterDirectory.RegisterCounter(armnn::profiling::BACKEND_ID,
1822 0,
1823 categoryName,
1824 0,
1825 1,
1826 123.45f,
1827 "counter",
1828 "counter description",
1829 std::string("invalid counter units"),
1830 5,
1831 device->m_Uid,
1832 counterSet->m_Uid));
1833 CHECK(counterDirectory.GetCounterCount() == 5);
1834 CHECK(counter);
1835
1836 // Buffer with enough space
1837 MockBufferManager mockBuffer(1024);
1838 SendCounterPacket sendCounterPacket(mockBuffer,
1839 arm::pipe::ARMNN_SOFTWARE_INFO,
1840 arm::pipe::ARMNN_SOFTWARE_VERSION,
1841 arm::pipe::ARMNN_HARDWARE_VERSION);
1842 CHECK_THROWS_AS(sendCounterPacket.SendCounterDirectoryPacket(counterDirectory), arm::pipe::ProfilingException);
1843 }
1844
1845 TEST_CASE("SendThreadTest0")
1846 {
1847 ProfilingStateMachine profilingStateMachine;
1848 SetActiveProfilingState(profilingStateMachine);
1849
1850 MockProfilingConnection mockProfilingConnection;
1851 MockStreamCounterBuffer mockStreamCounterBuffer(0);
1852 SendCounterPacket sendCounterPacket(mockStreamCounterBuffer,
1853 arm::pipe::ARMNN_SOFTWARE_INFO,
1854 arm::pipe::ARMNN_SOFTWARE_VERSION,
1855 arm::pipe::ARMNN_HARDWARE_VERSION);
1856 SendThread sendThread(profilingStateMachine, mockStreamCounterBuffer, sendCounterPacket);
1857
1858 // Try to start the send thread many times, it must only start once
1859
1860 sendThread.Start(mockProfilingConnection);
1861 CHECK(sendThread.IsRunning());
1862 sendThread.Start(mockProfilingConnection);
1863 sendThread.Start(mockProfilingConnection);
1864 sendThread.Start(mockProfilingConnection);
1865 sendThread.Start(mockProfilingConnection);
1866 CHECK(sendThread.IsRunning());
1867
1868 sendThread.Stop();
1869 CHECK(!sendThread.IsRunning());
1870 }
1871
1872 TEST_CASE("SendThreadTest1")
1873 {
1874 ProfilingStateMachine profilingStateMachine;
1875 SetActiveProfilingState(profilingStateMachine);
1876
1877 unsigned int totalWrittenSize = 0;
1878
1879 MockProfilingConnection mockProfilingConnection;
1880 MockStreamCounterBuffer mockStreamCounterBuffer(1024);
1881 SendCounterPacket sendCounterPacket(mockStreamCounterBuffer,
1882 arm::pipe::ARMNN_SOFTWARE_INFO,
1883 arm::pipe::ARMNN_SOFTWARE_VERSION,
1884 arm::pipe::ARMNN_HARDWARE_VERSION);
1885 SendThread sendThread(profilingStateMachine, mockStreamCounterBuffer, sendCounterPacket);
1886 sendThread.Start(mockProfilingConnection);
1887
1888 // Interleaving writes and reads to/from the buffer with pauses to test that the send thread actually waits for
1889 // something to become available for reading
1890
1891 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
1892
1893 CounterDirectory counterDirectory;
1894 sendCounterPacket.SendStreamMetaDataPacket();
1895
1896 totalWrittenSize += GetStreamMetaDataPacketSize();
1897
1898 sendThread.SetReadyToRead();
1899
1900 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
1901
1902 sendCounterPacket.SendCounterDirectoryPacket(counterDirectory);
1903
1904 // Get the size of the Counter Directory Packet
1905 unsigned int counterDirectoryPacketSize = 32;
1906 totalWrittenSize += counterDirectoryPacketSize;
1907
1908 sendThread.SetReadyToRead();
1909
1910 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
1911
1912 sendCounterPacket.SendPeriodicCounterCapturePacket(123u,
1913 {
1914 { 1u, 23u },
1915 { 33u, 1207623u }
1916 });
1917
1918 // Get the size of the Periodic Counter Capture Packet
1919 unsigned int periodicCounterCapturePacketSize = 28;
1920 totalWrittenSize += periodicCounterCapturePacketSize;
1921
1922 sendThread.SetReadyToRead();
1923
1924 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
1925
1926 sendCounterPacket.SendPeriodicCounterCapturePacket(44u,
1927 {
1928 { 211u, 923u }
1929 });
1930
1931 // Get the size of the Periodic Counter Capture Packet
1932 periodicCounterCapturePacketSize = 22;
1933 totalWrittenSize += periodicCounterCapturePacketSize;
1934
1935 sendCounterPacket.SendPeriodicCounterCapturePacket(1234u,
1936 {
1937 { 555u, 23u },
1938 { 556u, 6u },
1939 { 557u, 893454u },
1940 { 558u, 1456623u },
1941 { 559u, 571090u }
1942 });
1943
1944 // Get the size of the Periodic Counter Capture Packet
1945 periodicCounterCapturePacketSize = 46;
1946 totalWrittenSize += periodicCounterCapturePacketSize;
1947
1948 sendCounterPacket.SendPeriodicCounterCapturePacket(997u,
1949 {
1950 { 88u, 11u },
1951 { 96u, 22u },
1952 { 97u, 33u },
1953 { 999u, 444u }
1954 });
1955
1956 // Get the size of the Periodic Counter Capture Packet
1957 periodicCounterCapturePacketSize = 40;
1958 totalWrittenSize += periodicCounterCapturePacketSize;
1959
1960 sendThread.SetReadyToRead();
1961
1962 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
1963
1964 sendCounterPacket.SendPeriodicCounterSelectionPacket(1000u, { 1345u, 254u, 4536u, 408u, 54u, 6323u, 428u, 1u, 6u });
1965
1966 // Get the size of the Periodic Counter Capture Packet
1967 periodicCounterCapturePacketSize = 30;
1968 totalWrittenSize += periodicCounterCapturePacketSize;
1969
1970 sendThread.SetReadyToRead();
1971
1972 // To test an exact value of the "read size" in the mock buffer, wait to allow the send thread to
1973 // read all what's remaining in the buffer
1974 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
1975
1976 sendThread.Stop();
1977
1978 CHECK(mockStreamCounterBuffer.GetCommittedSize() == totalWrittenSize);
1979 CHECK(mockStreamCounterBuffer.GetReadableSize() == totalWrittenSize);
1980 CHECK(mockStreamCounterBuffer.GetReadSize() == totalWrittenSize);
1981 }
1982
1983 TEST_CASE("SendThreadTest2")
1984 {
1985 ProfilingStateMachine profilingStateMachine;
1986 SetActiveProfilingState(profilingStateMachine);
1987
1988 unsigned int totalWrittenSize = 0;
1989
1990 MockProfilingConnection mockProfilingConnection;
1991 MockStreamCounterBuffer mockStreamCounterBuffer(1024);
1992 SendCounterPacket sendCounterPacket(mockStreamCounterBuffer,
1993 arm::pipe::ARMNN_SOFTWARE_INFO,
1994 arm::pipe::ARMNN_SOFTWARE_VERSION,
1995 arm::pipe::ARMNN_HARDWARE_VERSION);
1996 SendThread sendThread(profilingStateMachine, mockStreamCounterBuffer, sendCounterPacket);
1997 sendThread.Start(mockProfilingConnection);
1998
1999 // Adding many spurious "ready to read" signals throughout the test to check that the send thread is
2000 // capable of handling unnecessary read requests
2001
2002 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
2003
2004 sendThread.SetReadyToRead();
2005
2006 CounterDirectory counterDirectory;
2007 sendCounterPacket.SendStreamMetaDataPacket();
2008
2009 totalWrittenSize += GetStreamMetaDataPacketSize();
2010
2011 sendThread.SetReadyToRead();
2012
2013 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
2014
2015 sendCounterPacket.SendCounterDirectoryPacket(counterDirectory);
2016
2017 // Get the size of the Counter Directory Packet
2018 unsigned int counterDirectoryPacketSize = 32;
2019 totalWrittenSize += counterDirectoryPacketSize;
2020
2021 sendThread.SetReadyToRead();
2022 sendThread.SetReadyToRead();
2023
2024 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
2025
2026 sendCounterPacket.SendPeriodicCounterCapturePacket(123u,
2027 {
2028 { 1u, 23u },
2029 { 33u, 1207623u }
2030 });
2031
2032 // Get the size of the Periodic Counter Capture Packet
2033 unsigned int periodicCounterCapturePacketSize = 28;
2034 totalWrittenSize += periodicCounterCapturePacketSize;
2035
2036 sendThread.SetReadyToRead();
2037
2038 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
2039
2040 sendThread.SetReadyToRead();
2041 sendThread.SetReadyToRead();
2042 sendThread.SetReadyToRead();
2043
2044 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
2045
2046 sendThread.SetReadyToRead();
2047 sendCounterPacket.SendPeriodicCounterCapturePacket(44u,
2048 {
2049 { 211u, 923u }
2050 });
2051
2052 // Get the size of the Periodic Counter Capture Packet
2053 periodicCounterCapturePacketSize = 22;
2054 totalWrittenSize += periodicCounterCapturePacketSize;
2055
2056 sendCounterPacket.SendPeriodicCounterCapturePacket(1234u,
2057 {
2058 { 555u, 23u },
2059 { 556u, 6u },
2060 { 557u, 893454u },
2061 { 558u, 1456623u },
2062 { 559u, 571090u }
2063 });
2064
2065 // Get the size of the Periodic Counter Capture Packet
2066 periodicCounterCapturePacketSize = 46;
2067 totalWrittenSize += periodicCounterCapturePacketSize;
2068
2069 sendThread.SetReadyToRead();
2070 sendCounterPacket.SendPeriodicCounterCapturePacket(997u,
2071 {
2072 { 88u, 11u },
2073 { 96u, 22u },
2074 { 97u, 33u },
2075 { 999u, 444u }
2076 });
2077
2078 // Get the size of the Periodic Counter Capture Packet
2079 periodicCounterCapturePacketSize = 40;
2080 totalWrittenSize += periodicCounterCapturePacketSize;
2081
2082 sendThread.SetReadyToRead();
2083 sendThread.SetReadyToRead();
2084
2085 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_UNTIL_READABLE_MS));
2086
2087 sendCounterPacket.SendPeriodicCounterSelectionPacket(1000u, { 1345u, 254u, 4536u, 408u, 54u, 6323u, 428u, 1u, 6u });
2088
2089 // Get the size of the Periodic Counter Capture Packet
2090 periodicCounterCapturePacketSize = 30;
2091 totalWrittenSize += periodicCounterCapturePacketSize;
2092
2093 sendThread.SetReadyToRead();
2094
2095 // To test an exact value of the "read size" in the mock buffer, wait to allow the send thread to
2096 // read all what's remaining in the buffer
2097 sendThread.Stop();
2098
2099 CHECK(mockStreamCounterBuffer.GetCommittedSize() == totalWrittenSize);
2100 CHECK(mockStreamCounterBuffer.GetReadableSize() == totalWrittenSize);
2101 CHECK(mockStreamCounterBuffer.GetReadSize() == totalWrittenSize);
2102 }
2103
2104 TEST_CASE("SendThreadTest3")
2105 {
2106 ProfilingStateMachine profilingStateMachine;
2107 SetActiveProfilingState(profilingStateMachine);
2108
2109 unsigned int totalWrittenSize = 0;
2110
2111 MockProfilingConnection mockProfilingConnection;
2112 MockStreamCounterBuffer mockStreamCounterBuffer(1024);
2113 SendCounterPacket sendCounterPacket(mockStreamCounterBuffer,
2114 arm::pipe::ARMNN_SOFTWARE_INFO,
2115 arm::pipe::ARMNN_SOFTWARE_VERSION,
2116 arm::pipe::ARMNN_HARDWARE_VERSION);
2117 SendThread sendThread(profilingStateMachine, mockStreamCounterBuffer, sendCounterPacket);
2118 sendThread.Start(mockProfilingConnection);
2119
2120 // Not using pauses or "grace periods" to stress test the send thread
2121
2122 sendThread.SetReadyToRead();
2123
2124 CounterDirectory counterDirectory;
2125 sendCounterPacket.SendStreamMetaDataPacket();
2126
2127 totalWrittenSize += GetStreamMetaDataPacketSize();
2128
2129 sendThread.SetReadyToRead();
2130 sendCounterPacket.SendCounterDirectoryPacket(counterDirectory);
2131
2132 // Get the size of the Counter Directory Packet
2133 unsigned int counterDirectoryPacketSize =32;
2134 totalWrittenSize += counterDirectoryPacketSize;
2135
2136 sendThread.SetReadyToRead();
2137 sendThread.SetReadyToRead();
2138 sendCounterPacket.SendPeriodicCounterCapturePacket(123u,
2139 {
2140 { 1u, 23u },
2141 { 33u, 1207623u }
2142 });
2143
2144 // Get the size of the Periodic Counter Capture Packet
2145 unsigned int periodicCounterCapturePacketSize = 28;
2146 totalWrittenSize += periodicCounterCapturePacketSize;
2147
2148 sendThread.SetReadyToRead();
2149 sendThread.SetReadyToRead();
2150 sendThread.SetReadyToRead();
2151 sendThread.SetReadyToRead();
2152 sendThread.SetReadyToRead();
2153 sendCounterPacket.SendPeriodicCounterCapturePacket(44u,
2154 {
2155 { 211u, 923u }
2156 });
2157
2158 // Get the size of the Periodic Counter Capture Packet
2159 periodicCounterCapturePacketSize = 22;
2160 totalWrittenSize += periodicCounterCapturePacketSize;
2161
2162 sendCounterPacket.SendPeriodicCounterCapturePacket(1234u,
2163 {
2164 { 555u, 23u },
2165 { 556u, 6u },
2166 { 557u, 893454u },
2167 { 558u, 1456623u },
2168 { 559u, 571090u }
2169 });
2170
2171 // Get the size of the Periodic Counter Capture Packet
2172 periodicCounterCapturePacketSize = 46;
2173 totalWrittenSize += periodicCounterCapturePacketSize;
2174
2175 sendThread.SetReadyToRead();
2176 sendThread.SetReadyToRead();
2177 sendCounterPacket.SendPeriodicCounterCapturePacket(997u,
2178 {
2179 { 88u, 11u },
2180 { 96u, 22u },
2181 { 97u, 33u },
2182 { 999u, 444u }
2183 });
2184
2185 // Get the size of the Periodic Counter Capture Packet
2186 periodicCounterCapturePacketSize = 40;
2187 totalWrittenSize += periodicCounterCapturePacketSize;
2188
2189 sendThread.SetReadyToRead();
2190 sendThread.SetReadyToRead();
2191 sendCounterPacket.SendPeriodicCounterSelectionPacket(1000u, { 1345u, 254u, 4536u, 408u, 54u, 6323u, 428u, 1u, 6u });
2192
2193 // Get the size of the Periodic Counter Capture Packet
2194 periodicCounterCapturePacketSize = 30;
2195 totalWrittenSize += periodicCounterCapturePacketSize;
2196
2197 sendThread.SetReadyToRead();
2198
2199 // Abruptly terminating the send thread, the amount of data sent may be less that the amount written (the send
2200 // thread is not guaranteed to flush the buffer)
2201 sendThread.Stop();
2202
2203 CHECK(mockStreamCounterBuffer.GetCommittedSize() == totalWrittenSize);
2204 CHECK(mockStreamCounterBuffer.GetReadableSize() <= totalWrittenSize);
2205 CHECK(mockStreamCounterBuffer.GetReadSize() <= totalWrittenSize);
2206 CHECK(mockStreamCounterBuffer.GetReadSize() <= mockStreamCounterBuffer.GetReadableSize());
2207 CHECK(mockStreamCounterBuffer.GetReadSize() <= mockStreamCounterBuffer.GetCommittedSize());
2208 }
2209
2210 TEST_CASE("SendCounterPacketTestWithSendThread")
2211 {
2212 ProfilingStateMachine profilingStateMachine;
2213 SetWaitingForAckProfilingState(profilingStateMachine);
2214
2215 MockProfilingConnection mockProfilingConnection;
2216 BufferManager bufferManager(1, 1024);
2217 SendCounterPacket sendCounterPacket(bufferManager,
2218 arm::pipe::ARMNN_SOFTWARE_INFO,
2219 arm::pipe::ARMNN_SOFTWARE_VERSION,
2220 arm::pipe::ARMNN_HARDWARE_VERSION);
2221 SendThread sendThread(profilingStateMachine, bufferManager, sendCounterPacket, -1);
2222 sendThread.Start(mockProfilingConnection);
2223
2224 unsigned int streamMetadataPacketsize = GetStreamMetaDataPacketSize();
2225
2226 sendThread.Stop();
2227
2228 // check for packet in ProfilingConnection
2229 CHECK(mockProfilingConnection.CheckForPacket({PacketType::StreamMetaData, streamMetadataPacketsize}) == 1);
2230
2231 SetActiveProfilingState(profilingStateMachine);
2232 sendThread.Start(mockProfilingConnection);
2233
2234 // SendCounterDirectoryPacket
2235 CounterDirectory counterDirectory;
2236 sendCounterPacket.SendCounterDirectoryPacket(counterDirectory);
2237
2238 sendThread.Stop();
2239 unsigned int counterDirectoryPacketSize = 32;
2240 // check for packet in ProfilingConnection
2241 CHECK(mockProfilingConnection.CheckForPacket(
2242 {PacketType::CounterDirectory, counterDirectoryPacketSize}) == 1);
2243
2244 sendThread.Start(mockProfilingConnection);
2245
2246 // SendPeriodicCounterCapturePacket
2247 sendCounterPacket.SendPeriodicCounterCapturePacket(123u,
2248 {
2249 { 1u, 23u },
2250 { 33u, 1207623u }
2251 });
2252
2253 sendThread.Stop();
2254
2255 unsigned int periodicCounterCapturePacketSize = 28;
2256 CHECK(mockProfilingConnection.CheckForPacket(
2257 {PacketType::PeriodicCounterCapture, periodicCounterCapturePacketSize}) == 1);
2258 }
2259
2260 TEST_CASE("SendThreadBufferTest")
2261 {
2262 ProfilingStateMachine profilingStateMachine;
2263 SetActiveProfilingState(profilingStateMachine);
2264
2265 MockProfilingConnection mockProfilingConnection;
2266 BufferManager bufferManager(3, 1024);
2267 SendCounterPacket sendCounterPacket(bufferManager,
2268 arm::pipe::ARMNN_SOFTWARE_INFO,
2269 arm::pipe::ARMNN_SOFTWARE_VERSION,
2270 arm::pipe::ARMNN_HARDWARE_VERSION);
2271 SendThread sendThread(profilingStateMachine, bufferManager, sendCounterPacket, -1);
2272 sendThread.Start(mockProfilingConnection);
2273
2274 // SendStreamMetaDataPacket
2275 sendCounterPacket.SendStreamMetaDataPacket();
2276
2277 // Read data from the buffer
2278 // Buffer should become readable after commit by SendStreamMetaDataPacket
2279 auto packetBuffer = bufferManager.GetReadableBuffer();
2280 CHECK(packetBuffer.get());
2281
2282 unsigned int streamMetadataPacketsize = GetStreamMetaDataPacketSize();
2283 CHECK(packetBuffer->GetSize() == streamMetadataPacketsize);
2284
2285 // Recommit to be read by sendCounterPacket
2286 bufferManager.Commit(packetBuffer, streamMetadataPacketsize);
2287
2288 // SendCounterDirectoryPacket
2289 CounterDirectory counterDirectory;
2290 sendCounterPacket.SendCounterDirectoryPacket(counterDirectory);
2291
2292 // SendPeriodicCounterCapturePacket
2293 sendCounterPacket.SendPeriodicCounterCapturePacket(123u,
2294 {
2295 { 1u, 23u },
2296 { 33u, 1207623u }
2297 });
2298
2299 sendThread.Stop();
2300
2301 // The buffer is read by the send thread so it should not be in the readable buffer.
2302 auto readBuffer = bufferManager.GetReadableBuffer();
2303 CHECK(!readBuffer);
2304
2305 // Successfully reserved the buffer with requested size
2306 unsigned int reservedSize = 0;
2307 auto reservedBuffer = bufferManager.Reserve(512, reservedSize);
2308 CHECK(reservedSize == 512);
2309 CHECK(reservedBuffer.get());
2310
2311 const auto writtenDataSize = mockProfilingConnection.GetWrittenDataSize();
2312 const auto metaDataPacketCount =
2313 mockProfilingConnection.CheckForPacket({PacketType::StreamMetaData, streamMetadataPacketsize});
2314
2315 CHECK(metaDataPacketCount >= 1);
2316 CHECK(mockProfilingConnection.CheckForPacket({PacketType::CounterDirectory, 32}) == 1);
2317 CHECK(mockProfilingConnection.CheckForPacket({PacketType::PeriodicCounterCapture, 28}) == 1);
2318 // Check that we only received the packets we expected
2319 CHECK(metaDataPacketCount + 2 == writtenDataSize);
2320 }
2321
2322 TEST_CASE("SendThreadSendStreamMetadataPacket1")
2323 {
2324 ProfilingStateMachine profilingStateMachine;
2325
2326 MockProfilingConnection mockProfilingConnection;
2327 BufferManager bufferManager(3, 1024);
2328 SendCounterPacket sendCounterPacket(bufferManager,
2329 arm::pipe::ARMNN_SOFTWARE_INFO,
2330 arm::pipe::ARMNN_SOFTWARE_VERSION,
2331 arm::pipe::ARMNN_HARDWARE_VERSION);
2332 SendThread sendThread(profilingStateMachine, bufferManager, sendCounterPacket);
2333 sendThread.Start(mockProfilingConnection);
2334
2335 // The profiling state is set to "Uninitialized", so the send thread should throw an exception
2336 CHECK_THROWS_AS(sendThread.Stop(), arm::pipe::ProfilingException);
2337 }
2338
2339 TEST_CASE("SendThreadSendStreamMetadataPacket2")
2340 {
2341 ProfilingStateMachine profilingStateMachine;
2342 SetNotConnectedProfilingState(profilingStateMachine);
2343
2344 MockProfilingConnection mockProfilingConnection;
2345 BufferManager bufferManager(3, 1024);
2346 SendCounterPacket sendCounterPacket(bufferManager,
2347 arm::pipe::ARMNN_SOFTWARE_INFO,
2348 arm::pipe::ARMNN_SOFTWARE_VERSION,
2349 arm::pipe::ARMNN_HARDWARE_VERSION);
2350 SendThread sendThread(profilingStateMachine, bufferManager, sendCounterPacket);
2351 sendThread.Start(mockProfilingConnection);
2352
2353 // The profiling state is set to "NotConnected", so the send thread should throw an exception
2354 CHECK_THROWS_AS(sendThread.Stop(), arm::pipe::ProfilingException);
2355 }
2356
2357 TEST_CASE("SendThreadSendStreamMetadataPacket3")
2358 {
2359 ProfilingStateMachine profilingStateMachine;
2360 SetWaitingForAckProfilingState(profilingStateMachine);
2361
2362 unsigned int streamMetadataPacketsize = GetStreamMetaDataPacketSize();
2363
2364 MockProfilingConnection mockProfilingConnection;
2365 BufferManager bufferManager(3, 1024);
2366 SendCounterPacket sendCounterPacket(bufferManager,
2367 arm::pipe::ARMNN_SOFTWARE_INFO,
2368 arm::pipe::ARMNN_SOFTWARE_VERSION,
2369 arm::pipe::ARMNN_HARDWARE_VERSION);
2370 SendThread sendThread(profilingStateMachine, bufferManager, sendCounterPacket);
2371 sendThread.Start(mockProfilingConnection);
2372
2373 // The profiling state is set to "WaitingForAck", so the send thread should send a Stream Metadata packet
2374 // Wait for sendThread to join
2375 CHECK_NOTHROW(sendThread.Stop());
2376
2377 // Check that the buffer contains at least one Stream Metadata packet and no other packets
2378 const auto writtenDataSize = mockProfilingConnection.GetWrittenDataSize();
2379
2380 CHECK(writtenDataSize >= 1u);
2381 CHECK(mockProfilingConnection.CheckForPacket(
2382 {PacketType::StreamMetaData, streamMetadataPacketsize}) == writtenDataSize);
2383 }
2384
2385 TEST_CASE("SendThreadSendStreamMetadataPacket4")
2386 {
2387 ProfilingStateMachine profilingStateMachine;
2388 SetWaitingForAckProfilingState(profilingStateMachine);
2389
2390 unsigned int streamMetadataPacketsize = GetStreamMetaDataPacketSize();
2391
2392 MockProfilingConnection mockProfilingConnection;
2393 BufferManager bufferManager(3, 1024);
2394 SendCounterPacket sendCounterPacket(bufferManager,
2395 arm::pipe::ARMNN_SOFTWARE_INFO,
2396 arm::pipe::ARMNN_SOFTWARE_VERSION,
2397 arm::pipe::ARMNN_HARDWARE_VERSION);
2398 SendThread sendThread(profilingStateMachine, bufferManager, sendCounterPacket);
2399 sendThread.Start(mockProfilingConnection);
2400
2401 // The profiling state is set to "WaitingForAck", so the send thread should send a Stream Metadata packet
2402 // Wait for sendThread to join
2403 sendThread.Stop();
2404
2405 sendThread.Start(mockProfilingConnection);
2406 // Check that the profiling state is still "WaitingForAck"
2407 CHECK((profilingStateMachine.GetCurrentState() == ProfilingState::WaitingForAck));
2408
2409 // Check that the buffer contains at least one Stream Metadata packet
2410 CHECK(mockProfilingConnection.CheckForPacket({PacketType::StreamMetaData, streamMetadataPacketsize}) >= 1);
2411
2412 mockProfilingConnection.Clear();
2413
2414 sendThread.Stop();
2415 sendThread.Start(mockProfilingConnection);
2416
2417 // Try triggering a new buffer read
2418 sendThread.SetReadyToRead();
2419
2420 // Wait for sendThread to join
2421 CHECK_NOTHROW(sendThread.Stop());
2422
2423 // Check that the profiling state is still "WaitingForAck"
2424 CHECK((profilingStateMachine.GetCurrentState() == ProfilingState::WaitingForAck));
2425
2426 // Check that the buffer contains at least one Stream Metadata packet and no other packets
2427 const auto writtenDataSize = mockProfilingConnection.GetWrittenDataSize();
2428
2429 CHECK(writtenDataSize >= 1u);
2430 CHECK(mockProfilingConnection.CheckForPacket(
2431 {PacketType::StreamMetaData, streamMetadataPacketsize}) == writtenDataSize);
2432 }
2433
2434 }
2435