Argus Camera Sample Argus Camera Sample

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

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
44 PerfTracker::PerfTracker()
45 : m_sessionId(0)
46 {
47 }
48
49 PerfTracker::~PerfTracker()
50 {
51 }
52
53 bool PerfTracker::initialize()
54 {
55 m_sessionId = 0;
56 m_displayCount = 0;
57 return true;
58 }
59
60 PerfTracker &PerfTracker::getInstance()
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
81 bool PerfTracker::onEvent(GlobalEvent event)
82 {
83 switch (event)
84 {
85 case GLOBAL_EVENT_APP_START:
86 m_appStartTime = getCurrentTime();
87 break;
88 case GLOBAL_EVENT_APP_INITIALIZED:
89 m_appInitializedTime = getCurrentTime();
90 break;
91 case GLOBAL_EVENT_DISPLAY:
92 if (!Dispatcher::getInstance().m_kpi)
93 return true;
94
95 if (m_firstDisplayTime == TimeValue())
96 {
97 // start measurement
98 m_firstDisplayTime = getCurrentTime();
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
114 m_firstDisplayTime = getCurrentTime();
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
127 SessionPerfTracker::SessionPerfTracker()
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
157 SessionPerfTracker::~SessionPerfTracker()
158 {
159 PROPAGATE_ERROR_CONTINUE(shutdown());
160 }
161
162 bool SessionPerfTracker::shutdown()
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
188 m_statsMinLatency = (m_minLatency < m_statsMinLatency) ?
189 m_minLatency : m_statsMinLatency;
190 m_statsMaxLatency = (m_maxLatency < m_statsMaxLatency) ?
191 m_statsMaxLatency : m_maxLatency;
192 m_statsSumLatency += m_sumLatency;
193 m_statsCountLatency += m_countLatency;
194 m_statsMinFramePeriod = (m_minFramePeriod < m_statsMinFramePeriod) ?
195 m_minFramePeriod : m_statsMinFramePeriod;
196 m_statsMaxFramePeriod = (m_maxFramePeriod < m_statsMaxFramePeriod) ?
197 m_statsMaxFramePeriod : m_maxFramePeriod;
198 m_statsSumFramePeriod += m_sumFramePeriod;
199 m_statsCountFramePeriod += m_countFramePeriod;
200
201 // print stats during the enabling kpi period
202 printf("===== PerfTracker %d Stats from %" PRIu64 " frames =====\n",
203 m_id, m_numberframesReceived);
204 printf("LATENCY : avg %.2f min %.2f max %.2f ms\n",
205 m_statsSumLatency / m_statsCountLatency / 1000.f,
206 m_statsMinLatency / 1000.f, m_statsMaxLatency / 1000.f);
207 printf("FRAMEPERIOD : avg %.2f min %.2f max %.2f ms\n",
208 m_statsSumFramePeriod / (m_statsCountFramePeriod + 1) / 1000.f,
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
215 m_numberframesReceived = 0;
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;
228 m_statsCountLatency = 0;
229 m_statsMinFramePeriod = std::numeric_limits<uint64_t>::max();
230 m_statsMaxFramePeriod = 0;
231 m_statsSumFramePeriod = 0;
232 m_statsCountFramePeriod = -1;
233 m_statsFrameDropCount = 0;
234 m_statsOutOfOrderCount = 0;
235
236 m_previousKpi = Dispatcher::getInstance().m_kpi;
237 return true;
238 }
239
240 m_previousKpi = Dispatcher::getInstance().m_kpi;
241 switch (event)
242 {
243 case SESSION_EVENT_TASK_START:
244 m_taskStartTime = getCurrentTime();
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;
251 case SESSION_EVENT_ISSUE_CAPTURE:
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
264 m_issueCaptureTime = getCurrentTime();
265 printf("PerfTracker %d: task start to issue capture %" PRIu64 " ms\n", m_id,
266 (m_issueCaptureTime - m_taskStartTime).toMSec());
267 break;
268 case SESSION_EVENT_REQUEST_RECEIVED:
269 m_requestReceivedTime = getCurrentTime();
270 if (m_numberframesReceived == 0)
271 {
272 m_firstRequestReceivedTime = m_requestReceivedTime;
273 printf("PerfTracker %d: first request %" PRIu64 " ms\n", m_id,
274 (m_firstRequestReceivedTime - m_issueCaptureTime).toMSec());
275 printf("PerfTracker %d: total launch time %" PRIu64 " ms\n", m_id,
276 (m_firstRequestReceivedTime - PerfTracker::getInstance().appStartTime()).toMSec());
277 }
278
279 m_numberframesReceived++;
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) *
285 (m_requestReceivedTime - m_firstRequestReceivedTime).toCyclesPerSec();
286 printf("PerfTracker %d: frameRate %.2f frames per second at %" PRIu64 " Seconds\n",
287 m_id,
288 frameRate,
289 (m_requestReceivedTime - m_firstRequestReceivedTime).toSec());
290 }
291 break;
292 case SESSION_EVENT_REQUEST_LATENCY:
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
306 m_statsMinLatency = (m_minLatency < m_statsMinLatency) ?
307 m_minLatency : m_statsMinLatency;
308 m_statsMaxLatency = (m_maxLatency < m_statsMaxLatency) ?
309 m_statsMaxLatency : m_maxLatency;
310 m_statsSumLatency += m_sumLatency;
311 m_statsCountLatency += m_countLatency;
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;
319 case SESSION_EVENT_FRAME_PERIOD:
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);
328 m_statsOutOfOrderCount += 1;
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
347 m_statsMinFramePeriod = (m_minFramePeriod < m_statsMinFramePeriod) ?
348 m_minFramePeriod : m_statsMinFramePeriod;
349 m_statsMaxFramePeriod = (m_maxFramePeriod < m_statsMaxFramePeriod) ?
350 m_statsMaxFramePeriod : m_maxFramePeriod;
351 m_statsSumFramePeriod += m_sumFramePeriod;
352 m_statsCountFramePeriod += m_countFramePeriod;
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 }
369 case SESSION_EVENT_FRAME_COUNT:
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,
386 m_totalFrameDrop,
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,
397 m_totalFrameDrop);
398 }
399 }
400
401 m_lastFrameCount = currentFrameCount;
402 break;
403 }
404 case SESSION_EVENT_CLOSE_REQUESTED:
405 m_closeRequestedTime = getCurrentTime();
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;
413 case SESSION_EVENT_FLUSH_DONE:
414 m_flushDoneTime = getCurrentTime();
415 printf("PerfTracker %d: flush takes %" PRIu64 " ms\n", m_id,
416 (m_flushDoneTime - m_closeRequestedTime).toMSec());
417 break;
418 case SESSION_EVENT_CLOSE_DONE:
419 m_closeDoneTime = getCurrentTime();
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,
423 (m_closeDoneTime - m_closeRequestedTime).toMSec());
424 break;
425 default:
426 ORIGINATE_ERROR("Unhandled session event");
427 break;
428 }
429
430 return true;
431 }
432
433 }; // namespace ArgusSamples