1 /* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 #include "tensorflow/lite/profiling/profiler.h"
16
17 #include <unistd.h>
18
19 #include <chrono> // NOLINT(build/c++11)
20 #include <cmath>
21 #include <thread> // NOLINT(build/c++11)
22
23 #include <gmock/gmock.h>
24 #include <gtest/gtest.h>
25
26 namespace tflite {
27 namespace profiling {
28 namespace {
29
GetDurationOfEventMs(const ProfileEvent * event)30 double GetDurationOfEventMs(const ProfileEvent* event) {
31 return (event->elapsed_time) / 1e3;
32 }
33
SleepForQuarterSecond(tflite::Profiler * profiler)34 void SleepForQuarterSecond(tflite::Profiler* profiler) {
35 ScopedProfile profile(profiler, "SleepForQuarter");
36 std::this_thread::sleep_for(std::chrono::milliseconds(250));
37 }
38
ChildFunction(tflite::Profiler * profiler)39 void ChildFunction(tflite::Profiler* profiler) {
40 ScopedProfile profile(profiler, "Child");
41 SleepForQuarterSecond(profiler);
42 }
43
ParentFunction(tflite::Profiler * profiler)44 void ParentFunction(tflite::Profiler* profiler) {
45 ScopedProfile profile(profiler, "Parent");
46 for (int i = 0; i < 2; i++) {
47 ChildFunction(profiler);
48 }
49 }
50
TEST(ProfilerTest,NoProfilesAreCollectedWhenDisabled)51 TEST(ProfilerTest, NoProfilesAreCollectedWhenDisabled) {
52 BufferedProfiler profiler(1024);
53 ParentFunction(&profiler);
54 auto profile_events = profiler.GetProfileEvents();
55 EXPECT_EQ(0, profile_events.size());
56 }
57
TEST(ProfilerTest,NoProfilesAreCollectedWhenEventTypeUnsupported)58 TEST(ProfilerTest, NoProfilesAreCollectedWhenEventTypeUnsupported) {
59 BufferedProfiler profiler(1024);
60 tflite::Profiler* p = &profiler;
61 p->AddEvent("Hello",
62 Profiler::EventType::GENERAL_RUNTIME_INSTRUMENTATION_EVENT,
63 /*elaped_time*/ 1,
64 /*event_metadata*/ 2);
65 auto handler = p->BeginEvent(
66 "begin", Profiler::EventType::GENERAL_RUNTIME_INSTRUMENTATION_EVENT, 0);
67 p->EndEvent(handler);
68 auto profile_events = profiler.GetProfileEvents();
69 EXPECT_EQ(0, profile_events.size());
70 }
71
TEST(ProfilingTest,ProfilesAreCollected)72 TEST(ProfilingTest, ProfilesAreCollected) {
73 BufferedProfiler profiler(1024);
74 profiler.StartProfiling();
75 ParentFunction(&profiler);
76 profiler.StopProfiling();
77 auto profile_events = profiler.GetProfileEvents();
78 // ParentFunction calls the ChildFunction 2 times.
79 // Each ChildFunction calls SleepForQuarterSecond once.
80 // We expect 1 entry for ParentFunction, 2 for ChildFunction and 2 for
81 // SleepForQuarterSecond: Total: 1+ 2 + 2 = 5
82 // Profiles should look like:
83 // Parent ~ 500 ms (due to 2 Child calls)
84 // - Child ~ 250 ms (due to SleepForQuarter calls)
85 // - SleepForQuarter ~ 250ms
86 // - Child ~ 250 ms (due to SleepForQuarter calls)
87 // - SleepForQuarter ~ 250ms
88 //
89 ASSERT_EQ(5, profile_events.size());
90 EXPECT_EQ("Parent", profile_events[0]->tag);
91 EXPECT_EQ("Child", profile_events[1]->tag);
92 EXPECT_EQ("SleepForQuarter", profile_events[2]->tag);
93 EXPECT_EQ("Child", profile_events[3]->tag);
94 EXPECT_EQ("SleepForQuarter", profile_events[4]->tag);
95
96 #ifndef ADDRESS_SANITIZER
97 // ASAN build is sometimes very slow. Set a large epsilon to avoid flakiness.
98 // Due to flakiness, just verify relative values match.
99 const int eps_ms = 50;
100 auto parent_ms = GetDurationOfEventMs(profile_events[0]);
101 double child_ms[2], sleep_for_quarter_ms[2];
102 child_ms[0] = GetDurationOfEventMs(profile_events[1]);
103 child_ms[1] = GetDurationOfEventMs(profile_events[3]);
104 sleep_for_quarter_ms[0] = GetDurationOfEventMs(profile_events[2]);
105 sleep_for_quarter_ms[1] = GetDurationOfEventMs(profile_events[4]);
106 EXPECT_NEAR(parent_ms, child_ms[0] + child_ms[1], eps_ms);
107 EXPECT_NEAR(child_ms[0], sleep_for_quarter_ms[0], eps_ms);
108 EXPECT_NEAR(child_ms[1], sleep_for_quarter_ms[1], eps_ms);
109 #endif
110 }
111
TEST(ProfilingTest,NullProfiler)112 TEST(ProfilingTest, NullProfiler) {
113 Profiler* profiler = nullptr;
114 { SCOPED_TAGGED_OPERATOR_PROFILE(profiler, "noop", 1); }
115 }
116
TEST(ProfilingTest,ScopedProfile)117 TEST(ProfilingTest, ScopedProfile) {
118 BufferedProfiler profiler(1024);
119 profiler.StartProfiling();
120 { SCOPED_TAGGED_OPERATOR_PROFILE(&profiler, "noop", 1); }
121 profiler.StopProfiling();
122 auto profile_events = profiler.GetProfileEvents();
123 EXPECT_EQ(1, profile_events.size());
124 }
125
TEST(ProfilingTest,NoopProfiler)126 TEST(ProfilingTest, NoopProfiler) {
127 NoopProfiler profiler;
128 profiler.StartProfiling();
129 { SCOPED_TAGGED_OPERATOR_PROFILE(&profiler, "noop", 1); }
130 profiler.StopProfiling();
131 auto profile_events = profiler.GetProfileEvents();
132 EXPECT_EQ(0, profile_events.size());
133 }
134
135 } // namespace
136 } // namespace profiling
137 } // namespace tflite
138