blob: 7d49a7d92a47f9d9916c4b75c0f0fa9aedf5776a [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 "PrintPacketHeaderHandler.hpp"
Jim Flynn3e9bc192022-03-23 23:01:26 +00007#include "ProfilingOptionsConverter.hpp"
8#include "ProfilingTestUtils.hpp"
Jim Flynn6398a982020-05-27 17:05:21 +01009#include <Runtime.hpp>
Jim Flynn4e755a52020-03-29 17:48:26 +010010#include "TestTimelinePacketHandler.hpp"
Keith Davis3201eea2019-10-24 17:30:41 +010011
Jim Flynn3e9bc192022-03-23 23:01:26 +000012#include <armnnUtils/Filesystem.hpp>
13
14#include <client/src/ProfilingService.hpp>
15
Sadik Armagan1625efc2021-06-10 18:24:34 +010016#include <doctest/doctest.h>
Keith Davis3201eea2019-10-24 17:30:41 +010017
Nikhil Raj77fe76b2021-06-09 14:55:32 +010018#include <common/include/LabelsAndEventClasses.hpp>
19
Keith Davis3201eea2019-10-24 17:30:41 +010020#include <cstdio>
Keith Davis3201eea2019-10-24 17:30:41 +010021#include <sstream>
22#include <sys/stat.h>
23
Cathal Corbett5aa9fd72022-02-25 15:33:28 +000024using namespace arm::pipe;
Keith Davis3201eea2019-10-24 17:30:41 +010025using namespace armnn;
26
27using namespace std::chrono_literals;
28
Finn Williams09ad6f92019-12-19 17:05:18 +000029class FileOnlyHelperService : public ProfilingService
30{
31 public:
32 // Wait for a notification from the send thread
33 bool WaitForPacketsSent(uint32_t timeout = 1000)
34 {
Sadik Armagan3184c902020-03-18 10:57:30 +000035 return ProfilingService::WaitForPacketSent(m_ProfilingService, timeout);
Finn Williams09ad6f92019-12-19 17:05:18 +000036 }
Cathal Corbett5aa9fd72022-02-25 15:33:28 +000037 ProfilingService m_ProfilingService;
Finn Williams09ad6f92019-12-19 17:05:18 +000038};
39
Sadik Armagan1625efc2021-06-10 18:24:34 +010040TEST_SUITE("FileOnlyProfilingDecoratorTests")
41{
42TEST_CASE("TestFileOnlyProfiling")
Jim Flynn4e755a52020-03-29 17:48:26 +010043{
Jan Eilersf78c7672020-07-01 18:09:39 +010044 // Get all registered backends
45 std::vector<BackendId> suitableBackends = GetSuitableBackendRegistered();
46
47 // Run test for each backend separately
48 for (auto const& backend : suitableBackends)
Finn Williams0c32ccf2020-05-12 13:37:06 +010049 {
Jan Eilersf78c7672020-07-01 18:09:39 +010050 // Enable m_FileOnly but also provide ILocalPacketHandler which should consume the packets.
51 // This won't dump anything to file.
Kevin Mayd92a6e42021-02-04 10:27:41 +000052 armnn::IRuntime::CreationOptions creationOptions;
Jan Eilersf78c7672020-07-01 18:09:39 +010053 creationOptions.m_ProfilingOptions.m_EnableProfiling = true;
54 creationOptions.m_ProfilingOptions.m_FileOnly = true;
55 creationOptions.m_ProfilingOptions.m_CapturePeriod = 100;
56 creationOptions.m_ProfilingOptions.m_TimelineEnabled = true;
57 ILocalPacketHandlerSharedPtr localPacketHandlerPtr = std::make_shared<TestTimelinePacketHandler>();
58 creationOptions.m_ProfilingOptions.m_LocalPacketHandlers.push_back(localPacketHandlerPtr);
59
Kevin Mayd92a6e42021-02-04 10:27:41 +000060 armnn::RuntimeImpl runtime(creationOptions);
Jan Eilersf78c7672020-07-01 18:09:39 +010061 // ensure the GUID generator is reset to zero
62 GetProfilingService(&runtime).ResetGuidGenerator();
63
64 // Load a simple network
65 // build up the structure of the network
66 INetworkPtr net(INetwork::Create());
67
68 IConnectableLayer* input = net->AddInputLayer(0, "input");
69
70 ElementwiseUnaryDescriptor descriptor(UnaryOperation::Rsqrt);
71 IConnectableLayer* Rsqrt = net->AddElementwiseUnaryLayer(descriptor, "Rsqrt");
72
73 IConnectableLayer* output = net->AddOutputLayer(0, "output");
74
75 input->GetOutputSlot(0).Connect(Rsqrt->GetInputSlot(0));
76 Rsqrt->GetOutputSlot(0).Connect(output->GetInputSlot(0));
77
78 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 4 }, DataType::Float32));
79 Rsqrt->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 4 }, DataType::Float32));
80
81 std::vector<armnn::BackendId> backendsVec {backend};
82 IOptimizedNetworkPtr optNet = Optimize(*net, backendsVec, runtime.GetDeviceSpec());
83
84 // Load it into the runtime. It should succeed.
85 armnn::NetworkId netId;
Sadik Armagan1625efc2021-06-10 18:24:34 +010086 CHECK(runtime.LoadNetwork(netId, std::move(optNet)) == Status::Success);
Jan Eilersf78c7672020-07-01 18:09:39 +010087
88 // Creates structures for input & output.
89 std::vector<float> inputData(16);
90 std::vector<float> outputData(16);
91 for (unsigned int i = 0; i < 16; ++i) {
92 inputData[i] = 9.0;
93 outputData[i] = 3.0;
94 }
95
Cathal Corbett5b8093c2021-10-22 11:12:07 +010096 TensorInfo inputTensorInfo = runtime.GetInputTensorInfo(netId, 0);
97 inputTensorInfo.SetConstant(true);
Jan Eilersf78c7672020-07-01 18:09:39 +010098 InputTensors inputTensors
99 {
Cathal Corbett5b8093c2021-10-22 11:12:07 +0100100 {0, ConstTensor(inputTensorInfo, inputData.data())}
Jan Eilersf78c7672020-07-01 18:09:39 +0100101 };
102 OutputTensors outputTensors
103 {
104 {0, Tensor(runtime.GetOutputTensorInfo(netId, 0), outputData.data())}
105 };
106
107 // Does the inference.
108 runtime.EnqueueWorkload(netId, inputTensors, outputTensors);
109
110 static_cast<TestTimelinePacketHandler *>(localPacketHandlerPtr.get())->WaitOnInferenceCompletion(3000);
111
112 const TimelineModel &model =
113 static_cast<TestTimelinePacketHandler *>(localPacketHandlerPtr.get())->GetTimelineModel();
114
115 for (auto &error : model.GetErrors()) {
116 std::cout << error.what() << std::endl;
117 }
Sadik Armagan1625efc2021-06-10 18:24:34 +0100118 CHECK(model.GetErrors().empty());
Jan Eilersf78c7672020-07-01 18:09:39 +0100119 std::vector<std::string> desc = GetModelDescription(model);
120 std::vector<std::string> expectedOutput;
121 expectedOutput.push_back("Entity [0] name = input type = layer");
Jim Flynnf7713212020-07-14 09:50:59 +0100122 expectedOutput.push_back(" connection [17] from entity [0] to entity [1]");
123 expectedOutput.push_back(" child: Entity [26] backendId = " + backend.Get() + " type = workload");
Jan Eilersf78c7672020-07-01 18:09:39 +0100124 expectedOutput.push_back("Entity [1] name = Rsqrt type = layer");
Jim Flynnf7713212020-07-14 09:50:59 +0100125 expectedOutput.push_back(" connection [25] from entity [1] to entity [2]");
126 expectedOutput.push_back(" child: Entity [18] backendId = " + backend.Get() + " type = workload");
Jan Eilersf78c7672020-07-01 18:09:39 +0100127 expectedOutput.push_back("Entity [2] name = output type = layer");
Jim Flynnf7713212020-07-14 09:50:59 +0100128 expectedOutput.push_back(" child: Entity [30] backendId = " + backend.Get() + " type = workload");
129 expectedOutput.push_back("Entity [6] processId = [processId] type = network");
Jan Eilersf78c7672020-07-01 18:09:39 +0100130 expectedOutput.push_back(" child: Entity [0] name = input type = layer");
131 expectedOutput.push_back(" child: Entity [1] name = Rsqrt type = layer");
132 expectedOutput.push_back(" child: Entity [2] name = output type = layer");
Jim Flynnf7713212020-07-14 09:50:59 +0100133 expectedOutput.push_back(" execution: Entity [34] type = inference");
134 expectedOutput.push_back(" event: [8] class [start_of_life]");
135 expectedOutput.push_back("Entity [18] backendId = " + backend.Get() + " type = workload");
136 expectedOutput.push_back(" execution: Entity [47] type = workload_execution");
137 expectedOutput.push_back("Entity [26] backendId = " + backend.Get() + " type = workload");
138 expectedOutput.push_back(" execution: Entity [39] type = workload_execution");
139 expectedOutput.push_back("Entity [30] backendId = " + backend.Get() + " type = workload");
140 expectedOutput.push_back(" execution: Entity [55] type = workload_execution");
141 expectedOutput.push_back("Entity [34] type = inference");
142 expectedOutput.push_back(" child: Entity [39] type = workload_execution");
143 expectedOutput.push_back(" child: Entity [47] type = workload_execution");
144 expectedOutput.push_back(" child: Entity [55] type = workload_execution");
145 expectedOutput.push_back(" event: [37] class [start_of_life]");
146 expectedOutput.push_back(" event: [63] class [end_of_life]");
147 expectedOutput.push_back("Entity [39] type = workload_execution");
148 expectedOutput.push_back(" event: [43] class [start_of_life]");
149 expectedOutput.push_back(" event: [45] class [end_of_life]");
150 expectedOutput.push_back("Entity [47] type = workload_execution");
151 expectedOutput.push_back(" event: [51] class [start_of_life]");
152 expectedOutput.push_back(" event: [53] class [end_of_life]");
153 expectedOutput.push_back("Entity [55] type = workload_execution");
154 expectedOutput.push_back(" event: [59] class [start_of_life]");
155 expectedOutput.push_back(" event: [61] class [end_of_life]");
Sadik Armagan1625efc2021-06-10 18:24:34 +0100156 CHECK(CompareOutput(desc, expectedOutput));
Finn Williams0c32ccf2020-05-12 13:37:06 +0100157 }
Jim Flynn4e755a52020-03-29 17:48:26 +0100158}
159
Sadik Armagan1625efc2021-06-10 18:24:34 +0100160TEST_CASE("DumpOutgoingValidFileEndToEnd")
Keith Davis3201eea2019-10-24 17:30:41 +0100161{
Jan Eilersf78c7672020-07-01 18:09:39 +0100162 // Get all registered backends
163 std::vector<BackendId> suitableBackends = GetSuitableBackendRegistered();
164
165 // Run test for each backend separately
166 for (auto const& backend : suitableBackends)
Keith Davis3201eea2019-10-24 17:30:41 +0100167 {
Jan Eilersf78c7672020-07-01 18:09:39 +0100168 // Create a temporary file name.
169 fs::path tempPath = armnnUtils::Filesystem::NamedTempFile("DumpOutgoingValidFileEndToEnd_CaptureFile.txt");
170 // Make sure the file does not exist at this point
Sadik Armagan1625efc2021-06-10 18:24:34 +0100171 CHECK(!fs::exists(tempPath));
Jan Eilersf78c7672020-07-01 18:09:39 +0100172
Kevin Mayd92a6e42021-02-04 10:27:41 +0000173 armnn::IRuntime::CreationOptions options;
Jan Eilersf78c7672020-07-01 18:09:39 +0100174 options.m_ProfilingOptions.m_EnableProfiling = true;
175 options.m_ProfilingOptions.m_FileOnly = true;
176 options.m_ProfilingOptions.m_IncomingCaptureFile = "";
177 options.m_ProfilingOptions.m_OutgoingCaptureFile = tempPath.string();
178 options.m_ProfilingOptions.m_CapturePeriod = 100;
179 options.m_ProfilingOptions.m_TimelineEnabled = true;
180
181 ILocalPacketHandlerSharedPtr localPacketHandlerPtr = std::make_shared<TestTimelinePacketHandler>();
182 options.m_ProfilingOptions.m_LocalPacketHandlers.push_back(localPacketHandlerPtr);
183
Kevin Mayd92a6e42021-02-04 10:27:41 +0000184 armnn::RuntimeImpl runtime(options);
Jan Eilersf78c7672020-07-01 18:09:39 +0100185 // ensure the GUID generator is reset to zero
186 GetProfilingService(&runtime).ResetGuidGenerator();
187
188 // Load a simple network
189 // build up the structure of the network
190 INetworkPtr net(INetwork::Create());
191
192 IConnectableLayer* input = net->AddInputLayer(0, "input");
193
194 ElementwiseUnaryDescriptor descriptor(UnaryOperation::Rsqrt);
195 IConnectableLayer* Rsqrt = net->AddElementwiseUnaryLayer(descriptor, "Rsqrt");
196
197 IConnectableLayer* output = net->AddOutputLayer(0, "output");
198
199 input->GetOutputSlot(0).Connect(Rsqrt->GetInputSlot(0));
200 Rsqrt->GetOutputSlot(0).Connect(output->GetInputSlot(0));
201
202 input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 4 }, DataType::Float32));
203 Rsqrt->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 4 }, DataType::Float32));
204
205
206 std::vector<BackendId> backendsVec{backend};
207 IOptimizedNetworkPtr optNet = Optimize(*net, backendsVec, runtime.GetDeviceSpec());
208
209 // Load it into the runtime. It should succeed.
210 armnn::NetworkId netId;
Sadik Armagan1625efc2021-06-10 18:24:34 +0100211 CHECK(runtime.LoadNetwork(netId, std::move(optNet)) == Status::Success);
Jan Eilersf78c7672020-07-01 18:09:39 +0100212
213 // Creates structures for input & output.
214 std::vector<float> inputData(16);
215 std::vector<float> outputData(16);
216 for (unsigned int i = 0; i < 16; ++i) {
217 inputData[i] = 9.0;
218 outputData[i] = 3.0;
219 }
220
Cathal Corbett5b8093c2021-10-22 11:12:07 +0100221 TensorInfo inputTensorInfo = runtime.GetInputTensorInfo(netId, 0);
222 inputTensorInfo.SetConstant(true);
Jan Eilersf78c7672020-07-01 18:09:39 +0100223 InputTensors inputTensors
224 {
Cathal Corbett5b8093c2021-10-22 11:12:07 +0100225 {0, ConstTensor(inputTensorInfo, inputData.data())}
Jan Eilersf78c7672020-07-01 18:09:39 +0100226 };
227 OutputTensors outputTensors
228 {
229 {0, Tensor(runtime.GetOutputTensorInfo(netId, 0), outputData.data())}
230 };
231
232 // Does the inference.
233 runtime.EnqueueWorkload(netId, inputTensors, outputTensors);
234
235 static_cast<TestTimelinePacketHandler *>(localPacketHandlerPtr.get())->WaitOnInferenceCompletion(3000);
236
237 // In order to flush the files we need to gracefully close the profiling service.
238 options.m_ProfilingOptions.m_EnableProfiling = false;
Jim Flynn4c9ed1d2022-01-23 23:57:20 +0000239 GetProfilingService(&runtime).ResetExternalProfilingOptions(
240 ConvertExternalProfilingOptions(options.m_ProfilingOptions), true);
Jan Eilersf78c7672020-07-01 18:09:39 +0100241
242 // The output file size should be greater than 0.
Sadik Armagan1625efc2021-06-10 18:24:34 +0100243 CHECK(fs::file_size(tempPath) > 0);
Jan Eilersf78c7672020-07-01 18:09:39 +0100244
245 // NOTE: would be an interesting exercise to take this file and decode it
246
247 // Delete the tmp file.
Sadik Armagan1625efc2021-06-10 18:24:34 +0100248 CHECK(fs::remove(tempPath));
Keith Davis3201eea2019-10-24 17:30:41 +0100249 }
Keith Davis3201eea2019-10-24 17:30:41 +0100250}
251
Sadik Armagan1625efc2021-06-10 18:24:34 +0100252}