xref: /aosp_15_r20/external/armnn/tests/profiling/gatordmock/tests/GatordMockTests.cpp (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
1 //
2 // Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include <ArmNNProfilingServiceInitialiser.hpp>
7 #include <GatordMockService.hpp>
8 #include <Runtime.hpp>
9 #include <armnnTestUtils/MockBackend.hpp>
10 
11 #include <client/src/ProfilingService.hpp>
12 #include <client/src/TimelinePacketWriterFactory.hpp>
13 
14 #include <armnn/profiling/ArmNNProfiling.hpp>
15 
16 #include <common/include/LabelsAndEventClasses.hpp>
17 #include <common/include/CommandHandlerRegistry.hpp>
18 
19 #include <armnn/utility/Assert.hpp>
20 #include <armnn/utility/NumericCast.hpp>
21 
22 #include <server/include/timelineDecoder/TimelineDirectoryCaptureCommandHandler.hpp>
23 #include <server/include/timelineDecoder/TimelineDecoder.hpp>
24 #include <server/include/basePipeServer/ConnectionHandler.hpp>
25 
26 #include <doctest/doctest.h>
27 
28 TEST_SUITE("GatordMockTests")
29 {
30 using namespace armnn;
31 using namespace std::this_thread;
32 using namespace std::chrono_literals;
33 
34 TEST_CASE("CounterCaptureHandlingTest")
35 {
36     arm::pipe::PacketVersionResolver packetVersionResolver;
37 
38     // Data with timestamp, counter idx & counter values
39     std::vector<std::pair<uint16_t, uint32_t>> indexValuePairs;
40     indexValuePairs.reserve(5);
41     indexValuePairs.emplace_back(std::make_pair<uint16_t, uint32_t>(0, 100));
42     indexValuePairs.emplace_back(std::make_pair<uint16_t, uint32_t>(1, 200));
43     indexValuePairs.emplace_back(std::make_pair<uint16_t, uint32_t>(2, 300));
44     indexValuePairs.emplace_back(std::make_pair<uint16_t, uint32_t>(3, 400));
45     indexValuePairs.emplace_back(std::make_pair<uint16_t, uint32_t>(4, 500));
46 
47     // ((uint16_t (2 bytes) + uint32_t (4 bytes)) * 5) + word1 + word2
48     uint32_t dataLength = 38;
49 
50     // Simulate two different packets incoming 500 ms apart
51     uint64_t time = static_cast<uint64_t>(
52         std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now().time_since_epoch())
53             .count());
54 
55     uint64_t time2 = time + 5000;
56 
57     // UniqueData required for Packet class
58     std::unique_ptr<unsigned char[]> uniqueData1 = std::make_unique<unsigned char[]>(dataLength);
59     unsigned char* data1                         = reinterpret_cast<unsigned char*>(uniqueData1.get());
60 
61     std::unique_ptr<unsigned char[]> uniqueData2 = std::make_unique<unsigned char[]>(dataLength);
62     unsigned char* data2                         = reinterpret_cast<unsigned char*>(uniqueData2.get());
63 
64     uint32_t sizeOfUint64 = armnn::numeric_cast<uint32_t>(sizeof(uint64_t));
65     uint32_t sizeOfUint32 = armnn::numeric_cast<uint32_t>(sizeof(uint32_t));
66     uint32_t sizeOfUint16 = armnn::numeric_cast<uint32_t>(sizeof(uint16_t));
67     // Offset index to point to mem address
68     uint32_t offset = 0;
69 
70     arm::pipe::WriteUint64(data1, offset, time);
71     offset += sizeOfUint64;
72     for (const auto& pair : indexValuePairs)
73     {
74         arm::pipe::WriteUint16(data1, offset, pair.first);
75         offset += sizeOfUint16;
76         arm::pipe::WriteUint32(data1, offset, pair.second);
77         offset += sizeOfUint32;
78     }
79 
80     offset = 0;
81 
82     arm::pipe::WriteUint64(data2, offset, time2);
83     offset += sizeOfUint64;
84     for (const auto& pair : indexValuePairs)
85     {
86         arm::pipe::WriteUint16(data2, offset, pair.first);
87         offset += sizeOfUint16;
88         arm::pipe::WriteUint32(data2, offset, pair.second);
89         offset += sizeOfUint32;
90     }
91 
92     uint32_t headerWord1 = packetVersionResolver.ResolvePacketVersion(0, 4).GetEncodedValue();
93     // Create packet to send through to the command functor
94     arm::pipe::Packet packet1(headerWord1, dataLength, uniqueData1);
95     arm::pipe::Packet packet2(headerWord1, dataLength, uniqueData2);
96 
97     gatordmock::PeriodicCounterCaptureCommandHandler commandHandler(0, 4, headerWord1, true);
98 
99     // Simulate two separate packets coming in to calculate period
100     commandHandler(packet1);
101     commandHandler(packet2);
102 
103     ARMNN_ASSERT(commandHandler.m_CurrentPeriodValue == 5000);
104 
105     for (size_t i = 0; i < commandHandler.m_CounterCaptureValues.m_Uids.size(); ++i)
106     {
107         ARMNN_ASSERT(commandHandler.m_CounterCaptureValues.m_Uids[i] == i);
108     }
109 }
110 
WaitFor(std::function<bool ()> predicate,std::string errorMsg,uint32_t timeout=2000,uint32_t sleepTime=50)111 void WaitFor(std::function<bool()> predicate, std::string errorMsg, uint32_t timeout = 2000, uint32_t sleepTime = 50)
112 {
113     uint32_t timeSlept = 0;
114     while (!predicate())
115     {
116         if (timeSlept >= timeout)
117         {
118             FAIL("Timeout: " << errorMsg);
119         }
120         std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
121         timeSlept += sleepTime;
122     }
123 }
124 
CheckTimelineDirectory(arm::pipe::TimelineDirectoryCaptureCommandHandler & commandHandler)125 void CheckTimelineDirectory(arm::pipe::TimelineDirectoryCaptureCommandHandler& commandHandler)
126 {
127     uint32_t uint8_t_size  = sizeof(uint8_t);
128     uint32_t uint32_t_size = sizeof(uint32_t);
129     uint32_t uint64_t_size = sizeof(uint64_t);
130     uint32_t threadId_size = sizeof(int);
131 
132     arm::pipe::BufferManager bufferManager(5);
133     arm::pipe::TimelinePacketWriterFactory timelinePacketWriterFactory(bufferManager);
134 
135     std::unique_ptr<arm::pipe::ISendTimelinePacket> sendTimelinePacket =
136             timelinePacketWriterFactory.GetSendTimelinePacket();
137 
138     sendTimelinePacket->SendTimelineMessageDirectoryPackage();
139     sendTimelinePacket->Commit();
140 
141     std::vector<arm::pipe::SwTraceMessage> swTraceBufferMessages;
142 
143     unsigned int offset = uint32_t_size * 2;
144 
145     std::unique_ptr<arm::pipe::IPacketBuffer> packetBuffer = bufferManager.GetReadableBuffer();
146 
147     uint8_t readStreamVersion = ReadUint8(packetBuffer, offset);
148     CHECK(readStreamVersion == 4);
149     offset += uint8_t_size;
150     uint8_t readPointerBytes = ReadUint8(packetBuffer, offset);
151     CHECK(readPointerBytes == uint64_t_size);
152     offset += uint8_t_size;
153     uint8_t readThreadIdBytes = ReadUint8(packetBuffer, offset);
154     CHECK(readThreadIdBytes == threadId_size);
155     offset += uint8_t_size;
156 
157     uint32_t declarationSize = arm::pipe::ReadUint32(packetBuffer, offset);
158     offset += uint32_t_size;
159     for(uint32_t i = 0; i < declarationSize; ++i)
160     {
161         swTraceBufferMessages.push_back(arm::pipe::ReadSwTraceMessage(packetBuffer->GetReadableData(),
162                                                                       offset,
163                                                                       packetBuffer->GetSize()));
164     }
165 
166     for(uint32_t index = 0; index < declarationSize; ++index)
167     {
168         arm::pipe::SwTraceMessage& bufferMessage = swTraceBufferMessages[index];
169         arm::pipe::SwTraceMessage& handlerMessage = commandHandler.m_SwTraceMessages[index];
170 
171         CHECK(bufferMessage.m_Name == handlerMessage.m_Name);
172         CHECK(bufferMessage.m_UiName == handlerMessage.m_UiName);
173         CHECK(bufferMessage.m_Id == handlerMessage.m_Id);
174 
175         CHECK(bufferMessage.m_ArgTypes.size() == handlerMessage.m_ArgTypes.size());
176         for(uint32_t i = 0; i < bufferMessage.m_ArgTypes.size(); ++i)
177         {
178             CHECK(bufferMessage.m_ArgTypes[i] == handlerMessage.m_ArgTypes[i]);
179         }
180 
181         CHECK(bufferMessage.m_ArgNames.size() == handlerMessage.m_ArgNames.size());
182         for(uint32_t i = 0; i < bufferMessage.m_ArgNames.size(); ++i)
183         {
184             CHECK(bufferMessage.m_ArgNames[i] == handlerMessage.m_ArgNames[i]);
185         }
186     }
187 }
188 
CheckTimelinePackets(arm::pipe::TimelineDecoder & timelineDecoder)189 void CheckTimelinePackets(arm::pipe::TimelineDecoder& timelineDecoder)
190 {
191     unsigned int i = 0; // Use a postfix increment to avoid changing indexes each time the packet gets updated.
192     timelineDecoder.ApplyToModel([&](arm::pipe::TimelineDecoder::Model& m) {
193         CHECK(m.m_Labels[i].m_Guid == arm::pipe::LabelsAndEventClasses::NAME_GUID);
194         CHECK(m.m_Labels[i++].m_Name == arm::pipe::LabelsAndEventClasses::NAME_LABEL);
195 
196         CHECK(m.m_Labels[i].m_Guid == arm::pipe::LabelsAndEventClasses::TYPE_GUID);
197         CHECK(m.m_Labels[i++].m_Name == arm::pipe::LabelsAndEventClasses::TYPE_LABEL);
198 
199         CHECK(m.m_Labels[i].m_Guid == arm::pipe::LabelsAndEventClasses::INDEX_GUID);
200         CHECK(m.m_Labels[i++].m_Name == arm::pipe::LabelsAndEventClasses::INDEX_LABEL);
201 
202         CHECK(m.m_Labels[i].m_Guid == arm::pipe::LabelsAndEventClasses::BACKENDID_GUID);
203         CHECK(m.m_Labels[i++].m_Name == arm::pipe::LabelsAndEventClasses::BACKENDID_LABEL);
204 
205         CHECK(m.m_Labels[i].m_Guid == arm::pipe::LabelsAndEventClasses::CHILD_GUID);
206         CHECK(m.m_Labels[i++].m_Name == arm::pipe::LabelsAndEventClasses::CHILD_LABEL);
207 
208         CHECK(m.m_Labels[i].m_Guid == arm::pipe::LabelsAndEventClasses::EXECUTION_OF_GUID);
209         CHECK(m.m_Labels[i++].m_Name ==
210                     arm::pipe::LabelsAndEventClasses::EXECUTION_OF_LABEL);
211 
212         CHECK(m.m_Labels[i].m_Guid == arm::pipe::LabelsAndEventClasses::PROCESS_ID_GUID);
213         CHECK(m.m_Labels[i++].m_Name ==
214                     arm::pipe::LabelsAndEventClasses::PROCESS_ID_LABEL);
215 
216         CHECK(m.m_Labels[i].m_Guid == arm::pipe::LabelsAndEventClasses::LAYER_GUID);
217         CHECK(m.m_Labels[i++].m_Name == arm::pipe::LabelsAndEventClasses::LAYER);
218 
219         CHECK(m.m_Labels[i].m_Guid == arm::pipe::LabelsAndEventClasses::WORKLOAD_GUID);
220         CHECK(m.m_Labels[i++].m_Name == arm::pipe::LabelsAndEventClasses::WORKLOAD);
221 
222         CHECK(m.m_Labels[i].m_Guid == arm::pipe::LabelsAndEventClasses::NETWORK_GUID);
223         CHECK(m.m_Labels[i++].m_Name == arm::pipe::LabelsAndEventClasses::NETWORK);
224 
225         CHECK(m.m_Labels[i].m_Guid == arm::pipe::LabelsAndEventClasses::CONNECTION_GUID);
226         CHECK(m.m_Labels[i++].m_Name == arm::pipe::LabelsAndEventClasses::CONNECTION);
227 
228         CHECK(m.m_Labels[i].m_Guid == arm::pipe::LabelsAndEventClasses::INFERENCE_GUID);
229         CHECK(m.m_Labels[i++].m_Name == arm::pipe::LabelsAndEventClasses::INFERENCE);
230 
231         CHECK(m.m_Labels[i].m_Guid ==
232                     arm::pipe::LabelsAndEventClasses::WORKLOAD_EXECUTION_GUID);
233         CHECK(m.m_Labels[i++].m_Name ==
234                     arm::pipe::LabelsAndEventClasses::WORKLOAD_EXECUTION);
235 
236         CHECK(m.m_EventClasses[0].m_Guid ==
237                     arm::pipe::LabelsAndEventClasses::ARMNN_PROFILING_SOL_EVENT_CLASS);
238         CHECK(m.m_EventClasses[1].m_Guid ==
239                     arm::pipe::LabelsAndEventClasses::ARMNN_PROFILING_EOL_EVENT_CLASS);
240     });
241 }
242 
243 TEST_CASE("GatorDMockEndToEnd")
244 {
245     // The purpose of this test is to setup both sides of the profiling service and get to the point of receiving
246     // performance data.
247 
248     // Setup the mock service to bind to the UDS.
249     std::string udsNamespace = "gatord_namespace";
250 
251     CHECK_NOTHROW(arm::pipe::ConnectionHandler connectionHandler(udsNamespace, false));
252 
253     arm::pipe::ConnectionHandler connectionHandler(udsNamespace, false);
254 
255     // Enable the profiling service.
256     arm::pipe::ProfilingOptions options;
257     options.m_EnableProfiling = true;
258     options.m_TimelineEnabled = true;
259 
260     armnn::ArmNNProfilingServiceInitialiser initialiser;
261     arm::pipe::ProfilingService profilingService(arm::pipe::MAX_ARMNN_COUNTER,
262                                                  initialiser,
263                                                  arm::pipe::ARMNN_SOFTWARE_INFO,
264                                                  arm::pipe::ARMNN_SOFTWARE_VERSION,
265                                                  arm::pipe::ARMNN_HARDWARE_VERSION);
266     profilingService.ResetExternalProfilingOptions(options, true);
267 
268     // Bring the profiling service to the "WaitingForAck" state
269     CHECK(profilingService.GetCurrentState() == arm::pipe::ProfilingState::Uninitialised);
270     profilingService.Update();
271     CHECK(profilingService.GetCurrentState() == arm::pipe::ProfilingState::NotConnected);
272     profilingService.Update();
273 
274     // Connect the profiling service
275     auto basePipeServer = connectionHandler.GetNewBasePipeServer(false);
276 
277     // Connect the profiling service to the mock Gatord.
278     gatordmock::GatordMockService mockService(std::move(basePipeServer), false);
279 
280     arm::pipe::TimelineDecoder& timelineDecoder = mockService.GetTimelineDecoder();
281     arm::pipe::DirectoryCaptureCommandHandler& directoryCaptureCommandHandler =
282          mockService.GetDirectoryCaptureCommandHandler();
283 
284     // Give the profiling service sending thread time start executing and send the stream metadata.
__anon38e2fdb80202()285     WaitFor([&](){return profilingService.GetCurrentState() == arm::pipe::ProfilingState::WaitingForAck;},
286             "Profiling service did not switch to WaitingForAck state");
287 
288     profilingService.Update();
289     // Read the stream metadata on the mock side.
290     if (!mockService.WaitForStreamMetaData())
291     {
292         FAIL("Failed to receive StreamMetaData");
293     }
294     // Send Ack from GatorD
295     mockService.SendConnectionAck();
296     // And start to listen for packets
297     mockService.LaunchReceivingThread();
298 
__anon38e2fdb80302()299     WaitFor([&](){return profilingService.GetCurrentState() == arm::pipe::ProfilingState::Active;},
300             "Profiling service did not switch to Active state");
301 
302     // As part of the default startup of the profiling service a counter directory packet will be sent.
__anon38e2fdb80402()303     WaitFor([&](){return directoryCaptureCommandHandler.ParsedCounterDirectory();},
304             "MockGatord did not receive counter directory packet");
305 
306     // Following that we will receive a collection of well known timeline labels and event classes
__anon38e2fdb80502()307     WaitFor([&](){return timelineDecoder.ApplyToModel([&](arm::pipe::TimelineDecoder::Model& m){
308             return m.m_EventClasses.size() >= 2;});},
309             "MockGatord did not receive well known timeline labels and event classes");
310 
311     CheckTimelineDirectory(mockService.GetTimelineDirectoryCaptureCommandHandler());
312     // Verify the commonly used timeline packets sent when the profiling service enters the active state
313     CheckTimelinePackets(timelineDecoder);
314 
315     const arm::pipe::ICounterDirectory& serviceCounterDirectory  = profilingService.GetCounterDirectory();
316     const arm::pipe::ICounterDirectory& receivedCounterDirectory = directoryCaptureCommandHandler.GetCounterDirectory();
317 
318     // Compare the basics of the counter directory from the service and the one we received over the wire.
319     CHECK(serviceCounterDirectory.GetDeviceCount() == receivedCounterDirectory.GetDeviceCount());
320     CHECK(serviceCounterDirectory.GetCounterSetCount() == receivedCounterDirectory.GetCounterSetCount());
321     CHECK(serviceCounterDirectory.GetCategoryCount() == receivedCounterDirectory.GetCategoryCount());
322     CHECK(serviceCounterDirectory.GetCounterCount() == receivedCounterDirectory.GetCounterCount());
323 
324     receivedCounterDirectory.GetDeviceCount();
325     serviceCounterDirectory.GetDeviceCount();
326 
327     const arm::pipe::Devices& serviceDevices = serviceCounterDirectory.GetDevices();
328     for (auto& device : serviceDevices)
329     {
330         // Find the same device in the received counter directory.
331         auto foundDevice = receivedCounterDirectory.GetDevices().find(device.second->m_Uid);
332         CHECK(foundDevice != receivedCounterDirectory.GetDevices().end());
333         CHECK(device.second->m_Name.compare((*foundDevice).second->m_Name) == 0);
334         CHECK(device.second->m_Cores == (*foundDevice).second->m_Cores);
335     }
336 
337     const arm::pipe::CounterSets& serviceCounterSets = serviceCounterDirectory.GetCounterSets();
338     for (auto& counterSet : serviceCounterSets)
339     {
340         // Find the same counter set in the received counter directory.
341         auto foundCounterSet = receivedCounterDirectory.GetCounterSets().find(counterSet.second->m_Uid);
342         CHECK(foundCounterSet != receivedCounterDirectory.GetCounterSets().end());
343         CHECK(counterSet.second->m_Name.compare((*foundCounterSet).second->m_Name) == 0);
344         CHECK(counterSet.second->m_Count == (*foundCounterSet).second->m_Count);
345     }
346 
347     const arm::pipe::Categories& serviceCategories = serviceCounterDirectory.GetCategories();
348     for (auto& category : serviceCategories)
349     {
350         for (auto& receivedCategory : receivedCounterDirectory.GetCategories())
351         {
352             if (receivedCategory->m_Name.compare(category->m_Name) == 0)
353             {
354                 // We've found the matching category.
355                 // Now look at the interiors of the counters. Start by sorting them.
356                 std::sort(category->m_Counters.begin(), category->m_Counters.end());
357                 std::sort(receivedCategory->m_Counters.begin(), receivedCategory->m_Counters.end());
358                 // When comparing uid's here we need to translate them.
359                 std::function<bool(const uint16_t&, const uint16_t&)> comparator =
__anon38e2fdb80702(const uint16_t& first, const uint16_t& second) 360                     [&directoryCaptureCommandHandler](const uint16_t& first, const uint16_t& second) {
361                         uint16_t translated = directoryCaptureCommandHandler.TranslateUIDCopyToOriginal(second);
362                         if (translated == first)
363                         {
364                             return true;
365                         }
366                         return false;
367                     };
368                 // Then let vector == do the work.
369                 CHECK(std::equal(category->m_Counters.begin(), category->m_Counters.end(),
370                                        receivedCategory->m_Counters.begin(), comparator));
371                 break;
372             }
373         }
374     }
375 
376     // Finally check the content of the counters.
377     const arm::pipe::Counters& receivedCounters = receivedCounterDirectory.GetCounters();
378     for (auto& receivedCounter : receivedCounters)
379     {
380         // Translate the Uid and find the corresponding counter in the original counter directory.
381         // Note we can't check m_MaxCounterUid here as it will likely differ between the two counter directories.
382         uint16_t translated = directoryCaptureCommandHandler.TranslateUIDCopyToOriginal(receivedCounter.first);
383         const arm::pipe::Counter* serviceCounter = serviceCounterDirectory.GetCounter(translated);
384         CHECK(serviceCounter->m_DeviceUid == receivedCounter.second->m_DeviceUid);
385         CHECK(serviceCounter->m_Name.compare(receivedCounter.second->m_Name) == 0);
386         CHECK(serviceCounter->m_CounterSetUid == receivedCounter.second->m_CounterSetUid);
387         CHECK(serviceCounter->m_Multiplier == receivedCounter.second->m_Multiplier);
388         CHECK(serviceCounter->m_Interpolation == receivedCounter.second->m_Interpolation);
389         CHECK(serviceCounter->m_Class == receivedCounter.second->m_Class);
390         CHECK(serviceCounter->m_Units.compare(receivedCounter.second->m_Units) == 0);
391         CHECK(serviceCounter->m_Description.compare(receivedCounter.second->m_Description) == 0);
392     }
393 
394     mockService.WaitForReceivingThread();
395     options.m_EnableProfiling = false;
396     profilingService.ResetExternalProfilingOptions(options, true);
397     // Future tests here will add counters to the ProfilingService, increment values and examine
398     // PeriodicCounterCapture data received. These are yet to be integrated.
399 }
400 
401 TEST_CASE("GatorDMockTimeLineActivation")
402 {
403     // This test requires the CpuRef backend to be enabled
404     if(!BackendRegistryInstance().IsBackendRegistered("CpuRef"))
405     {
406         return;
407     }
408     armnn::MockBackendInitialiser initialiser;
409     // Setup the mock service to bind to the UDS.
410     std::string udsNamespace = "gatord_namespace";
411 
412     arm::pipe::ConnectionHandler connectionHandler(udsNamespace, false);
413 
414     armnn::IRuntime::CreationOptions options;
415     options.m_ProfilingOptions.m_EnableProfiling = true;
416     options.m_ProfilingOptions.m_TimelineEnabled = true;
417     armnn::RuntimeImpl runtime(options);
418 
419     auto basePipeServer = connectionHandler.GetNewBasePipeServer(false);
420     gatordmock::GatordMockService mockService(std::move(basePipeServer), false);
421 
422     // Read the stream metadata on the mock side.
423     if (!mockService.WaitForStreamMetaData())
424     {
425         FAIL("Failed to receive StreamMetaData");
426     }
427 
428     armnn::MockBackendProfilingService  mockProfilingService = armnn::MockBackendProfilingService::Instance();
429     armnn::MockBackendProfilingContext* mockBackEndProfilingContext = mockProfilingService.GetContext();
430 
431     // Send Ack from GatorD
432     mockService.SendConnectionAck();
433     // And start to listen for packets
434     mockService.LaunchReceivingThread();
435 
436     // Build and optimize a simple network while we wait
437     INetworkPtr net(INetwork::Create());
438 
439     IConnectableLayer* input = net->AddInputLayer(0, "input");
440 
441     NormalizationDescriptor descriptor;
442     IConnectableLayer* normalize = net->AddNormalizationLayer(descriptor, "normalization");
443 
444     IConnectableLayer* output = net->AddOutputLayer(0, "output");
445 
446     input->GetOutputSlot(0).Connect(normalize->GetInputSlot(0));
447     normalize->GetOutputSlot(0).Connect(output->GetInputSlot(0));
448 
449     input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 4 }, DataType::Float32));
450     normalize->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 4 }, DataType::Float32));
451 
452     std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef };
453     IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime.GetDeviceSpec());
454 
__anon38e2fdb80802()455     WaitFor([&](){return mockService.GetDirectoryCaptureCommandHandler().ParsedCounterDirectory();},
456             "MockGatord did not receive counter directory packet");
457 
458     arm::pipe::TimelineDecoder& timelineDecoder = mockService.GetTimelineDecoder();
459 
__anon38e2fdb80a02(arm::pipe::TimelineDecoder::Model& m)460     WaitFor([&](){return timelineDecoder.ApplyToModel([&](arm::pipe::TimelineDecoder::Model& m){
461              return m.m_EventClasses.size() >= 2;});},
462             "MockGatord did not receive well known timeline labels");
463 
__anon38e2fdb80b02()464     WaitFor([&](){return timelineDecoder.ApplyToModel([&](arm::pipe::TimelineDecoder::Model& m){
465              return m.m_Entities.size() >= 1;});},
466             "MockGatord did not receive mock backend test entity");
467 
468     // Packets we expect from SendWellKnownLabelsAndEventClassesTest
__anon38e2fdb80d02(const arm::pipe::TimelineDecoder::Model& m)469     timelineDecoder.ApplyToModel([&](const arm::pipe::TimelineDecoder::Model& m){
470         CHECK(m.m_Entities.size() == 1);
471         CHECK(m.m_EventClasses.size()  == 2);
472         CHECK(m.m_Labels.size()  == 15);
473         CHECK(m.m_Relationships.size()  == 0);
474         CHECK(m.m_Events.size()  == 0);
475     });
476 
477     mockService.SendDeactivateTimelinePacket();
478 
__anon38e2fdb80e02()479     WaitFor([&](){return !mockBackEndProfilingContext->TimelineReportingEnabled();},
480             "Timeline packets were not deactivated");
481 
482     // Load the network into runtime now that timeline reporting is disabled
483     armnn::NetworkId netId;
484     runtime.LoadNetwork(netId, std::move(optNet));
485 
486     // Now activate timeline packets
487     mockService.SendActivateTimelinePacket();
488 
__anon38e2fdb80f02()489     WaitFor([&](){return mockBackEndProfilingContext->TimelineReportingEnabled();},
490             "Timeline packets were not activated");
491 
492     // Once TimelineReporting is Enabled additional activateTimelinePackets should be ignored
493     mockService.SendActivateTimelinePacket();
494     mockService.SendActivateTimelinePacket();
495 
496     // Once timeline packets have been reactivated the ActivateTimelineReportingCommandHandler will resend the
497     // SendWellKnownLabelsAndEventClasses and then send the structure of any loaded networks
__anon38e2fdb81002()498     WaitFor([&](){return timelineDecoder.ApplyToModel([&](arm::pipe::TimelineDecoder::Model& m){
499             return m.m_Labels.size() >= 24;});},
500             "MockGatord did not receive well known timeline labels");
501 
502     // Packets we expect from SendWellKnownLabelsAndEventClassesTest * 2 + network above (input, norm, backend, output)
__anon38e2fdb81202(const arm::pipe::TimelineDecoder::Model& m)503     timelineDecoder.ApplyToModel([&](const arm::pipe::TimelineDecoder::Model& m){
504         CHECK(m.m_Entities.size() == 6);
505         CHECK(m.m_EventClasses.size()  == 4);
506         CHECK(m.m_Labels.size()  == 34);
507         CHECK(m.m_Relationships.size()  == 15);
508         CHECK(m.m_Events.size()  == 0);
509     });
510 
511     mockService.WaitForReceivingThread();
512     GetProfilingService(&runtime).Disconnect();
513 }
514 
515 }
516