blob: f9df633a1c6399d6f264ef865acfa25f18576fa5 [file] [log] [blame]
Keith Davis3201eea2019-10-24 17:30:41 +01001//
Jim Flynn6398a982020-05-27 17:05:21 +01002// Copyright © 2019 Arm Ltd and Contributors. All rights reserved.
Keith Davis3201eea2019-10-24 17:30:41 +01003// SPDX-License-Identifier: MIT
4//
5
Jim Flynn4e755a52020-03-29 17:48:26 +01006#include <Filesystem.hpp>
Jim Flynn6398a982020-05-27 17:05:21 +01007#include <LabelsAndEventClasses.hpp>
Aron Virginas-Tar8bf442e2019-11-07 18:41:40 +00008#include <ProfilingService.hpp>
Jim Flynn6398a982020-05-27 17:05:21 +01009#include "ProfilingTestUtils.hpp"
Jim Flynn4e755a52020-03-29 17:48:26 +010010#include "PrintPacketHeaderHandler.hpp"
Jim Flynn6398a982020-05-27 17:05:21 +010011#include <Runtime.hpp>
Jim Flynn4e755a52020-03-29 17:48:26 +010012#include "TestTimelinePacketHandler.hpp"
Keith Davis3201eea2019-10-24 17:30:41 +010013
Keith Davis3201eea2019-10-24 17:30:41 +010014#include <boost/numeric/conversion/cast.hpp>
15#include <boost/test/unit_test.hpp>
16
Keith Davis3201eea2019-10-24 17:30:41 +010017#include <cstdio>
Keith Davis3201eea2019-10-24 17:30:41 +010018#include <sstream>
19#include <sys/stat.h>
20
Keith Davis3201eea2019-10-24 17:30:41 +010021using namespace armnn::profiling;
22using namespace armnn;
23
24using namespace std::chrono_literals;
25
Finn Williams09ad6f92019-12-19 17:05:18 +000026class FileOnlyHelperService : public ProfilingService
27{
28 public:
29 // Wait for a notification from the send thread
30 bool WaitForPacketsSent(uint32_t timeout = 1000)
31 {
Sadik Armagan3184c902020-03-18 10:57:30 +000032 return ProfilingService::WaitForPacketSent(m_ProfilingService, timeout);
Finn Williams09ad6f92019-12-19 17:05:18 +000033 }
Sadik Armagan3184c902020-03-18 10:57:30 +000034 armnn::profiling::ProfilingService m_ProfilingService;
Finn Williams09ad6f92019-12-19 17:05:18 +000035};
36
Keith Davis3201eea2019-10-24 17:30:41 +010037BOOST_AUTO_TEST_SUITE(FileOnlyProfilingDecoratorTests)
38
Jim Flynn4e755a52020-03-29 17:48:26 +010039BOOST_AUTO_TEST_CASE(TestFileOnlyProfiling)
40{
Jan Eilersf78c7672020-07-01 18:09:39 +010041 // Get all registered backends
42 std::vector<BackendId> suitableBackends = GetSuitableBackendRegistered();
43
44 // Run test for each backend separately
45 for (auto const& backend : suitableBackends)
Finn Williams0c32ccf2020-05-12 13:37:06 +010046 {
Jan Eilersf78c7672020-07-01 18:09:39 +010047 // Enable m_FileOnly but also provide ILocalPacketHandler which should consume the packets.
48 // This won't dump anything to file.
49 armnn::Runtime::CreationOptions creationOptions;
50 creationOptions.m_ProfilingOptions.m_EnableProfiling = true;
51 creationOptions.m_ProfilingOptions.m_FileOnly = true;
52 creationOptions.m_ProfilingOptions.m_CapturePeriod = 100;
53 creationOptions.m_ProfilingOptions.m_TimelineEnabled = true;
54 ILocalPacketHandlerSharedPtr localPacketHandlerPtr = std::make_shared<TestTimelinePacketHandler>();
55 creationOptions.m_ProfilingOptions.m_LocalPacketHandlers.push_back(localPacketHandlerPtr);
56
57 armnn::Runtime runtime(creationOptions);
58 // ensure the GUID generator is reset to zero
59 GetProfilingService(&runtime).ResetGuidGenerator();
60
61 // Load a simple network
62 // build up the structure of the network
63 INetworkPtr net(INetwork::Create());
64
65 IConnectableLayer* input = net->AddInputLayer(0, "input");
66
67 ElementwiseUnaryDescriptor descriptor(UnaryOperation::Rsqrt);
68 IConnectableLayer* Rsqrt = net->AddElementwiseUnaryLayer(descriptor, "Rsqrt");
69
70 IConnectableLayer* output = net->AddOutputLayer(0, "output");
71
72 input->GetOutputSlot(0).Connect(Rsqrt->GetInputSlot(0));
73 Rsqrt->GetOutputSlot(0).Connect(output->GetInputSlot(0));
74
75 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 4 }, DataType::Float32));
76 Rsqrt->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 4 }, DataType::Float32));
77
78 std::vector<armnn::BackendId> backendsVec {backend};
79 IOptimizedNetworkPtr optNet = Optimize(*net, backendsVec, runtime.GetDeviceSpec());
80
81 // Load it into the runtime. It should succeed.
82 armnn::NetworkId netId;
83 BOOST_TEST(runtime.LoadNetwork(netId, std::move(optNet)) == Status::Success);
84
85 // Creates structures for input & output.
86 std::vector<float> inputData(16);
87 std::vector<float> outputData(16);
88 for (unsigned int i = 0; i < 16; ++i) {
89 inputData[i] = 9.0;
90 outputData[i] = 3.0;
91 }
92
93 InputTensors inputTensors
94 {
95 {0, ConstTensor(runtime.GetInputTensorInfo(netId, 0), inputData.data())}
96 };
97 OutputTensors outputTensors
98 {
99 {0, Tensor(runtime.GetOutputTensorInfo(netId, 0), outputData.data())}
100 };
101
102 // Does the inference.
103 runtime.EnqueueWorkload(netId, inputTensors, outputTensors);
104
105 static_cast<TestTimelinePacketHandler *>(localPacketHandlerPtr.get())->WaitOnInferenceCompletion(3000);
106
107 const TimelineModel &model =
108 static_cast<TestTimelinePacketHandler *>(localPacketHandlerPtr.get())->GetTimelineModel();
109
110 for (auto &error : model.GetErrors()) {
111 std::cout << error.what() << std::endl;
112 }
113 BOOST_TEST(model.GetErrors().empty());
114 std::vector<std::string> desc = GetModelDescription(model);
115 std::vector<std::string> expectedOutput;
116 expectedOutput.push_back("Entity [0] name = input type = layer");
Jim Flynnf7713212020-07-14 09:50:59 +0100117 expectedOutput.push_back(" connection [17] from entity [0] to entity [1]");
118 expectedOutput.push_back(" child: Entity [26] backendId = " + backend.Get() + " type = workload");
Jan Eilersf78c7672020-07-01 18:09:39 +0100119 expectedOutput.push_back("Entity [1] name = Rsqrt type = layer");
Jim Flynnf7713212020-07-14 09:50:59 +0100120 expectedOutput.push_back(" connection [25] from entity [1] to entity [2]");
121 expectedOutput.push_back(" child: Entity [18] backendId = " + backend.Get() + " type = workload");
Jan Eilersf78c7672020-07-01 18:09:39 +0100122 expectedOutput.push_back("Entity [2] name = output type = layer");
Jim Flynnf7713212020-07-14 09:50:59 +0100123 expectedOutput.push_back(" child: Entity [30] backendId = " + backend.Get() + " type = workload");
124 expectedOutput.push_back("Entity [6] processId = [processId] type = network");
Jan Eilersf78c7672020-07-01 18:09:39 +0100125 expectedOutput.push_back(" child: Entity [0] name = input type = layer");
126 expectedOutput.push_back(" child: Entity [1] name = Rsqrt type = layer");
127 expectedOutput.push_back(" child: Entity [2] name = output type = layer");
Jim Flynnf7713212020-07-14 09:50:59 +0100128 expectedOutput.push_back(" execution: Entity [34] type = inference");
129 expectedOutput.push_back(" event: [8] class [start_of_life]");
130 expectedOutput.push_back("Entity [18] backendId = " + backend.Get() + " type = workload");
131 expectedOutput.push_back(" execution: Entity [47] type = workload_execution");
132 expectedOutput.push_back("Entity [26] backendId = " + backend.Get() + " type = workload");
133 expectedOutput.push_back(" execution: Entity [39] type = workload_execution");
134 expectedOutput.push_back("Entity [30] backendId = " + backend.Get() + " type = workload");
135 expectedOutput.push_back(" execution: Entity [55] type = workload_execution");
136 expectedOutput.push_back("Entity [34] type = inference");
137 expectedOutput.push_back(" child: Entity [39] type = workload_execution");
138 expectedOutput.push_back(" child: Entity [47] type = workload_execution");
139 expectedOutput.push_back(" child: Entity [55] type = workload_execution");
140 expectedOutput.push_back(" event: [37] class [start_of_life]");
141 expectedOutput.push_back(" event: [63] class [end_of_life]");
142 expectedOutput.push_back("Entity [39] type = workload_execution");
143 expectedOutput.push_back(" event: [43] class [start_of_life]");
144 expectedOutput.push_back(" event: [45] class [end_of_life]");
145 expectedOutput.push_back("Entity [47] type = workload_execution");
146 expectedOutput.push_back(" event: [51] class [start_of_life]");
147 expectedOutput.push_back(" event: [53] class [end_of_life]");
148 expectedOutput.push_back("Entity [55] type = workload_execution");
149 expectedOutput.push_back(" event: [59] class [start_of_life]");
150 expectedOutput.push_back(" event: [61] class [end_of_life]");
Jan Eilersf78c7672020-07-01 18:09:39 +0100151 BOOST_TEST(CompareOutput(desc, expectedOutput));
Finn Williams0c32ccf2020-05-12 13:37:06 +0100152 }
Jim Flynn4e755a52020-03-29 17:48:26 +0100153}
154
Jim Flynnc9631102020-06-24 11:11:20 +0100155BOOST_AUTO_TEST_CASE(DumpOutgoingValidFileEndToEnd)
Keith Davis3201eea2019-10-24 17:30:41 +0100156{
Jan Eilersf78c7672020-07-01 18:09:39 +0100157 // Get all registered backends
158 std::vector<BackendId> suitableBackends = GetSuitableBackendRegistered();
159
160 // Run test for each backend separately
161 for (auto const& backend : suitableBackends)
Keith Davis3201eea2019-10-24 17:30:41 +0100162 {
Jan Eilersf78c7672020-07-01 18:09:39 +0100163 // Create a temporary file name.
164 fs::path tempPath = armnnUtils::Filesystem::NamedTempFile("DumpOutgoingValidFileEndToEnd_CaptureFile.txt");
165 // Make sure the file does not exist at this point
166 BOOST_CHECK(!fs::exists(tempPath));
167
168 armnn::Runtime::CreationOptions options;
169 options.m_ProfilingOptions.m_EnableProfiling = true;
170 options.m_ProfilingOptions.m_FileOnly = true;
171 options.m_ProfilingOptions.m_IncomingCaptureFile = "";
172 options.m_ProfilingOptions.m_OutgoingCaptureFile = tempPath.string();
173 options.m_ProfilingOptions.m_CapturePeriod = 100;
174 options.m_ProfilingOptions.m_TimelineEnabled = true;
175
176 ILocalPacketHandlerSharedPtr localPacketHandlerPtr = std::make_shared<TestTimelinePacketHandler>();
177 options.m_ProfilingOptions.m_LocalPacketHandlers.push_back(localPacketHandlerPtr);
178
179 armnn::Runtime runtime(options);
180 // ensure the GUID generator is reset to zero
181 GetProfilingService(&runtime).ResetGuidGenerator();
182
183 // Load a simple network
184 // build up the structure of the network
185 INetworkPtr net(INetwork::Create());
186
187 IConnectableLayer* input = net->AddInputLayer(0, "input");
188
189 ElementwiseUnaryDescriptor descriptor(UnaryOperation::Rsqrt);
190 IConnectableLayer* Rsqrt = net->AddElementwiseUnaryLayer(descriptor, "Rsqrt");
191
192 IConnectableLayer* output = net->AddOutputLayer(0, "output");
193
194 input->GetOutputSlot(0).Connect(Rsqrt->GetInputSlot(0));
195 Rsqrt->GetOutputSlot(0).Connect(output->GetInputSlot(0));
196
197 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 4 }, DataType::Float32));
198 Rsqrt->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 4 }, DataType::Float32));
199
200
201 std::vector<BackendId> backendsVec{backend};
202 IOptimizedNetworkPtr optNet = Optimize(*net, backendsVec, runtime.GetDeviceSpec());
203
204 // Load it into the runtime. It should succeed.
205 armnn::NetworkId netId;
206 BOOST_TEST(runtime.LoadNetwork(netId, std::move(optNet)) == Status::Success);
207
208 // Creates structures for input & output.
209 std::vector<float> inputData(16);
210 std::vector<float> outputData(16);
211 for (unsigned int i = 0; i < 16; ++i) {
212 inputData[i] = 9.0;
213 outputData[i] = 3.0;
214 }
215
216 InputTensors inputTensors
217 {
218 {0, ConstTensor(runtime.GetInputTensorInfo(netId, 0), inputData.data())}
219 };
220 OutputTensors outputTensors
221 {
222 {0, Tensor(runtime.GetOutputTensorInfo(netId, 0), outputData.data())}
223 };
224
225 // Does the inference.
226 runtime.EnqueueWorkload(netId, inputTensors, outputTensors);
227
228 static_cast<TestTimelinePacketHandler *>(localPacketHandlerPtr.get())->WaitOnInferenceCompletion(3000);
229
230 // In order to flush the files we need to gracefully close the profiling service.
231 options.m_ProfilingOptions.m_EnableProfiling = false;
232 GetProfilingService(&runtime).ResetExternalProfilingOptions(options.m_ProfilingOptions, true);
233
234 // The output file size should be greater than 0.
235 BOOST_CHECK(fs::file_size(tempPath) > 0);
236
237 // NOTE: would be an interesting exercise to take this file and decode it
238
239 // Delete the tmp file.
240 BOOST_CHECK(fs::remove(tempPath));
Keith Davis3201eea2019-10-24 17:30:41 +0100241 }
Keith Davis3201eea2019-10-24 17:30:41 +0100242}
243
244BOOST_AUTO_TEST_SUITE_END()