Argus Camera Sample
Argus Camera Sample
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
PerfTracker.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of NVIDIA CORPORATION nor the names of its
13  * contributors may be used to endorse or promote products derived
14  * from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "PerfTracker.h"
30 
31 #include <stdio.h>
32 #define __STDC_FORMAT_MACROS
33 #include <inttypes.h>
34 
35 #include <limits>
36 
37 #include "Dispatcher.h"
38 #include "EventThread.h"
39 #include "InitOnce.h"
40 
41 namespace ArgusSamples
42 {
43 
45  : m_sessionId(0)
46 {
47 }
48 
50 {
51 }
52 
54 {
55  m_sessionId = 0;
56  m_displayCount = 0;
57  return true;
58 }
59 
61 {
62  static InitOnce initOnce;
63  static PerfTracker instance;
64 
65  if (initOnce.begin())
66  {
67  if (instance.initialize())
68  {
69  initOnce.complete();
70  }
71  else
72  {
73  initOnce.failed();
74  REPORT_ERROR("Initalization failed");
75  }
76  }
77 
78  return instance;
79 }
80 
82 {
83  switch (event)
84  {
87  break;
90  break;
92  if (!Dispatcher::getInstance().m_kpi)
93  return true;
94 
96  {
97  // start measurement
99  }
100  else
101  {
102  const TimeValue curTime = getCurrentTime();
103 
104  m_displayCount++;
105 
106  // print every second
107  if (curTime - m_firstDisplayTime > TimeValue::fromSec(1.f))
108  {
109  const float frameRate = static_cast<float>(m_displayCount) *
110  (curTime - m_firstDisplayTime).toCyclesPerSec();
111  printf("PerfTracker: display frame rate %.2f frames per second\n", frameRate);
112 
113  // restart measurement
115  m_displayCount = 0;
116  }
117  }
118  break;
119  default:
120  ORIGINATE_ERROR("Unhandled global event");
121  break;
122  }
123 
124  return true;
125 }
126 
128  : m_id(PerfTracker::getInstance().getNewSessionID())
129  , m_session(NULL)
130  , m_firstRequestReceivedTime(TimeValue::infinite())
131  , m_numberframesReceived(0)
132  , m_lastFrameCount(0)
133  , m_totalFrameDrop(0)
134  , m_minLatency(std::numeric_limits<uint64_t>::max())
135  , m_maxLatency(0)
136  , m_sumLatency(0)
137  , m_countLatency(0)
138  , m_previousSensorTime(0)
139  , m_minFramePeriod(std::numeric_limits<uint64_t>::max())
140  , m_maxFramePeriod(0)
141  , m_sumFramePeriod(0)
142  , m_countFramePeriod(-1)
143  , m_statsMinLatency(std::numeric_limits<uint64_t>::max())
144  , m_statsMaxLatency(0)
145  , m_statsSumLatency(0)
146  , m_statsCountLatency(0)
147  , m_statsMinFramePeriod(std::numeric_limits<uint64_t>::max())
148  , m_statsMaxFramePeriod(0)
149  , m_statsSumFramePeriod(0)
150  , m_statsCountFramePeriod(0)
151  , m_statsFrameDropCount(0)
152  , m_statsOutOfOrderCount(0)
153  , m_previousKpi(false)
154 {
155 }
156 
158 {
159  PROPAGATE_ERROR_CONTINUE(shutdown());
160 }
161 
163 {
164  if (m_eventThread)
165  {
166  PROPAGATE_ERROR_CONTINUE(m_eventThread->shutdown());
167  m_eventThread.reset();
168  }
169 
170  return true;
171 }
172 
173 bool SessionPerfTracker::setSession(Argus::CaptureSession *session)
174 {
175  m_session = session;
176  return true;
177 }
178 
179 bool SessionPerfTracker::onEvent(SessionEvent event, uint64_t value)
180 {
181  if (!Dispatcher::getInstance().m_kpi && !m_previousKpi)
182  return true;
183 
184  // switch kpi ON to OFF case
185  if (!Dispatcher::getInstance().m_kpi && m_previousKpi)
186  {
187  // take buffered info into account
200 
201  // print stats during the enabling kpi period
202  printf("===== PerfTracker %d Stats from %" PRIu64 " frames =====\n",
204  printf("LATENCY : avg %.2f min %.2f max %.2f ms\n",
206  m_statsMinLatency / 1000.f, m_statsMaxLatency / 1000.f);
207  printf("FRAMEPERIOD : avg %.2f min %.2f max %.2f ms\n",
209  m_statsMinFramePeriod / 1000.f, m_statsMaxFramePeriod / 1000.f);
210  printf("FRAMEDROP : %d frames\n", m_statsFrameDropCount);
211  printf("OUT OF ORDER: %d frames\n", m_statsOutOfOrderCount);
212  printf("===============================================\n");
213 
214  // clean up stats
216  m_lastFrameCount = 0;
217  m_minLatency = std::numeric_limits<uint64_t>::max();
218  m_maxLatency = 0;
219  m_sumLatency = 0;
220  m_countLatency = 0;
221  m_minFramePeriod = std::numeric_limits<uint64_t>::max();
222  m_maxFramePeriod = 0;
223  m_sumFramePeriod= 0;
224  m_countFramePeriod = -1;
225  m_statsMinLatency = std::numeric_limits<uint64_t>::max();
226  m_statsMaxLatency = 0;
227  m_statsSumLatency = 0;
229  m_statsMinFramePeriod = std::numeric_limits<uint64_t>::max();
235 
237  return true;
238  }
239 
241  switch (event)
242  {
245  printf("PerfTracker: app initial %" PRIu64 " ms\n",
246  (PerfTracker::getInstance().appInitializedTime() -
247  PerfTracker::getInstance().appStartTime()).toMSec());
248  printf("PerfTracker %d: app intialized to task start %" PRIu64 " ms\n", m_id,
249  (m_taskStartTime - PerfTracker::getInstance().appInitializedTime()).toMSec());
250  break;
252  // captures are about to start, create the event thread which collects information on the
253  // captures received
254  if (!m_eventThread)
255  {
256  m_eventThread.reset(new EventThread(m_session, this));
257  if (!m_eventThread)
258  ORIGINATE_ERROR("Failed to allocate EventThread");
259 
260  PROPAGATE_ERROR(m_eventThread->initialize());
261  PROPAGATE_ERROR(m_eventThread->waitRunning());
262  }
263 
265  printf("PerfTracker %d: task start to issue capture %" PRIu64 " ms\n", m_id,
266  (m_issueCaptureTime - m_taskStartTime).toMSec());
267  break;
270  if (m_numberframesReceived == 0)
271  {
273  printf("PerfTracker %d: first request %" PRIu64 " ms\n", m_id,
275  printf("PerfTracker %d: total launch time %" PRIu64 " ms\n", m_id,
276  (m_firstRequestReceivedTime - PerfTracker::getInstance().appStartTime()).toMSec());
277  }
278 
280  // print only when receiving > 30 frames
281  if ((m_numberframesReceived % 30) == 2 && m_numberframesReceived >= 30)
282  {
283  const float frameRate =
284  static_cast<float>(m_numberframesReceived - 1) *
286  printf("PerfTracker %d: frameRate %.2f frames per second at %" PRIu64 " Seconds\n",
287  m_id,
288  frameRate,
290  }
291  break;
293  m_minLatency = (m_minLatency < value) ? m_minLatency : value;
294  m_maxLatency = (m_maxLatency < value) ? value : m_maxLatency;
295  m_sumLatency += value;
296  m_countLatency += 1;
297  if ((m_numberframesReceived % 30) == 6)
298  {
299  const uint64_t latencyAverage = m_sumLatency / m_countLatency;
300  printf("PerfTracker %d: latency %.1f ms average, min %.1f max %.1f" \
301  " from %" PRIu64 " frames\n",
302  m_id, latencyAverage / 1000.f, m_minLatency / 1000.f,
303  m_maxLatency / 1000.f, m_countLatency);
304 
305  // record all data in stats
312 
313  m_minLatency = std::numeric_limits<uint64_t>::max();
314  m_maxLatency = 0;
315  m_sumLatency = 0;
316  m_countLatency = 0;
317  }
318  break;
320  {
321  // skip first run
322  if (m_countFramePeriod != -1)
323  {
324  // not record the old timestamp to m_previousSensorTime in this case
325  if (value < m_previousSensorTime)
326  {
327  printf("PerfTracker %d: warning: receive a frame out of order\n", m_id);
329  break;
330  }
331  const uint64_t framePeriod = value - m_previousSensorTime;
332  m_minFramePeriod = (m_minFramePeriod < framePeriod) ?
333  m_minFramePeriod : framePeriod;
334  m_maxFramePeriod = (m_maxFramePeriod < framePeriod) ?
335  framePeriod : m_maxFramePeriod;
336  m_sumFramePeriod += framePeriod;
337  m_countFramePeriod += 1;
338  if ((m_numberframesReceived % 30) == 6)
339  {
340  const uint64_t framePeriodAverage = m_sumFramePeriod / m_countFramePeriod;
341  printf("PerfTracker %d: frame period %.1f ms average, min %.1f" \
342  " max %.1f from %" PRId64 " frames\n",
343  m_id, framePeriodAverage / 1000.f, m_minFramePeriod / 1000.f,
344  m_maxFramePeriod / 1000.f, m_countFramePeriod + 1);
345 
346  // record all data in stats
353 
354  m_minFramePeriod = std::numeric_limits<uint64_t>::max();
355  m_maxFramePeriod = 0;
356  m_sumFramePeriod= 0;
357  m_countFramePeriod = -1;
358  m_previousSensorTime = 0;
359  }
360  }
361  else
362  {
363  m_countFramePeriod += 1;
364  }
365 
366  m_previousSensorTime = value;
367  break;
368  }
370  {
371  const TimeValue currentTime = getCurrentTime();
372  const uint64_t currentFrameCount = value;
373  int64_t currentFrameDrop = 0;
374  // start frame drop count from 2nd frame
375  if (m_lastFrameCount > 0)
376  {
377  // currentFrameDrop can be negative when metadata comes out of order
378  currentFrameDrop = currentFrameCount - m_lastFrameCount - 1;
379  m_totalFrameDrop += currentFrameDrop;
380  }
381  if (currentFrameDrop != 0)
382  {
383  printf("PerfTracker %d: framedrop current request %" PRId64 ", total %" PRId64
384  ", Drop at %" PRIu64 " Seconds !\n",
385  m_id, currentFrameDrop,
387  (currentTime - m_firstRequestReceivedTime).toSec());
388  m_statsFrameDropCount += currentFrameDrop;
389  }
390  else
391  {
392  if ((m_numberframesReceived % 30) == 4)
393  {
394  printf("PerfTracker %d: framedrop current request %" PRId64 ", total %"
395  PRId64 "\n",
396  m_id, currentFrameDrop,
398  }
399  }
400 
401  m_lastFrameCount = currentFrameCount;
402  break;
403  }
406  // captures are about to be stopped, destroy the event thread.
407  if (m_eventThread)
408  {
409  PROPAGATE_ERROR(m_eventThread->shutdown());
410  m_eventThread.reset();
411  }
412  break;
415  printf("PerfTracker %d: flush takes %" PRIu64 " ms\n", m_id,
417  break;
420  printf("PerfTracker %d: device close takes %" PRIu64 " ms\n", m_id,
421  (m_closeDoneTime - m_flushDoneTime).toMSec());
422  printf("PerfTracker %d: total close takes %" PRIu64 " ms\n", m_id,
424  break;
425  default:
426  ORIGINATE_ERROR("Unhandled session event");
427  break;
428  }
429 
430  return true;
431 }
432 
433 }; // namespace ArgusSamples