ArmNN
 21.08
FileOnlyProfilingDecoratorTests.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2019 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
7 #include <ProfilingService.hpp>
8 #include "ProfilingTestUtils.hpp"
10 #include <Runtime.hpp>
12 
13 #include <doctest/doctest.h>
14 
15 #include <common/include/LabelsAndEventClasses.hpp>
16 
17 #include <cstdio>
18 #include <sstream>
19 #include <sys/stat.h>
20 
21 using namespace armnn::profiling;
22 using namespace armnn;
23 
24 using namespace std::chrono_literals;
25 
26 class FileOnlyHelperService : public ProfilingService
27 {
28  public:
29  // Wait for a notification from the send thread
30  bool WaitForPacketsSent(uint32_t timeout = 1000)
31  {
32  return ProfilingService::WaitForPacketSent(m_ProfilingService, timeout);
33  }
34  armnn::profiling::ProfilingService m_ProfilingService;
35 };
36 
37 TEST_SUITE("FileOnlyProfilingDecoratorTests")
38 {
39 TEST_CASE("TestFileOnlyProfiling")
40 {
41  // Get all registered backends
42  std::vector<BackendId> suitableBackends = GetSuitableBackendRegistered();
43 
44  // Run test for each backend separately
45  for (auto const& backend : suitableBackends)
46  {
47  // Enable m_FileOnly but also provide ILocalPacketHandler which should consume the packets.
48  // This won't dump anything to file.
49  armnn::IRuntime::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::RuntimeImpl runtime(creationOptions);
58  // ensure the GUID generator is reset to zero
60 
61  // Load a simple network
62  // build up the structure of the network
64 
65  IConnectableLayer* input = net->AddInputLayer(0, "input");
66 
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  CHECK(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  CHECK(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");
117  expectedOutput.push_back(" connection [17] from entity [0] to entity [1]");
118  expectedOutput.push_back(" child: Entity [26] backendId = " + backend.Get() + " type = workload");
119  expectedOutput.push_back("Entity [1] name = Rsqrt type = layer");
120  expectedOutput.push_back(" connection [25] from entity [1] to entity [2]");
121  expectedOutput.push_back(" child: Entity [18] backendId = " + backend.Get() + " type = workload");
122  expectedOutput.push_back("Entity [2] name = output type = layer");
123  expectedOutput.push_back(" child: Entity [30] backendId = " + backend.Get() + " type = workload");
124  expectedOutput.push_back("Entity [6] processId = [processId] type = network");
125  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");
128  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]");
151  CHECK(CompareOutput(desc, expectedOutput));
152  }
153 }
154 
155 TEST_CASE("DumpOutgoingValidFileEndToEnd")
156 {
157  // Get all registered backends
158  std::vector<BackendId> suitableBackends = GetSuitableBackendRegistered();
159 
160  // Run test for each backend separately
161  for (auto const& backend : suitableBackends)
162  {
163  // 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  CHECK(!fs::exists(tempPath));
167 
169  options.m_ProfilingOptions.m_EnableProfiling = true;
170  options.m_ProfilingOptions.m_FileOnly = true;
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::RuntimeImpl runtime(options);
180  // ensure the GUID generator is reset to zero
182 
183  // Load a simple network
184  // build up the structure of the network
186 
187  IConnectableLayer* input = net->AddInputLayer(0, "input");
188 
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  CHECK(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;
233 
234  // The output file size should be greater than 0.
235  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  CHECK(fs::remove(tempPath));
241  }
242 }
243 
244 }
TEST_SUITE("TestConstTensorLayerVisitor")
profiling::ProfilingService & GetProfilingService(armnn::RuntimeImpl *runtime)
Definition: TestUtils.cpp:35
TensorInfo GetInputTensorInfo(NetworkId networkId, LayerBindingId layerId) const
Definition: Runtime.cpp:469
std::shared_ptr< ILocalPacketHandler > ILocalPacketHandlerSharedPtr
Interface for a layer that is connectable to other layers via InputSlots and OutputSlots.
Definition: INetwork.hpp:61
Status LoadNetwork(NetworkId &networkIdOut, IOptimizedNetworkPtr network)
Loads a complete network into the Runtime.
Definition: Runtime.cpp:123
std::vector< std::pair< LayerBindingId, class ConstTensor > > InputTensors
Definition: Tensor.hpp:360
TensorInfo GetOutputTensorInfo(NetworkId networkId, LayerBindingId layerId) const
Definition: Runtime.cpp:474
const std::vector< arm::pipe::ProfilingException > & GetErrors() const
Copyright (c) 2021 ARM Limited and Contributors.
Status EnqueueWorkload(NetworkId networkId, const InputTensors &inputTensors, const OutputTensors &outputTensors)
Definition: Runtime.cpp:480
std::vector< BackendId > GetSuitableBackendRegistered()
Returns a vector of CpuRef, CpuAcc or GpuAcc backends if they where registered.
virtual void SetTensorInfo(const TensorInfo &tensorInfo)=0
bool WaitForPacketSent(ProfilingService &instance, uint32_t timeout=1000)
A tensor defined by a TensorInfo (shape and data type) and a mutable backing store.
Definition: Tensor.hpp:319
std::vector< armnn::profiling::ILocalPacketHandlerSharedPtr > m_LocalPacketHandlers
Definition: IRuntime.hpp:158
IOptimizedNetworkPtr Optimize(const INetwork &network, const std::vector< BackendId > &backendPreferences, const IDeviceSpec &deviceSpec, const OptimizerOptions &options=OptimizerOptions(), Optional< std::vector< std::string > &> messages=EmptyOptional())
Create an optimized version of the network.
Definition: Network.cpp:1613
bool CompareOutput(std::vector< std::string > output, std::vector< std::string > expectedOutput)
const IDeviceSpec & GetDeviceSpec() const
Definition: Runtime.hpp:78
int NetworkId
Definition: IRuntime.hpp:24
A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
Definition: Tensor.hpp:327
std::vector< std::pair< LayerBindingId, class Tensor > > OutputTensors
Definition: Tensor.hpp:361
std::unique_ptr< IOptimizedNetwork, void(*)(IOptimizedNetwork *network)> IOptimizedNetworkPtr
Definition: INetwork.hpp:173
void ResetExternalProfilingOptions(const ExternalProfilingOptions &options, bool resetProfilingService=false)
A ElementwiseUnaryDescriptor for the ElementwiseUnaryLayer.
Definition: Descriptors.hpp:98
std::vector< std::string > GetModelDescription(const TimelineModel &model)
virtual const IInputSlot & GetInputSlot(unsigned int index) const =0
Get a const input slot handle by slot index.
virtual const IOutputSlot & GetOutputSlot(unsigned int index) const =0
Get the const output slot handle by slot index.
fs::path NamedTempFile(const char *fileName)
Returns a path to a file in the system temporary folder. If the file existed it will be deleted...
Definition: Filesystem.cpp:23
std::unique_ptr< INetwork, void(*)(INetwork *network)> INetworkPtr
Definition: INetwork.hpp:172
virtual int Connect(IInputSlot &destination)=0
ExternalProfilingOptions m_ProfilingOptions
Definition: IRuntime.hpp:160
static INetworkPtr Create(NetworkOptions networkOptions={})
Definition: Network.cpp:530