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 #ifndef TENSORFLOW_LITE_PROFILING_PROFILER_H_ 16 #define TENSORFLOW_LITE_PROFILING_PROFILER_H_ 17 18 #include <vector> 19 20 #include "tensorflow/lite/profiling/profile_buffer.h" 21 22 #ifdef TFLITE_PROFILING_ENABLED 23 24 namespace tflite { 25 namespace profiling { 26 class ScopedProfile; 27 class ScopedOperatorProfile; 28 29 // Controls whether profiling is enabled or disabled and collects profiles. 30 // TFLite is used on platforms that don't have posix threads, so the profiler is 31 // kept as simple as possible. It is designed to be used only on a single 32 // thread. 33 // 34 // Profiles are collected using Scoped*Profile objects that begin and end a 35 // profile event. 36 // An example usage is shown in the example below: 37 // 38 // Say Worker class has a DoWork method and we are interested in profiling 39 // the overall execution time for DoWork and time spent in Task1 and Task2 40 // functions. 41 // 42 // class Worker { 43 // public: 44 // void DoWork() { 45 // ScopedProfile(&controller, "DoWork"); 46 // Task1(); 47 // Task2(); 48 // ..... 49 // } 50 // 51 // void Task1() { 52 // ScopedProfile(&controller, "Task1"); 53 // .... 54 // } 55 // 56 // void Task2() { 57 // ScopedProfile(&controller, "Task2"); 58 // } 59 // 60 // Profiler profiler; 61 // } 62 // 63 // We instrument the functions that need to be profiled. 64 // 65 // Profile can be collected by enable profiling and then getting profile 66 // events. 67 // 68 // void ProfileWorker() { 69 // Worker worker; 70 // worker.profiler.EnableProfiling(); 71 // worker.DoWork(); 72 // worker.profiler.DisableProfiling(); 73 // // Profiling is complete, extract profiles. 74 // auto profile_events = worker.profiler.GetProfiles(); 75 // } 76 // 77 // 78 class Profiler { 79 public: Profiler()80 Profiler() : buffer_(1024, false) {} 81 StartProfiling()82 void StartProfiling() { buffer_.SetEnabled(true); } StopProfiling()83 void StopProfiling() { buffer_.SetEnabled(false); } Reset()84 void Reset() { buffer_.Reset(); } GetProfileEvents()85 std::vector<const ProfileEvent*> GetProfileEvents() { 86 std::vector<const ProfileEvent*> profile_events; 87 profile_events.reserve(buffer_.Size()); 88 for (size_t i = 0; i < buffer_.Size(); i++) { 89 profile_events.push_back(buffer_.At(i)); 90 } 91 return profile_events; 92 } 93 94 private: 95 friend class ScopedProfile; 96 friend class ScopedOperatorProfile; GetProfileBuffer()97 ProfileBuffer* GetProfileBuffer() { return &buffer_; } 98 ProfileBuffer buffer_; 99 }; 100 101 class ScopedProfile { 102 public: 103 // Adds a profile event to profile that begins with the construction 104 // of object and ends when the object goes out of scope. 105 // The lifetime of tag should be at least the lifetime of profiler. 106 ScopedProfile(Profiler * profiler,const char * tag)107 ScopedProfile(Profiler* profiler, const char* tag) 108 : buffer_(nullptr), event_handle_(0) { 109 if (profiler) { 110 buffer_ = profiler->GetProfileBuffer(); 111 event_handle_ = 112 buffer_->BeginEvent(tag, ProfileEvent::EventType::DEFAULT, 0); 113 } 114 } ~ScopedProfile()115 ~ScopedProfile() { 116 if (buffer_) { 117 buffer_->EndEvent(event_handle_); 118 } 119 } 120 121 private: 122 ProfileBuffer* buffer_; 123 int32_t event_handle_; 124 }; 125 126 class ScopedOperatorProfile { 127 public: 128 // Adds a profile event to profile that begins with the construction 129 // of object and ends when the object goes out of scope. 130 // The lifetime of tag should be at least the lifetime of profiler. ScopedOperatorProfile(Profiler * profiler,const char * tag,int node_index)131 ScopedOperatorProfile(Profiler* profiler, const char* tag, int node_index) 132 : buffer_(nullptr), event_handle_(0) { 133 if (profiler) { 134 buffer_ = profiler->GetProfileBuffer(); 135 event_handle_ = buffer_->BeginEvent( 136 tag, ProfileEvent::EventType::OPERATOR_INVOKE_EVENT, node_index); 137 } 138 } 139 ~ScopedOperatorProfile()140 ~ScopedOperatorProfile() { 141 if (buffer_) { 142 buffer_->EndEvent(event_handle_); 143 } 144 } 145 146 private: 147 ProfileBuffer* buffer_; 148 int32_t event_handle_; 149 }; 150 151 } // namespace profiling 152 } // namespace tflite 153 154 #define VARNAME_UNIQ(name, ctr) name##ctr 155 156 #define SCOPED_TAGGED_OPERATOR_PROFILE(profiler, tag, node_index) \ 157 tflite::profiling::ScopedOperatorProfile VARNAME_UNIQ( \ 158 _profile_, __COUNTER__)((profiler), (tag), (node_index)) 159 #define SCOPED_OPERATOR_PROFILE(profiler, node_index) \ 160 SCOPED_TAGGED_OPERATOR_PROFILE((profiler), "OpInvoke", (node_index)) 161 #else 162 163 namespace tflite { 164 namespace profiling { 165 // A noop version of profiler when profiling is disabled. 166 class Profiler { 167 public: Profiler()168 Profiler() {} StartProfiling()169 void StartProfiling() {} StopProfiling()170 void StopProfiling() {} Reset()171 void Reset() {} GetProfileEvents()172 std::vector<const ProfileEvent*> GetProfileEvents() { return {}; } 173 }; 174 } // namespace profiling 175 } // namespace tflite 176 177 #define SCOPED_TAGGED_OPERATOR_PROFILE(profiler, tag, node_index) 178 #define SCOPED_OPERATOR_PROFILE(profiler, node_index) 179 180 #endif // TFLITE_PROFILING_ENABLED 181 182 #endif // TENSORFLOW_LITE_PROFILING_PROFILER_H_ 183