Release 18.08
[platform/upstream/armnn.git] / src / armnn / test / ProfilerTests.cpp
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // See LICENSE file in the project root for full license information.
4 //
5
6 #include <boost/test/unit_test.hpp>
7 #include <boost/test/output_test_stream.hpp>
8 #include <boost/algorithm/string.hpp>
9
10 #include <memory>
11 #include <thread>
12
13 #include <armnn/TypesUtils.hpp>
14 #include <Profiling.hpp>
15
16 namespace armnn
17 {
18
19 size_t GetProfilerEventSequenceSize(armnn::Profiler* profiler)
20 {
21     if (!profiler)
22     {
23         return static_cast<size_t>(-1);
24     }
25
26     return profiler->m_EventSequence.size();
27 }
28 } // namespace armnn
29
30 namespace
31 {
32
33 void RegisterUnregisterProfilerSingleThreadImpl()
34 {
35     // Important! Regular assertions must be used in this function for testing (rather than
36     // BOOST_TEST macros) otherwise multi-threading tests would randomly fail.
37
38     // Get a reference to the profiler manager.
39     armnn::ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
40
41     // Check that there's no profiler registered for this thread.
42     assert(!profilerManager.GetProfiler());
43
44     // Create and register a profiler for this thread.
45     std::unique_ptr<armnn::Profiler> profiler = std::make_unique<armnn::Profiler>();
46     profilerManager.RegisterProfiler(profiler.get());
47
48     // Check that on a single thread we get the same profiler we registered.
49     assert(profiler.get() == profilerManager.GetProfiler());
50
51     // Destroy the profiler.
52     profiler.reset();
53
54     // Check that the profiler has been un-registered for this thread.
55     assert(!profilerManager.GetProfiler());
56 }
57
58 } // namespace
59
60 BOOST_AUTO_TEST_SUITE(Profiler)
61
62 BOOST_AUTO_TEST_CASE(EnableDisableProfiling)
63 {
64     std::unique_ptr<armnn::Profiler> profiler = std::make_unique<armnn::Profiler>();
65
66     // Check that profiling is disabled by default.
67     BOOST_TEST(!profiler->IsProfilingEnabled());
68
69     // Enable profiling.
70     profiler->EnableProfiling(true);
71
72     // Check that profiling is enabled.
73     BOOST_TEST(profiler->IsProfilingEnabled());
74
75     // Disable profiling.
76     profiler->EnableProfiling(false);
77
78     // Check that profiling is disabled.
79     BOOST_TEST(!profiler->IsProfilingEnabled());
80 }
81
82 BOOST_AUTO_TEST_CASE(RegisterUnregisterProfilerSingleThread)
83 {
84     RegisterUnregisterProfilerSingleThreadImpl();
85 }
86
87 BOOST_AUTO_TEST_CASE(RegisterUnregisterProfilerMultipleThreads)
88 {
89     std::thread thread1([]() { RegisterUnregisterProfilerSingleThreadImpl(); });
90     std::thread thread2([]() { RegisterUnregisterProfilerSingleThreadImpl(); });
91     std::thread thread3([]() { RegisterUnregisterProfilerSingleThreadImpl(); });
92
93     thread1.join();
94     thread2.join();
95     thread3.join();
96 }
97
98 BOOST_AUTO_TEST_CASE(ProfilingMacros)
99 {
100     // Get a reference to the profiler manager.
101     armnn::ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
102
103     { // --- No profiler ---
104
105         // Check that there's no profiler registered for this thread.
106         BOOST_TEST(!profilerManager.GetProfiler());
107
108         // Test scoped event.
109         { ARMNN_SCOPED_PROFILING_EVENT(armnn::Compute::CpuAcc, "test"); }
110
111         // Check that we still cannot get a profiler for this thread.
112         BOOST_TEST(!profilerManager.GetProfiler());
113     }
114
115     // Create and register a profiler for this thread.
116     std::unique_ptr<armnn::Profiler> profiler = std::make_unique<armnn::Profiler>();
117     profilerManager.RegisterProfiler(profiler.get());
118
119     { // --- Profiler, but profiling disabled ---
120
121         // Get current event sequence size.
122         size_t eventSequenceSizeBefore = armnn::GetProfilerEventSequenceSize(profiler.get());
123
124         // Test scoped macro.
125         { ARMNN_SCOPED_PROFILING_EVENT(armnn::Compute::CpuAcc, "test"); }
126
127         // Check that no profiling event has been added to the sequence.
128         size_t eventSequenceSizeAfter = armnn::GetProfilerEventSequenceSize(profiler.get());
129         BOOST_TEST(eventSequenceSizeBefore == eventSequenceSizeAfter);
130     }
131
132     // Enable profiling.
133     profiler->EnableProfiling(true);
134
135     { // --- Profiler, and profiling enabled ---
136
137         // Get current event sequence size.
138         size_t eventSequenceSizeBefore = armnn::GetProfilerEventSequenceSize(profiler.get());
139
140         // Test scoped macro.
141         { ARMNN_SCOPED_PROFILING_EVENT(armnn::Compute::CpuAcc, "test"); }
142
143         // Check that a profiling event has been added to the sequence.
144         size_t eventSequenceSizeAfter = armnn::GetProfilerEventSequenceSize(profiler.get());
145         BOOST_TEST(eventSequenceSizeAfter == eventSequenceSizeBefore + 1);
146     }
147
148     // Disable profiling here to not print out anything on stdout.
149     profiler->EnableProfiling(false);
150 }
151
152 BOOST_AUTO_TEST_CASE(RuntimeLoadNetwork)
153 {
154     // Get a reference to the profiler manager.
155     armnn::ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
156
157     // Check that there's no profiler registered for this thread.
158     BOOST_TEST(!profilerManager.GetProfiler());
159
160     // Build a mock-network and load it into the runtime.
161     armnn::IRuntime::CreationOptions options;
162     armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options));
163     armnn::NetworkId networkIdentifier = 1;
164     armnn::INetworkPtr mockNetwork(armnn::INetwork::Create());
165     mockNetwork->AddInputLayer(0, "test layer");
166     std::vector<armnn::Compute> backends = { armnn::Compute::CpuRef };
167     runtime->LoadNetwork(networkIdentifier, armnn::Optimize(*mockNetwork, backends, runtime->GetDeviceSpec()));
168
169     // Check that now there's a profiler registered for this thread (created and registered by the loading the network).
170     BOOST_TEST(profilerManager.GetProfiler());
171
172     // Unload the network.
173     runtime->UnloadNetwork(networkIdentifier);
174
175     // Check that the profiler has been un-registered for this thread.
176     BOOST_TEST(!profilerManager.GetProfiler());
177 }
178
179 BOOST_AUTO_TEST_CASE(WriteEventResults)
180 {
181     // Get a reference to the profiler manager.
182     armnn::ProfilerManager& profileManager = armnn::ProfilerManager::GetInstance();
183
184     // Create and register a profiler for this thread.
185     std::unique_ptr<armnn::Profiler> profiler = std::make_unique<armnn::Profiler>();
186     profileManager.RegisterProfiler(profiler.get());
187
188     // Enable profiling.
189     profiler->EnableProfiling(true);
190
191     { // --- Profiler, and profiling enabled ---
192
193         // Get current event sequence size.
194         size_t eventSequenceSizeBefore = armnn::GetProfilerEventSequenceSize(profiler.get());
195
196         // Test scoped macro.
197         {
198             // Need to directly create a ScopedProfilingEvent as the one created by the macro falls out of scope
199             // immediately causing the Event.Stop() function method to be called immediately after the Event.Start()
200             // function resulting in periodic test failures on the Dent and Smith HiKeys
201             armnn::ScopedProfilingEvent testEvent(armnn::Compute::CpuAcc, "test", armnn::WallClockTimer());
202             std::this_thread::sleep_for(std::chrono::milliseconds(10));
203         }
204
205         // Check that a profiling event has been added to the sequence.
206         size_t eventSequenceSizeAfter = armnn::GetProfilerEventSequenceSize(profiler.get());
207         BOOST_TEST(eventSequenceSizeAfter == eventSequenceSizeBefore + 1);
208
209         boost::test_tools::output_test_stream output;
210         profiler->AnalyzeEventsAndWriteResults(output);
211         BOOST_TEST(!output.is_empty(false));
212
213         // output should contain event name 'test'
214         BOOST_CHECK(boost::contains(output.str(), "test"));
215
216         // output should contain headers
217         BOOST_CHECK(boost::contains(output.str(), "Event Sequence - Name"));
218         BOOST_CHECK(boost::contains(output.str(), "Event Stats - Name"));
219         BOOST_CHECK(boost::contains(output.str(), "Total"));
220         BOOST_CHECK(boost::contains(output.str(), "Device"));
221         // output should contain compute device 'CpuAcc'
222         BOOST_CHECK(boost::contains(output.str(), "CpuAcc"));
223         // output should not contain un-readable numbers
224         BOOST_CHECK(!(boost::contains(output.str(), "e+")));
225         // output should not contain un-readable numbers
226         BOOST_CHECK(!(boost::contains(output.str(), "+")));
227         // output should not contain zero value
228         BOOST_CHECK(!(boost::contains(output.str(), " 0 ")));
229     }
230
231     // Disable profiling here to not print out anything on stdout.
232     profiler->EnableProfiling(false);
233 }
234
235 BOOST_AUTO_TEST_SUITE_END()