IVGCVSW-4737 Add check for CpuRef back-end before using it in tests
[platform/upstream/armnn.git] / tests / profiling / gatordmock / tests / GatordMockTests.cpp
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5
6 #include <CommandHandlerRegistry.hpp>
7 #include <ConnectionHandler.hpp>
8 #include <DirectoryCaptureCommandHandler.hpp>
9 #include <GatordMockService.hpp>
10 #include <LabelsAndEventClasses.hpp>
11 #include <ProfilingService.hpp>
12 #include <TimelinePacketWriterFactory.hpp>
13
14 #include <TimelineDirectoryCaptureCommandHandler.hpp>
15 #include <TimelineDecoder.hpp>
16
17 #include <Runtime.hpp>
18
19 #include <MockBackend.hpp>
20
21 #include <boost/cast.hpp>
22 #include <boost/test/test_tools.hpp>
23 #include <boost/test/unit_test_suite.hpp>
24
25
26 BOOST_AUTO_TEST_SUITE(GatordMockTests)
27
28 using namespace armnn;
29 using namespace std::this_thread;
30 using namespace std::chrono_literals;
31
32 BOOST_AUTO_TEST_CASE(CounterCaptureHandlingTest)
33 {
34     using boost::numeric_cast;
35
36     profiling::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 = numeric_cast<uint32_t>(sizeof(uint64_t));
65     uint32_t sizeOfUint32 = numeric_cast<uint32_t>(sizeof(uint32_t));
66     uint32_t sizeOfUint16 = numeric_cast<uint32_t>(sizeof(uint16_t));
67     // Offset index to point to mem address
68     uint32_t offset = 0;
69
70     profiling::WriteUint64(data1, offset, time);
71     offset += sizeOfUint64;
72     for (const auto& pair : indexValuePairs)
73     {
74         profiling::WriteUint16(data1, offset, pair.first);
75         offset += sizeOfUint16;
76         profiling::WriteUint32(data1, offset, pair.second);
77         offset += sizeOfUint32;
78     }
79
80     offset = 0;
81
82     profiling::WriteUint64(data2, offset, time2);
83     offset += sizeOfUint64;
84     for (const auto& pair : indexValuePairs)
85     {
86         profiling::WriteUint16(data2, offset, pair.first);
87         offset += sizeOfUint16;
88         profiling::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     profiling::Packet packet1(headerWord1, dataLength, uniqueData1);
95     profiling::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
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             BOOST_FAIL("Timeout: " + errorMsg);
119         }
120         std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
121         timeSlept += sleepTime;
122     }
123 }
124
125 void CheckTimelineDirectory(timelinedecoder::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(std::thread::id);
131
132     profiling::BufferManager bufferManager(5);
133     profiling::TimelinePacketWriterFactory timelinePacketWriterFactory(bufferManager);
134
135     std::unique_ptr<profiling::ISendTimelinePacket> sendTimelinePacket =
136             timelinePacketWriterFactory.GetSendTimelinePacket();
137
138     sendTimelinePacket->SendTimelineMessageDirectoryPackage();
139     sendTimelinePacket->Commit();
140
141     std::vector<profiling::SwTraceMessage> swTraceBufferMessages;
142
143     unsigned int offset = uint32_t_size * 2;
144
145     std::unique_ptr<profiling::IPacketBuffer> packetBuffer = bufferManager.GetReadableBuffer();
146
147     uint8_t readStreamVersion = ReadUint8(packetBuffer, offset);
148     BOOST_CHECK(readStreamVersion == 4);
149     offset += uint8_t_size;
150     uint8_t readPointerBytes = ReadUint8(packetBuffer, offset);
151     BOOST_CHECK(readPointerBytes == uint64_t_size);
152     offset += uint8_t_size;
153     uint8_t readThreadIdBytes = ReadUint8(packetBuffer, offset);
154     BOOST_CHECK(readThreadIdBytes == threadId_size);
155     offset += uint8_t_size;
156
157     uint32_t declarationSize = profiling::ReadUint32(packetBuffer, offset);
158     offset += uint32_t_size;
159     for(uint32_t i = 0; i < declarationSize; ++i)
160     {
161         swTraceBufferMessages.push_back(profiling::ReadSwTraceMessage(packetBuffer->GetReadableData(), offset));
162     }
163
164     for(uint32_t index = 0; index < declarationSize; ++index)
165     {
166         profiling::SwTraceMessage& bufferMessage = swTraceBufferMessages[index];
167         profiling::SwTraceMessage& handlerMessage = commandHandler.m_SwTraceMessages[index];
168
169         BOOST_CHECK(bufferMessage.m_Name == handlerMessage.m_Name);
170         BOOST_CHECK(bufferMessage.m_UiName == handlerMessage.m_UiName);
171         BOOST_CHECK(bufferMessage.m_Id == handlerMessage.m_Id);
172
173         BOOST_CHECK(bufferMessage.m_ArgTypes.size() == handlerMessage.m_ArgTypes.size());
174         for(uint32_t i = 0; i < bufferMessage.m_ArgTypes.size(); ++i)
175         {
176             BOOST_CHECK(bufferMessage.m_ArgTypes[i] == handlerMessage.m_ArgTypes[i]);
177         }
178
179         BOOST_CHECK(bufferMessage.m_ArgNames.size() == handlerMessage.m_ArgNames.size());
180         for(uint32_t i = 0; i < bufferMessage.m_ArgNames.size(); ++i)
181         {
182             BOOST_CHECK(bufferMessage.m_ArgNames[i] == handlerMessage.m_ArgNames[i]);
183         }
184     }
185 }
186
187 void CheckTimelinePackets(timelinedecoder::TimelineDecoder& timelineDecoder)
188 {
189     BOOST_CHECK(timelineDecoder.GetModel().m_Labels[0].m_Guid == profiling::LabelsAndEventClasses::NAME_GUID);
190     BOOST_CHECK(timelineDecoder.GetModel().m_Labels[0].m_Name == profiling::LabelsAndEventClasses::NAME_LABEL);
191
192     BOOST_CHECK(timelineDecoder.GetModel().m_Labels[1].m_Guid == profiling::LabelsAndEventClasses::TYPE_GUID);
193     BOOST_CHECK(timelineDecoder.GetModel().m_Labels[1].m_Name == profiling::LabelsAndEventClasses::TYPE_LABEL);
194
195     BOOST_CHECK(timelineDecoder.GetModel().m_Labels[2].m_Guid == profiling::LabelsAndEventClasses::INDEX_GUID);
196     BOOST_CHECK(timelineDecoder.GetModel().m_Labels[2].m_Name == profiling::LabelsAndEventClasses::INDEX_LABEL);
197
198     BOOST_CHECK(timelineDecoder.GetModel().m_Labels[3].m_Guid == profiling::LabelsAndEventClasses::BACKENDID_GUID);
199     BOOST_CHECK(timelineDecoder.GetModel().m_Labels[3].m_Name == profiling::LabelsAndEventClasses::BACKENDID_LABEL);
200
201     BOOST_CHECK(timelineDecoder.GetModel().m_Labels[4].m_Guid == profiling::LabelsAndEventClasses::LAYER_GUID);
202     BOOST_CHECK(timelineDecoder.GetModel().m_Labels[4].m_Name == profiling::LabelsAndEventClasses::LAYER);
203
204     BOOST_CHECK(timelineDecoder.GetModel().m_Labels[5].m_Guid == profiling::LabelsAndEventClasses::WORKLOAD_GUID);
205     BOOST_CHECK(timelineDecoder.GetModel().m_Labels[5].m_Name == profiling::LabelsAndEventClasses::WORKLOAD);
206
207     BOOST_CHECK(timelineDecoder.GetModel().m_Labels[6].m_Guid == profiling::LabelsAndEventClasses::NETWORK_GUID);
208     BOOST_CHECK(timelineDecoder.GetModel().m_Labels[6].m_Name == profiling::LabelsAndEventClasses::NETWORK);
209
210     BOOST_CHECK(timelineDecoder.GetModel().m_Labels[7].m_Guid == profiling::LabelsAndEventClasses::CONNECTION_GUID);
211     BOOST_CHECK(timelineDecoder.GetModel().m_Labels[7].m_Name == profiling::LabelsAndEventClasses::CONNECTION);
212
213     BOOST_CHECK(timelineDecoder.GetModel().m_Labels[8].m_Guid == profiling::LabelsAndEventClasses::INFERENCE_GUID);
214     BOOST_CHECK(timelineDecoder.GetModel().m_Labels[8].m_Name == profiling::LabelsAndEventClasses::INFERENCE);
215
216     BOOST_CHECK(timelineDecoder.GetModel().m_Labels[9].m_Guid ==
217                 profiling::LabelsAndEventClasses::WORKLOAD_EXECUTION_GUID);
218     BOOST_CHECK(timelineDecoder.GetModel().m_Labels[9].m_Name == profiling::LabelsAndEventClasses::WORKLOAD_EXECUTION);
219
220     BOOST_CHECK(timelineDecoder.GetModel().m_EventClasses[0].m_Guid ==
221                 profiling::LabelsAndEventClasses::ARMNN_PROFILING_SOL_EVENT_CLASS);
222     BOOST_CHECK(timelineDecoder.GetModel().m_EventClasses[1].m_Guid ==
223                 profiling::LabelsAndEventClasses::ARMNN_PROFILING_EOL_EVENT_CLASS);
224 }
225
226 BOOST_AUTO_TEST_CASE(GatorDMockEndToEnd)
227 {
228     // The purpose of this test is to setup both sides of the profiling service and get to the point of receiving
229     // performance data.
230
231     // Setup the mock service to bind to the UDS.
232     std::string udsNamespace = "gatord_namespace";
233
234     BOOST_CHECK_NO_THROW(armnnProfiling::ConnectionHandler connectionHandler(udsNamespace, false));
235
236     armnnProfiling::ConnectionHandler connectionHandler(udsNamespace, false);
237
238     // Enable the profiling service.
239     armnn::IRuntime::CreationOptions::ExternalProfilingOptions options;
240     options.m_EnableProfiling = true;
241     options.m_TimelineEnabled = true;
242
243     armnn::profiling::ProfilingService profilingService;
244     profilingService.ResetExternalProfilingOptions(options, true);
245
246     // Bring the profiling service to the "WaitingForAck" state
247     BOOST_CHECK(profilingService.GetCurrentState() == profiling::ProfilingState::Uninitialised);
248     profilingService.Update();
249     BOOST_CHECK(profilingService.GetCurrentState() == profiling::ProfilingState::NotConnected);
250     profilingService.Update();
251
252     // Connect the profiling service
253     auto basePipeServer = connectionHandler.GetNewBasePipeServer(false);
254
255     // Connect the profiling service to the mock Gatord.
256     gatordmock::GatordMockService mockService(std::move(basePipeServer), false);
257
258     timelinedecoder::TimelineDecoder& timelineDecoder = mockService.GetTimelineDecoder();
259     profiling::DirectoryCaptureCommandHandler& directoryCaptureCommandHandler =
260          mockService.GetDirectoryCaptureCommandHandler();
261
262     // Give the profiling service sending thread time start executing and send the stream metadata.
263     WaitFor([&](){return profilingService.GetCurrentState() == profiling::ProfilingState::WaitingForAck;},
264             "Profiling service did not switch to WaitingForAck state");
265
266     profilingService.Update();
267     // Read the stream metadata on the mock side.
268     if (!mockService.WaitForStreamMetaData())
269     {
270         BOOST_FAIL("Failed to receive StreamMetaData");
271     }
272     // Send Ack from GatorD
273     mockService.SendConnectionAck();
274     // And start to listen for packets
275     mockService.LaunchReceivingThread();
276
277     WaitFor([&](){return profilingService.GetCurrentState() == profiling::ProfilingState::Active;},
278             "Profiling service did not switch to Active state");
279
280     // As part of the default startup of the profiling service a counter directory packet will be sent.
281     WaitFor([&](){return directoryCaptureCommandHandler.ParsedCounterDirectory();},
282             "MockGatord did not receive counter directory packet");
283
284     // Following that we will receive a collection of well known timeline labels and event classes
285     WaitFor([&](){return timelineDecoder.GetModel().m_EventClasses.size() >= 2;},
286             "MockGatord did not receive well known timeline labels and event classes");
287
288     CheckTimelineDirectory(mockService.GetTimelineDirectoryCaptureCommandHandler());
289     // Verify the commonly used timeline packets sent when the profiling service enters the active state
290     CheckTimelinePackets(timelineDecoder);
291
292     const profiling::ICounterDirectory& serviceCounterDirectory  = profilingService.GetCounterDirectory();
293     const profiling::ICounterDirectory& receivedCounterDirectory = directoryCaptureCommandHandler.GetCounterDirectory();
294
295     // Compare the basics of the counter directory from the service and the one we received over the wire.
296     BOOST_CHECK(serviceCounterDirectory.GetDeviceCount() == receivedCounterDirectory.GetDeviceCount());
297     BOOST_CHECK(serviceCounterDirectory.GetCounterSetCount() == receivedCounterDirectory.GetCounterSetCount());
298     BOOST_CHECK(serviceCounterDirectory.GetCategoryCount() == receivedCounterDirectory.GetCategoryCount());
299     BOOST_CHECK(serviceCounterDirectory.GetCounterCount() == receivedCounterDirectory.GetCounterCount());
300
301     receivedCounterDirectory.GetDeviceCount();
302     serviceCounterDirectory.GetDeviceCount();
303
304     const profiling::Devices& serviceDevices = serviceCounterDirectory.GetDevices();
305     for (auto& device : serviceDevices)
306     {
307         // Find the same device in the received counter directory.
308         auto foundDevice = receivedCounterDirectory.GetDevices().find(device.second->m_Uid);
309         BOOST_CHECK(foundDevice != receivedCounterDirectory.GetDevices().end());
310         BOOST_CHECK(device.second->m_Name.compare((*foundDevice).second->m_Name) == 0);
311         BOOST_CHECK(device.second->m_Cores == (*foundDevice).second->m_Cores);
312     }
313
314     const profiling::CounterSets& serviceCounterSets = serviceCounterDirectory.GetCounterSets();
315     for (auto& counterSet : serviceCounterSets)
316     {
317         // Find the same counter set in the received counter directory.
318         auto foundCounterSet = receivedCounterDirectory.GetCounterSets().find(counterSet.second->m_Uid);
319         BOOST_CHECK(foundCounterSet != receivedCounterDirectory.GetCounterSets().end());
320         BOOST_CHECK(counterSet.second->m_Name.compare((*foundCounterSet).second->m_Name) == 0);
321         BOOST_CHECK(counterSet.second->m_Count == (*foundCounterSet).second->m_Count);
322     }
323
324     const profiling::Categories& serviceCategories = serviceCounterDirectory.GetCategories();
325     for (auto& category : serviceCategories)
326     {
327         for (auto& receivedCategory : receivedCounterDirectory.GetCategories())
328         {
329             if (receivedCategory->m_Name.compare(category->m_Name) == 0)
330             {
331                 // We've found the matching category.
332                 // Now look at the interiors of the counters. Start by sorting them.
333                 std::sort(category->m_Counters.begin(), category->m_Counters.end());
334                 std::sort(receivedCategory->m_Counters.begin(), receivedCategory->m_Counters.end());
335                 // When comparing uid's here we need to translate them.
336                 std::function<bool(const uint16_t&, const uint16_t&)> comparator =
337                     [&directoryCaptureCommandHandler](const uint16_t& first, const uint16_t& second) {
338                         uint16_t translated = directoryCaptureCommandHandler.TranslateUIDCopyToOriginal(second);
339                         if (translated == first)
340                         {
341                             return true;
342                         }
343                         return false;
344                     };
345                 // Then let vector == do the work.
346                 BOOST_CHECK(std::equal(category->m_Counters.begin(), category->m_Counters.end(),
347                                        receivedCategory->m_Counters.begin(), comparator));
348                 break;
349             }
350         }
351     }
352
353     // Finally check the content of the counters.
354     const profiling::Counters& receivedCounters = receivedCounterDirectory.GetCounters();
355     for (auto& receivedCounter : receivedCounters)
356     {
357         // Translate the Uid and find the corresponding counter in the original counter directory.
358         // Note we can't check m_MaxCounterUid here as it will likely differ between the two counter directories.
359         uint16_t translated = directoryCaptureCommandHandler.TranslateUIDCopyToOriginal(receivedCounter.first);
360         const profiling::Counter* serviceCounter = serviceCounterDirectory.GetCounter(translated);
361         BOOST_CHECK(serviceCounter->m_DeviceUid == receivedCounter.second->m_DeviceUid);
362         BOOST_CHECK(serviceCounter->m_Name.compare(receivedCounter.second->m_Name) == 0);
363         BOOST_CHECK(serviceCounter->m_CounterSetUid == receivedCounter.second->m_CounterSetUid);
364         BOOST_CHECK(serviceCounter->m_Multiplier == receivedCounter.second->m_Multiplier);
365         BOOST_CHECK(serviceCounter->m_Interpolation == receivedCounter.second->m_Interpolation);
366         BOOST_CHECK(serviceCounter->m_Class == receivedCounter.second->m_Class);
367         BOOST_CHECK(serviceCounter->m_Units.compare(receivedCounter.second->m_Units) == 0);
368         BOOST_CHECK(serviceCounter->m_Description.compare(receivedCounter.second->m_Description) == 0);
369     }
370
371     mockService.WaitForReceivingThread();
372     options.m_EnableProfiling = false;
373     profilingService.ResetExternalProfilingOptions(options, true);
374     // Future tests here will add counters to the ProfilingService, increment values and examine
375     // PeriodicCounterCapture data received. These are yet to be integrated.
376 }
377
378 BOOST_AUTO_TEST_CASE(GatorDMockTimeLineActivation)
379 {
380     // This test requires the CpuRef backend to be enabled
381     if(!BackendRegistryInstance().IsBackendRegistered("CpuRef"))
382     {
383         return;
384     }
385     armnn::MockBackendInitialiser initialiser;
386     // Setup the mock service to bind to the UDS.
387     std::string udsNamespace = "gatord_namespace";
388
389     armnnProfiling::ConnectionHandler connectionHandler(udsNamespace, false);
390
391     armnn::IRuntime::CreationOptions options;
392     options.m_ProfilingOptions.m_EnableProfiling = true;
393     options.m_ProfilingOptions.m_TimelineEnabled = true;
394     armnn::Runtime runtime(options);
395
396     auto basePipeServer = connectionHandler.GetNewBasePipeServer(false);
397     gatordmock::GatordMockService mockService(std::move(basePipeServer), false);
398
399     // Read the stream metadata on the mock side.
400     if (!mockService.WaitForStreamMetaData())
401     {
402         BOOST_FAIL("Failed to receive StreamMetaData");
403     }
404
405     armnn::MockBackendProfilingService mockProfilingService = armnn::MockBackendProfilingService::Instance();
406     armnn::MockBackendProfilingContext *mockBackEndProfilingContext = mockProfilingService.GetContext();
407
408     // Send Ack from GatorD
409     mockService.SendConnectionAck();
410     // And start to listen for packets
411     mockService.LaunchReceivingThread();
412
413     // Build and optimize a simple network while we wait
414     INetworkPtr net(INetwork::Create());
415
416     IConnectableLayer* input = net->AddInputLayer(0, "input");
417
418     NormalizationDescriptor descriptor;
419     IConnectableLayer* normalize = net->AddNormalizationLayer(descriptor, "normalization");
420
421     IConnectableLayer* output = net->AddOutputLayer(0, "output");
422
423     input->GetOutputSlot(0).Connect(normalize->GetInputSlot(0));
424     normalize->GetOutputSlot(0).Connect(output->GetInputSlot(0));
425
426     input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 4 }, DataType::Float32));
427     normalize->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 4 }, DataType::Float32));
428
429     std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef };
430     IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime.GetDeviceSpec());
431
432     WaitFor([&](){return mockService.GetDirectoryCaptureCommandHandler().ParsedCounterDirectory();},
433             "MockGatord did not receive counter directory packet");
434
435     timelinedecoder::TimelineDecoder& timelineDecoder = mockService.GetTimelineDecoder();
436
437     WaitFor([&](){return timelineDecoder.GetModel().m_EventClasses.size() >= 2;},
438             "MockGatord did not receive well known timeline labels");
439
440     WaitFor([&](){return timelineDecoder.GetModel().m_Entities.size() >= 1;},
441             "MockGatord did not receive mock backend test entity");
442
443     // Packets we expect from SendWellKnownLabelsAndEventClassesTest
444     BOOST_CHECK(timelineDecoder.GetModel().m_Entities.size() == 1);
445     BOOST_CHECK(timelineDecoder.GetModel().m_EventClasses.size()  == 2);
446     BOOST_CHECK(timelineDecoder.GetModel().m_Labels.size()  == 10);
447     BOOST_CHECK(timelineDecoder.GetModel().m_Relationships.size()  == 0);
448     BOOST_CHECK(timelineDecoder.GetModel().m_Events.size()  == 0);
449
450     mockService.SendDeactivateTimelinePacket();
451
452     WaitFor([&](){return !mockBackEndProfilingContext->TimelineReportingEnabled();},
453             "Timeline packets were not deactivated");
454
455     // Load the network into runtime now that timeline reporting is disabled
456     armnn::NetworkId netId;
457     runtime.LoadNetwork(netId, std::move(optNet));
458
459     // Now activate timeline packets
460     mockService.SendActivateTimelinePacket();
461
462     WaitFor([&](){return mockBackEndProfilingContext->TimelineReportingEnabled();},
463             "Timeline packets were not activated");
464
465     // Once timeline packets have been reactivated the ActivateTimelineReportingCommandHandler will resend the
466     // SendWellKnownLabelsAndEventClasses and then send the structure of any loaded networks
467     WaitFor([&](){return timelineDecoder.GetModel().m_Labels.size() >= 24;},
468             "MockGatord did not receive well known timeline labels");
469
470     // Packets we expect from SendWellKnownLabelsAndEventClassesTest * 2 and the loaded model
471     BOOST_CHECK(timelineDecoder.GetModel().m_Entities.size() == 6);
472     BOOST_CHECK(timelineDecoder.GetModel().m_EventClasses.size()  == 4);
473     BOOST_CHECK(timelineDecoder.GetModel().m_Labels.size()  == 24);
474     BOOST_CHECK(timelineDecoder.GetModel().m_Relationships.size()  == 28);
475     BOOST_CHECK(timelineDecoder.GetModel().m_Events.size()  == 0);
476
477     mockService.WaitForReceivingThread();
478     GetProfilingService(&runtime).Disconnect();
479 }
480
481 BOOST_AUTO_TEST_SUITE_END()