NVIDIA DeepStream SDK API Reference

9.1 Release
9.1/service-maker/sources/modules/measure_fps_probe/measure_fps_probe.hpp
Go to the documentation of this file.
1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3  * SPDX-License-Identifier: Apache-2.0
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include <algorithm>
19 #include <fstream>
20 #include <iomanip>
21 #include <iostream>
22 #include <utility>
23 #include <chrono>
24 #include <mutex>
25 #include <set>
26 #include <string>
27 #include <unordered_map>
28 #include <thread>
29 #include <condition_variable>
30 
31 #include "buffer_probe.hpp"
32 
33 using namespace std;
34 
35 namespace deepstream {
36 
38 
39 class FPSCounter : public BufferProbe::IBatchMetadataObserver
40 {
41 public:
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;
45  std::chrono::steady_clock::time_point last_measurement_time;
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;
53 
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_;
60 
61 
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([&](){
70  do {
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);
75  });
76  }
77 
78  virtual ~FPSCounter() {
79  {
80  std::unique_lock<std::mutex> lock(this->count_mutex);
81  pause_measurment = true;
82  cv_.notify_one();
83  }
84  scheduler_.join();
85  }
86 
88  time_point current = std::chrono::steady_clock::now();
89  auto current_buf_count = std::move(buf_count);
90  // Print the header after every HEADER_PRINT_INTERVAL or if a source
91  // was dynamically added and pad_idxs size grew
92  if (this->last_header_print_interval == 0 ||
93  this->last_pad_idx_count != this->pad_idxs.size()) {
94  // this->print_header_unlocked();
95  this->last_header_print_interval = 0;
96  }
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;
103  // Insert does not update a value if the key already exists
104  accumulated_time.insert({pad_idx, std::chrono::microseconds(0)});
105  time_point first_frame_time = current;
106  time_point end_time = current;
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()) {
112  // If the eos was reached, change the end to the time EOS received instead
113  // of the interval end.
114  end_time = last_frame_time->second;
115  source_is_eos = true;
116  }
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;
120  }
121  // If the source reached EOS before the current measurement interval, do
122  // not print current values. However, if the EOS was reached in the current
123  // interval, print whatever was measured.
124  if (source_is_eos && end_time < this->last_measurement_time)
125  {
126  ostr << "--.--";
127  }
128  else
129  {
130  time_point start =
131  std::max(first_frame_time, this->last_measurement_time);
132  double interval = std::chrono::duration_cast<std::chrono::microseconds>(
133  end_time - start)
134  .count();
135  ostr << (1000000 * current_buf_count_source / interval);
136  }
137  double lifetime = std::chrono::duration_cast<std::chrono::microseconds>(
138  end_time - first_frame_time)
139  .count() +
140  accumulated_time[pad_idx].count();
141  ostr << " (" << (1000000 * this->buf_count_lifetime[pad_idx] / lifetime)
142  << ")\t";
143  }
144 
145  ostr << "\n";
146 
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();
151 }
152 
153  virtual probeReturn handleData(BufferProbe& probe, const BatchMetadata& data) {
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_) {
158  int val = 0;
159  probe.getProperty("interval", val);
160  if (val > 0) {
161  interval_seconds_ = static_cast<uint>(val);
162  cv_.notify_one();
163  }
164  interval_loaded_ = true;
165  }
166  auto cnt = 0;
167  pad_idxs.clear();
168  data.iterate([&](const FrameMetadata& frame_meta) {
169  if (cnt++ % num_surfaces_per_frame == 0) {
170  auto pad_idx = frame_meta.padIndex();
171  pad_idxs.insert(pad_idx);
172  // Insert does not update a value if the key already exists
173  first_frame_time.insert({pad_idx, current});
174  buf_count[pad_idx]++;
175  }
176  });
177  return probeReturn::Probe_Ok;
178  }
179 
180 };
181 
182 }
deepstream::FPSCounter::FPSCounter
FPSCounter()
Definition: 9.1/service-maker/sources/modules/measure_fps_probe/measure_fps_probe.hpp:62
deepstream::BufferProbe
Represent a custom object for the purpose of probing output buffers.
Definition: service-maker/includes/buffer_probe.hpp:63
deepstream::FPSCounter::~FPSCounter
virtual ~FPSCounter()
Definition: 9.1/service-maker/sources/modules/measure_fps_probe/measure_fps_probe.hpp:78
deepstream::FPSCounter::handleData
virtual probeReturn handleData(BufferProbe &probe, const BatchMetadata &data)
Definition: 9.1/service-maker/sources/modules/measure_fps_probe/measure_fps_probe.hpp:153
deepstream::BatchMetadata::iterate
unsigned int iterate(const std::function< void(const FrameMetadata &)> &func) const
Iterate the frame metadata within it.
deepstream::probeReturn
probeReturn
Return values from user implemented probe interfaces.
Definition: service-maker/includes/buffer_probe.hpp:47
deepstream
Definition: service-maker/includes/buffer.hpp:38
deepstream::FrameMetadata::padIndex
unsigned int padIndex() const
Index of the pad from which the frame is generated.
deepstream::BatchMetadata
Holds information about a formed batch containingframes from different sources.
Definition: service-maker/includes/metadata.hpp:797
deepstream::FPSCounter::measure_and_print_unlocked
void measure_and_print_unlocked()
Definition: 9.1/service-maker/sources/modules/measure_fps_probe/measure_fps_probe.hpp:87
deepstream::time_point
std::chrono::steady_clock::time_point time_point
Definition: service-maker/sources/modules/measure_fps_probe/measure_fps_probe.hpp:37
deepstream::Object::getProperty
Object & getProperty(const std::string &name, T &value, Args &... args)
Template for getting multiple properties.
Definition: service-maker/includes/object.hpp:176
deepstream::FrameMetadata
Holds information for a single frame.
Definition: service-maker/includes/metadata.hpp:454