27 #include <unordered_map>
29 #include <condition_variable>
31 #include "buffer_probe.hpp"
39 class FPSCounter :
public BufferProbe::IBatchMetadataObserver
42 static const int HEADER_PRINT_INTERVAL = 10;
43 std::unordered_map<unsigned int, std::chrono::microseconds> accumulated_time;
44 std::unordered_map<unsigned int, uint64_t> buf_count_lifetime;
46 std::mutex count_mutex;
47 bool pause_measurment;
48 int num_surfaces_per_frame;
49 std::set<unsigned int> pad_idxs;
50 std::unordered_map<unsigned int, std::chrono::steady_clock::time_point>
51 first_frame_time, last_frame_time;
52 std::unordered_map<unsigned int, uint64_t> buf_count;
54 std::thread scheduler_;
55 std::condition_variable cv_;
56 int last_header_print_interval;
57 std::size_t last_pad_idx_count;
58 uint interval_seconds_;
59 bool interval_loaded_;
63 interval_seconds_ = 5U;
64 interval_loaded_ =
false;
65 last_pad_idx_count = 0;
66 last_header_print_interval = 0;
67 num_surfaces_per_frame = 1;
68 pause_measurment =
false;
69 scheduler_ = std::thread([&](){
71 std::unique_lock<std::mutex> lock(this->count_mutex);
72 this->measure_and_print_unlocked();
73 this->cv_.wait_for(lock, std::chrono::seconds(this->interval_seconds_));
74 }
while (!this->pause_measurment);
80 std::unique_lock<std::mutex> lock(this->count_mutex);
81 pause_measurment =
true;
88 time_point current = std::chrono::steady_clock::now();
89 auto current_buf_count = std::move(buf_count);
92 if (this->last_header_print_interval == 0 ||
93 this->last_pad_idx_count != this->pad_idxs.size()) {
95 this->last_header_print_interval = 0;
97 this->last_header_print_interval =
98 (this->last_header_print_interval + 1) % HEADER_PRINT_INTERVAL;
99 std::ostringstream ostr;
100 ostr <<
"**FPS: " << std::fixed << std::setprecision(2);
101 for (
auto pad_idx : this->pad_idxs) {
102 uint64_t current_buf_count_source = 0;
104 accumulated_time.insert({pad_idx, std::chrono::microseconds(0)});
107 bool source_is_eos =
false;
108 if (this->first_frame_time.find(pad_idx) != this->first_frame_time.end())
109 first_frame_time = this->first_frame_time[pad_idx];
110 auto last_frame_time = this->last_frame_time.find(pad_idx);
111 if (last_frame_time != this->last_frame_time.end()) {
114 end_time = last_frame_time->second;
115 source_is_eos =
true;
117 if (current_buf_count.find(pad_idx) != current_buf_count.end()) {
118 current_buf_count_source = current_buf_count[pad_idx];
119 this->buf_count_lifetime[pad_idx] += current_buf_count_source;
124 if (source_is_eos && end_time < this->last_measurement_time)
131 std::max(first_frame_time, this->last_measurement_time);
132 double interval = std::chrono::duration_cast<std::chrono::microseconds>(
135 ostr << (1000000 * current_buf_count_source / interval);
137 double lifetime = std::chrono::duration_cast<std::chrono::microseconds>(
138 end_time - first_frame_time)
140 accumulated_time[pad_idx].count();
141 ostr <<
" (" << (1000000 * this->buf_count_lifetime[pad_idx] / lifetime)
147 if (ostr.str() !=
"**FPS: \n")
148 std::cout << ostr.str() << std::flush;
149 this->last_measurement_time = current;
150 this->last_pad_idx_count = this->pad_idxs.size();
154 time_point current = std::chrono::steady_clock::now();
155 std::lock_guard<std::mutex> lock(count_mutex);
156 if (pause_measurment)
return probeReturn::Probe_Ok;
157 if (!interval_loaded_) {
161 interval_seconds_ =
static_cast<uint
>(val);
164 interval_loaded_ =
true;
169 if (cnt++ % num_surfaces_per_frame == 0) {
170 auto pad_idx = frame_meta.
padIndex();
171 pad_idxs.insert(pad_idx);
173 first_frame_time.insert({pad_idx, current});
174 buf_count[pad_idx]++;
177 return probeReturn::Probe_Ok;