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_PROFILE_BUFFER_H_ 16 #define TENSORFLOW_LITE_PROFILING_PROFILE_BUFFER_H_ 17 18 #include <cstddef> 19 #include <cstdint> 20 #include <cstdio> 21 #include <vector> 22 23 #include "tensorflow/lite/core/api/profiler.h" 24 #include "tensorflow/lite/profiling/memory_info.h" 25 #include "tensorflow/lite/profiling/time.h" 26 27 namespace tflite { 28 namespace profiling { 29 30 constexpr uint32_t kInvalidEventHandle = static_cast<uint32_t>(~0) - 1; 31 32 // A profiling event. 33 struct ProfileEvent { 34 // Describes the type of event. 35 // The event_metadata field may contain additional data for interpreting 36 // the event. 37 using EventType = tflite::Profiler::EventType; 38 39 // Label of the event. This usually describes the event. 40 std::string tag; 41 // Timestamp in microseconds when the event began. 42 uint64_t begin_timestamp_us; 43 // Timestamp in microseconds when the event ended. 44 uint64_t end_timestamp_us; 45 46 // The memory usage when the event begins. 47 memory::MemoryUsage begin_mem_usage; 48 // The memory usage when the event ends. 49 memory::MemoryUsage end_mem_usage; 50 51 // The field containing the type of event. This must be one of the event types 52 // in EventType. 53 EventType event_type; 54 // Meta data associated w/ the event. 55 int64_t event_metadata; 56 // Note: if this is an OPERATOR_INVOKE_EVENT, 'extra_event_metadata' will 57 // represent the index of the subgraph that this event comes from. 58 int64_t extra_event_metadata; 59 }; 60 61 // A ring buffer of profile events. 62 // This class is not thread safe. 63 class ProfileBuffer { 64 public: ProfileBuffer(uint32_t max_num_entries,bool enabled)65 ProfileBuffer(uint32_t max_num_entries, bool enabled) 66 : enabled_(enabled), current_index_(0), event_buffer_(max_num_entries) {} 67 68 // Adds an event to the buffer with begin timestamp set to the current 69 // timestamp. Returns a handle to event that can be used to call EndEvent. If 70 // buffer is disabled this has no affect. 71 // The tag of the event should remain valid till the buffer is valid. BeginEvent(const char * tag,ProfileEvent::EventType event_type,int64_t event_metadata1,int64_t event_metadata2)72 uint32_t BeginEvent(const char* tag, ProfileEvent::EventType event_type, 73 int64_t event_metadata1, int64_t event_metadata2) { 74 if (!enabled_) { 75 return kInvalidEventHandle; 76 } 77 uint64_t timestamp = time::NowMicros(); 78 int index = current_index_ % event_buffer_.size(); 79 if (current_index_ != 0 && index == 0) { 80 fprintf(stderr, "Warning: Dropping ProfileBuffer event.\n"); 81 return current_index_; 82 } 83 event_buffer_[index].tag = tag; 84 event_buffer_[index].event_type = event_type; 85 event_buffer_[index].event_metadata = event_metadata1; 86 event_buffer_[index].extra_event_metadata = event_metadata2; 87 event_buffer_[index].begin_timestamp_us = timestamp; 88 event_buffer_[index].end_timestamp_us = 0; 89 if (event_type != Profiler::EventType::OPERATOR_INVOKE_EVENT) { 90 event_buffer_[index].begin_mem_usage = memory::GetMemoryUsage(); 91 } 92 current_index_++; 93 return index; 94 } 95 96 // Sets the enabled state of buffer to |enabled| SetEnabled(bool enabled)97 void SetEnabled(bool enabled) { enabled_ = enabled; } 98 99 // Sets the end timestamp for event for the handle to current time. 100 // If the buffer is disabled or previous event has been overwritten this 101 // operation has not effect. 102 void EndEvent(uint32_t event_handle, const int64_t* event_metadata1 = nullptr, 103 const int64_t* event_metadata2 = nullptr) { 104 if (!enabled_ || event_handle == kInvalidEventHandle || 105 event_handle > current_index_) { 106 return; 107 } 108 const uint32_t max_size = event_buffer_.size(); 109 if (current_index_ > (max_size + event_handle)) { 110 // Ignore, buffer has already overflowed. 111 fprintf(stderr, "Warning: Dropping ProfileBuffer event.\n"); 112 return; 113 } 114 115 int event_index = event_handle % max_size; 116 event_buffer_[event_index].end_timestamp_us = time::NowMicros(); 117 if (event_buffer_[event_index].event_type != 118 Profiler::EventType::OPERATOR_INVOKE_EVENT) { 119 event_buffer_[event_index].end_mem_usage = memory::GetMemoryUsage(); 120 } 121 if (event_metadata1) { 122 event_buffer_[event_index].event_metadata = *event_metadata1; 123 } 124 if (event_metadata2) { 125 event_buffer_[event_index].extra_event_metadata = *event_metadata2; 126 } 127 } 128 AddEvent(const char * tag,ProfileEvent::EventType event_type,uint64_t start,uint64_t end,int64_t event_metadata1,int64_t event_metadata2)129 void AddEvent(const char* tag, ProfileEvent::EventType event_type, 130 uint64_t start, uint64_t end, int64_t event_metadata1, 131 int64_t event_metadata2) { 132 if (!enabled_) { 133 return; 134 } 135 const int index = current_index_ % event_buffer_.size(); 136 if (current_index_ != 0 && index == 0) { 137 fprintf(stderr, "Warning: Dropping ProfileBuffer event.\n"); 138 return; 139 } 140 event_buffer_[index].tag = tag; 141 event_buffer_[index].event_type = event_type; 142 event_buffer_[index].event_metadata = event_metadata1; 143 event_buffer_[index].extra_event_metadata = event_metadata2; 144 event_buffer_[index].begin_timestamp_us = start; 145 event_buffer_[index].end_timestamp_us = end; 146 current_index_++; 147 } 148 149 // Returns the size of the buffer. Size()150 size_t Size() const { 151 return (current_index_ >= event_buffer_.size()) ? event_buffer_.size() 152 : current_index_; 153 } 154 155 // Resets the buffer. Reset()156 void Reset() { 157 enabled_ = false; 158 current_index_ = 0; 159 } 160 161 // Returns the profile event at the given index. If the index is invalid a 162 // nullptr is returned. The return event may get overwritten if more events 163 // are added to buffer. At(size_t index)164 const struct ProfileEvent* At(size_t index) const { 165 size_t size = Size(); 166 if (index >= size) { 167 return nullptr; 168 } 169 const uint32_t max_size = event_buffer_.size(); 170 uint32_t start = 171 (current_index_ > max_size) ? current_index_ % max_size : max_size; 172 index = (index + start) % max_size; 173 return &event_buffer_[index]; 174 } 175 176 private: 177 bool enabled_; 178 uint32_t current_index_; 179 std::vector<ProfileEvent> event_buffer_; 180 }; 181 182 } // namespace profiling 183 } // namespace tflite 184 185 #endif // TENSORFLOW_LITE_PROFILING_PROFILE_BUFFER_H_ 186