1
2/*
3 * Copyright (C) Texas Instruments - http://www.ti.com/
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22#ifdef __PERF_CUSTOMIZABLE__
23
24    #define __PERF_RT_C__
25
26    #include "perf_config.h"
27    #include "perf.h"
28    #include "perf_rt.h"
29    #include "math.h"
30
31/* ============================================================================
32   DEBUG RT METHODS
33============================================================================ */
34
35#define MAX_RATES_TRACKED   10
36#define MAX_GRANULARITY     15
37#define MIN_FRAMES_FOR_RATE 10
38
39static int uptime_started = 0;
40
41static void init_delay(PERF_RTdata_delay *dDelay, long n0)
42{
43    dDelay->xx = dDelay->x = 0;
44    dDelay->n = n0;
45}
46
47PERF_RT_Private *
48PERF_RT_create(PERF_Private *perf, PERF_Config *config,
49               PERF_MODULETYPE eModule)
50{
51    char *fOutFile = NULL;
52    FILE *fOut = NULL;
53
54    /* check if we support this component */
55    if (perf->ulID != PERF_FOURS("CAM_") && perf->ulID != PERF_FOURS("CAMT") &&
56        perf->ulID != PERF_FOURS("VP__") && perf->ulID != PERF_FOURS("VP_T") &&
57        perf->ulID != PERF_FOURS("VD__") && perf->ulID != PERF_FOURS("VD_T") &&
58        perf->ulID != PERF_FOURS("VE__") && perf->ulID != PERF_FOURS("VE_T"))
59    {
60        /* if we don't support this component, we don't create the real-time
61           interface */
62        return (NULL);
63    }
64
65    PERF_RT_Private *me =
66    perf->cip.pRT = malloc(sizeof(PERF_RT_Private));
67
68    if (me)
69    {
70        int succeed = 1;
71
72        /* we track steady state on the component thread only */
73        me->needSteadyState = (perf->ulID & 0xff) == 'T';
74        me->steadyState = 0;
75
76        /* allocate rate tracking structures */
77        me->maxDRate = MAX_RATES_TRACKED;
78        me->dRate = malloc(sizeof(PERF_RTdata_rate) * me->maxDRate);
79        succeed = succeed && me->dRate;
80
81        me->decoder = (perf->ulID == PERF_FOURS("VD__") || perf->ulID == PERF_FOURS("VD_T"));
82        me->encoder = (perf->ulID == PERF_FOURS("VE__") || perf->ulID == PERF_FOURS("VE_T"));
83        me->nDRate = 0;
84
85        /* allocate shot-to-shot tracking structures */
86        if (succeed && perf->ulID == PERF_FOURS("CAMT"))
87        {
88            me->dSTS = malloc(sizeof(PERF_RTdata_sts));
89            succeed = succeed && me->dSTS;
90            if (me->dSTS)
91            {
92                init_delay(&me->dSTS->dBurst, -1);   /* no first timestamp yet */
93                init_delay(&me->dSTS->dABurst, 0);
94                init_delay(&me->dSTS->dBurst2, 0);
95                init_delay(&me->dSTS->dABurst2, 0);
96                init_delay(&me->dSTS->dSingle, -1);  /* no first timestamp yet */
97                me->dSTS->size_max = me->dSTS->size_min = me->dSTS->capturing = 0;
98            }
99        }
100        else
101        {
102            me->dSTS = NULL;
103        }
104
105        /* allocate uptime tracking structures */
106
107        /* :NOTE: for now we restrict creations of uptime to steady state
108            only */
109        if (succeed && !uptime_started && me->needSteadyState &&
110            !(perf->uMode & PERF_Mode_Replay))
111        {
112            me->dUptime = malloc(sizeof(PERF_RTdata_uptime));
113            succeed = succeed && me->dUptime;
114
115            if (succeed)
116            {
117                uptime_started = 1;
118                me->dUptime->measuring = 0;
119                me->dUptime->last_idletime = me->dUptime->last_uptime = 0;
120                me->dUptime->start_idletime = me->dUptime->start_uptime = 0;
121                me->dUptime->success = 1;
122                me->dUptime->xx = me->dUptime->x = me->dUptime->n = 0;
123                TIME_GET(me->dUptime->last_reporting);
124            }
125        }
126        else
127        {
128            me->dUptime = NULL;
129        }
130
131        /* configuration */
132        me->summary     = config->rt_summary != 0;
133        me->debug       = config->rt_debug & 0x1FF;
134        me->detailed    = (config->rt_detailed > 2) ? 2 : (int) config->rt_detailed;
135
136        me->granularity = (config->rt_granularity < 1) ? 1 :
137                          (config->rt_granularity > MAX_GRANULARITY) ?
138                          MAX_GRANULARITY : (long) config->rt_granularity;
139        me->granularity *= 1000000;  /* convert to microsecs */
140        TIME_COPY(me->first_time, perf->time);
141
142        /* if we do not care about detailed statistics, only report significant
143           statistics for each component */
144        if (succeed && !me->detailed)
145        {
146            /* VP_T - display rate */
147            if (perf->ulID == PERF_FOURS("VP_T"))
148            {
149                me->only_moduleandflags = PERF_FlagSending | PERF_FlagFrame | PERF_ModuleHardware;
150            }
151            /* VD_T - decode rate */
152            else if (perf->ulID == PERF_FOURS("VD_T"))
153            {
154                me->only_moduleandflags = PERF_FlagSending | PERF_FlagFrame | PERF_ModuleLLMM;
155            }
156            /* VE_T - encode rate */
157            else if (perf->ulID == PERF_FOURS("VE_T"))
158            {
159                me->only_moduleandflags = PERF_FlagSending | PERF_FlagFrame | PERF_ModuleLLMM;
160            }
161            /* CAMT - capture rate */
162            else if (perf->ulID == PERF_FOURS("CAMT"))
163            {
164                me->only_moduleandflags = PERF_FlagReceived | PERF_FlagFrame | PERF_ModuleHardware;
165            }
166            /* otherwise, we don't care about rates */
167            else
168            {
169                free(me->dRate);
170                me->dRate = NULL;
171                me->maxDRate = 0;
172            }
173        }
174
175        /* set up fRt file pointers */
176        if (config->rt_file && succeed)
177        {
178            /* open log file unless STDOUT or STDERR is specified */
179            if (!strcasecmp(config->rt_file, "STDOUT")) fOut = stdout;
180            else if (!strcasecmp(config->rt_file, "STDERR")) fOut = stderr;
181            else
182            {
183                /* expand file name with PID and name */
184                fOutFile = (char *) malloc (strlen(config->rt_file) + 32);
185                if (fOutFile)
186                {
187                    sprintf(fOutFile, "%s-%05lu-%08lx-%c%c%c%c.log",
188                            config->rt_file, perf->ulPID, (unsigned long) perf,
189                            PERF_FOUR_CHARS(perf->ulID));
190                    fOut = fopen(fOutFile, "at");
191
192                    /* free new file name */
193                    free(fOutFile);
194                    fOutFile = NULL;
195                }
196
197                /* if could not open output, set it to STDOUT */
198                if (!fOut) fOut = stderr;
199            }
200            me->fRt = fOut;
201        }
202
203        /* if we had allocation failures, free resources and return NULL */
204        if (succeed)
205        {
206            perf->uMode |= PERF_Mode_RealTime;
207        }
208        else
209        {
210            PERF_RT_done(perf);
211            me = NULL;
212        }
213    }
214
215    return(me);
216}
217
218void PERF_RT_done(PERF_Private *perf)
219{
220    PERF_RT_Private *me = perf->cip.pRT;
221
222    /* close debug file unless stdout or stderr */
223    if (me->fRt && me->fRt != stdout &&
224        me->fRt != stderr) fclose(me->fRt);
225
226    /* free allocated structures */
227    free(me->dRate);   me->dRate = NULL;
228    free(me->dUptime); me->dUptime = NULL;
229    free(me->dSTS);    me->dSTS = NULL;
230
231    /* free private structure */
232    free(me);
233    perf->cip.pRT = NULL;
234}
235
236static void get_uptime(double *uptime, double *idletime)
237{
238    FILE *fUptime = fopen("/proc/uptime", "r");
239    if (fUptime)
240    {
241        fscanf(fUptime, "%lg %lg", uptime, idletime);
242        fclose (fUptime);
243    }
244    else
245    {
246        *uptime = *idletime = 0.;
247    }
248}
249
250static void start_stop_uptime(PERF_RTdata_uptime *dUptime, int start)
251{
252    double uptime, idletime;
253
254    if (dUptime && dUptime->measuring != start)
255    {
256        /* add uptime since last time */
257        get_uptime(&uptime, &idletime);
258
259        /* if successful */
260        if (dUptime->success && uptime && idletime)
261        {
262            dUptime->start_idletime = idletime - dUptime->start_idletime;
263            dUptime->start_uptime = uptime - dUptime->start_uptime;
264            dUptime->last_idletime = idletime - dUptime->last_idletime;
265            dUptime->last_uptime = uptime - dUptime->last_uptime;
266        }
267        else
268        {
269            dUptime->start_idletime = dUptime->start_uptime = dUptime->success = 0;
270            dUptime->last_idletime = dUptime->last_uptime = 0;
271        }
272
273        dUptime->measuring = start;
274    }
275}
276
277extern char const * const PERF_ModuleTypes[];
278
279double my_sqrt(double a)
280{
281    double b = (a + 1) / 2;
282    b = (b + a/b) / 2;
283    b = (b + a/b) / 2;
284    b = (b + a/b) / 2;
285    b = (b + a/b) / 2;
286    b = (b + a/b) / 2;
287    b = (b + a/b) / 2;
288    return (b + a/b) / 2;
289}
290
291static const char *sendRecvTxt[] = {
292        "received", "sending", "requesting", "sent",
293    };
294
295static void print_rate_info(FILE *fOut,
296                            unsigned long ID, PERF_MODULETYPE modulesAndFlags,
297                            unsigned long size, long n)
298{
299    unsigned long module1 = modulesAndFlags & PERF_ModuleMask;
300    unsigned long module2 = (modulesAndFlags >> PERF_ModuleBits) & PERF_ModuleMask;
301    int xfering  = PERF_IsXfering(modulesAndFlags);
302    int sendIx   = (PERF_GetSendRecv(modulesAndFlags) >> 28) & 3;
303    int sending  = PERF_IsSending(modulesAndFlags);
304    int frame    = PERF_IsFrame  (modulesAndFlags);
305
306    fprintf(fOut, "%c%c%c%c %s %ld+ %s[0x%lX]%s%s%s%s",
307            PERF_FOUR_CHARS(ID),
308            xfering ? "xfering" : sendRecvTxt[sendIx],
309            n,
310            frame ? "frames" : "buffers",
311            size,
312            (xfering || !sending) ? " from " : " to ",
313            (module1 < PERF_ModuleMax ? PERF_ModuleTypes[module1] : "INVALID"),
314            xfering ? " to " : "",
315            xfering ? (module2 < PERF_ModuleMax ? PERF_ModuleTypes[module2] : "INVALID") : "");
316}
317
318void count_temporal_rate(unsigned long ID, PERF_RT_Private *me, PERF_RTdata_rate *dRate)
319{
320    /* get the temporal rate */
321    double x = (dRate->tn ? (dRate->tx ? ((1e6 * dRate->tn) / dRate->tx) : 1e6) : 0.);
322    if (me->debug)
323    {
324        fprintf(me->fRt, "rtPERF: [%ld] ", TIME_DELTA(dRate->last_reporting, me->first_time)/1000000);
325        print_rate_info(me->fRt,
326                        ID, dRate->modulesAndFlags, dRate->size, dRate->tn);
327
328        /* calculate smoothness */
329        double s = dRate->txx ? (dRate->tx * (double) dRate->tx / dRate->txx / dRate->tn) : 1;
330
331        fprintf(me->fRt, ": %.3g fps (s=%.3g)\n", x, s);
332    }
333
334    /* calculate the average of the temporal rate */
335    dRate->axx += x * x;
336    dRate->ax  += x;
337    dRate->an  ++;
338
339    dRate->txx = dRate->tx = dRate->tn = 0;
340}
341
342static void delay_add(PERF_RTdata_delay *dDelay, unsigned long delta)
343{
344    dDelay->x  += delta;
345    dDelay->xx += delta * (double) delta;
346    dDelay->n  ++;
347}
348
349static void delay_delta(PERF_RTdata_delay *dDelay, PERF_Private *perf)
350{
351    if (dDelay->n < 0)
352    {
353        dDelay->n++;
354    }
355    else
356    {
357        delay_add(dDelay, TIME_DELTA(perf->time, dDelay->last_timestamp));
358    }
359    TIME_COPY(dDelay->last_timestamp, perf->time);
360}
361
362static void count_delay(PERF_RT_Private *me, char *tag, PERF_RTdata_delay *dDelay, long n0)
363{
364    fprintf(me->fRt, "rtPERF: %s[0x%lX]: ", tag, me->dSTS->size_min);
365    if (dDelay->n > 0)
366    {
367        double x = 1e-6 * dDelay->x / dDelay->n;
368        double xx = 1e-12 * dDelay->xx / dDelay->n;
369        xx = my_sqrt(xx - x * x);
370
371        if (dDelay->n > 1)
372        {
373            fprintf(me->fRt, "%.3g +- %.3g s (%ld samples)\n",
374                    x, xx, dDelay->n);
375        }
376        else
377        {
378            fprintf(me->fRt, "%.3g\n", x);
379        }
380    }
381    else
382    {
383        fprintf(me->fRt, "UNABLE TO CALCULATE\n");
384    }
385
386    dDelay->n = n0;
387    dDelay->xx = dDelay->x = 0;
388}
389
390void __rt_Boundary(PERF_Private *perf, PERF_BOUNDARYTYPE eBoundary)
391{
392    /* get real-time private structure */
393    PERF_RT_Private *me = perf->cip.pRT;
394
395    /* check steady state if we need it */
396    if (me->needSteadyState)
397    {
398        if (eBoundary == (PERF_BoundaryStart | PERF_BoundarySteadyState))
399        {
400            if (!me->steadyState)
401            {
402                /* continue uptime measurement */
403                start_stop_uptime(me->dUptime, 1);
404
405                /* for each rate, reset skip count as well as tn0 */
406                int i;
407                for (i = 0; i < me->nDRate; i++)
408                {
409                    me->dRate[i].txx = me->dRate[i].tx = me->dRate[i].tn = me->dRate[i].tn0 = 0;
410                    me->dRate[i].skip = 0;
411                }
412            }
413
414            me->steadyState = 1;
415        }
416        else if (eBoundary == (PERF_BoundaryComplete | PERF_BoundarySteadyState))
417        {
418            if (me->steadyState)
419            {
420                /* stop uptime measurement */
421                start_stop_uptime(me->dUptime, 0);
422
423                /* complete any temporary rate measurements */
424                int i;
425                for (i = 0; i < me->nDRate; i++)
426                {
427                    /* only if we had any buffers in this cycle */
428                    if (me->dRate[i].tn0 >= MIN_FRAMES_FOR_RATE ||
429                        (me->dRate[i].tn && me->debug & 4))
430                    {
431                        count_temporal_rate(perf->ulID, me, me->dRate + i);
432                    }
433                }
434            }
435
436            me->steadyState = 0;
437        }
438    }
439    else
440    {
441        /* if we do not check steady state, we still complete on cleanup */
442        if (eBoundary == (PERF_BoundaryStart | PERF_BoundaryCleanup))
443        {
444            /* stop measurements */
445            start_stop_uptime(me->dUptime, 0);
446        }
447    }
448}
449
450void __rt_Buffer(PERF_Private *perf,
451                 unsigned long ulAddress1,
452                 unsigned long ulAddress2,
453                 unsigned long ulSize,
454                 PERF_MODULETYPE eModuleAndFlags)
455{
456    /* get real-time private structure */
457    PERF_RT_Private *me = perf->cip.pRT;
458
459    /* see if we care about this buffer in the rate calculation */
460    unsigned long module = eModuleAndFlags & PERF_ModuleMask;
461
462    /* ------------------------ RATE METRICS ------------------------ */
463
464    /* change HLMM to LLMM for detailed = 0 and 1 */
465    if (me->detailed < 2 && module == PERF_ModuleHLMM)
466    {
467        module = PERF_ModuleLLMM;
468    }
469
470    int rate = (me->detailed == 2) ||
471               (me->detailed == 0 &&
472                (eModuleAndFlags == me->only_moduleandflags && ulSize >= 8)) ||
473               (me->detailed == 1 &&
474                ((module == PERF_ModuleHardware || module == PERF_ModuleLLMM)));
475
476    if (rate && me->dRate && (!me->needSteadyState || me->steadyState))
477    {
478        /* change encoded filled frame sizes to 0xBEEFED, as they tend to
479           have varying sizes and thus not be counted */
480        unsigned long sending = PERF_GetXferSendRecv(eModuleAndFlags);
481        unsigned long size = ulSize;
482        if ((me->encoder || me->decoder) && !PERF_IsXfering(sending))
483        {
484            /* reverse sending direction to common layer or socket node */
485            if (module >= PERF_ModuleCommonLayer &&
486                module <= PERF_ModuleSocketNode)
487            {
488                sending ^= PERF_FlagSending;
489            }
490
491            if ((me->encoder && (sending == PERF_FlagSending)) ||
492                (me->decoder && (sending == PERF_FlagReceived)))
493            {
494                size = size ? 0xBEEFED : 0;
495            }
496        }
497
498        /* see if we are tracking this buffer size */
499        int i, j = -1;  /* j is one of the lest used indexes */
500        for (i=0; i < me->nDRate; i++)
501        {
502            if (me->dRate[i].modulesAndFlags == eModuleAndFlags &&
503                me->dRate[i].size == size) break;
504            if (j < 0 || me->dRate[i].n < me->dRate[j].n)
505            {
506                j = i;
507            }
508        }
509
510        /* if we are not yet tracking this buffer, see if we can track
511           it. */
512        if (i == me->nDRate)
513        {
514            /* we have space to track it */
515            if (i < me->maxDRate)
516            {
517                me->nDRate++;
518            }
519            /* if we cannot replace another rate, we don't track it */
520            else if (j < 0 || me->dRate[j].n < 2)
521            {
522                i = me->maxDRate;
523            }
524            else
525            {
526                i = j;
527            }
528
529            /* start tracking */
530            if (i < me->maxDRate)
531            {
532                me->dRate[i].modulesAndFlags = eModuleAndFlags;
533                me->dRate[i].size = size;
534                me->dRate[i].xx = me->dRate[i].x = me->dRate[i].n = 0;
535                me->dRate[i].txx = me->dRate[i].tx = me->dRate[i].tn = me->dRate[i].tn0 = 0;
536                me->dRate[i].axx = me->dRate[i].ax = me->dRate[i].an = 0;
537                me->dRate[i].skip = me->needSteadyState ? 0 : 4;
538                TIME_COPY(me->dRate[i].last_timestamp, perf->time);
539                TIME_COPY(me->dRate[i].last_reporting, perf->time);
540            }
541        }
542        else
543        {
544            if (me->dRate[i].skip == 0)
545            {
546                /* see if we passed our granularity */
547                int steps = TIME_DELTA(perf->time, me->dRate[i].last_reporting);
548                if (steps >= me->granularity)
549                {
550                    steps /= me->granularity;
551
552                    /* unless debug bit 4 is set, ignore temporal statistics if
553                       we passed the last time by more than a second, and less than
554                       the minimul frames were processed in this burst so far, and
555                       the last fps was less than 1. */
556                    if (!(me->debug & 4) &&
557                        (me->dRate[i].tn0 < MIN_FRAMES_FOR_RATE) &&
558                        (me->dRate[i].tn < me->granularity * steps))
559                    {
560                        if (me->debug & 256)
561                        {
562                            fprintf(me->fRt, "rtPERF: [%ld] IGNORED (steps=%d, tn0=%ld, tn=%ld)\n",
563                                    TIME_DELTA(me->dRate[i].last_reporting, me->first_time)/1000000,
564                                    steps, me->dRate[i].tn0, me->dRate[i].tn);
565                        }
566                        me->dRate[i].txx = me->dRate[i].tx = me->dRate[i].tn = me->dRate[i].tn0 = 0;
567
568                        TIME_INCREASE(me->dRate[i].last_reporting, me->granularity * steps);
569                        steps = 0;
570                    }
571                    else if (me->debug & 256)
572                    {
573                        fprintf(me->fRt, "rtPERF: [%ld] not-ignored (steps=%d, tn0=%ld, tn=%ld)\n",
574                                TIME_DELTA(me->dRate[i].last_reporting, me->first_time)/1000000,
575                                steps, me->dRate[i].tn0, me->dRate[i].tn);
576                    }
577
578                    /* see if we surpassed our granularity.  if yes, calculate
579                       temporal statistics */
580                    while (steps)
581                    {
582                        /* count temporal rate */
583                        count_temporal_rate(perf->ulID, me, me->dRate + i);
584
585                        TIME_INCREASE(me->dRate[i].last_reporting, me->granularity);
586                        steps--;
587                    }
588                }
589
590                /* rate is */
591                unsigned long delta = TIME_DELTA(perf->time, me->dRate[i].last_timestamp);
592                me->dRate[i].x   += delta;
593                me->dRate[i].tx  += delta;
594                me->dRate[i].xx  += delta * (double) delta;
595                me->dRate[i].txx += delta * (double) delta;
596                me->dRate[i].n   ++;
597                me->dRate[i].tn  ++;
598                me->dRate[i].tn0 ++;
599            }
600            else
601            {
602                me->dRate[i].skip--;
603                if (me->dRate[i].skip == 0)
604                {
605                    TIME_COPY(me->dRate[i].last_reporting, perf->time);
606                    me->dRate[i].txx = me->dRate[i].tx = me->dRate[i].tn = 0;
607                }
608            }
609
610            TIME_COPY(me->dRate[i].last_timestamp, perf->time);
611        }
612    }
613
614    /* ------------------------ SHOT-TO-SHOT METRICS ------------------------ */
615    if (me->dSTS)
616    {
617        if (eModuleAndFlags == (PERF_FlagSending | PERF_FlagFrame | PERF_ModuleHardware))
618        {
619            /* queueing buffers to camera */
620
621            /* see if resolution has changed */
622            if (ulSize < me->dSTS->size_min ||
623                ulSize > me->dSTS->size_max)
624            {
625                /* report burst rate if we have any */
626                if (me->debug)
627                {
628                    if (me->dSTS->dBurst2.n > 0)
629                    {
630                        count_delay(me, "Modified burst shot-to-shot", &me->dSTS->dBurst2, 0);
631                    }
632                    if (me->dSTS->dBurst.n > 0)
633                    {
634                        count_delay(me, "Raw burst shot-to-shot", &me->dSTS->dBurst, -1);
635                    }
636                }
637
638                me->dSTS->dBurst.n = -1;
639                me->dSTS->dBurst2.n = 0;
640
641                /* set new size */
642                me->dSTS->size_min = ulSize > 2048 ? ulSize - 2048 : 0;
643                me->dSTS->size_max = ulSize;
644
645                /* if more than D1-PAL, we assume it is an image, not a preview */
646                if (ulSize > 0x119000)
647                {
648                    /* new burst mode start */
649                    me->dSTS->capturing = 1;
650                }
651                else
652                {
653                    /* preview start */
654                    me->dSTS->capturing = 0;
655                }
656            }
657        }
658        else if (eModuleAndFlags == (PERF_FlagReceived | PERF_FlagFrame | PERF_ModuleHardware))
659        {
660            /* gotten buffers from camera */
661            if (me->dSTS->capturing &&
662                ulSize >= me->dSTS->size_min &&
663                ulSize <= me->dSTS->size_max)
664            {
665                /* see if we have a capture already (we ignore the first) to
666                   count into the modified capture */
667                if (me->dSTS->dBurst.n > 1)
668                {
669                    /* count last time delta */
670                    if (me->dSTS->dBurst.n > 2)
671                    {
672                        delay_add(&me->dSTS->dBurst2, me->dSTS->last_burst);
673                        delay_add(&me->dSTS->dABurst2, me->dSTS->last_burst);
674                        if (me->debug)
675                        {
676                            fprintf(me->fRt, "rtPERF: [%ld] Modified burst shot-to-shot[0x%lX]: %.3g s\n",
677                                    me->dSTS->dBurst2.n, me->dSTS->size_min, 1e-6 * me->dSTS->last_burst);
678                        }
679                    }
680                    me->dSTS->last_burst = TIME_DELTA(perf->time, me->dSTS->dBurst.last_timestamp);
681                }
682                else if (me->dSTS->dBurst.n < 0)
683                {
684                    /* if this is the first shot in the burst sequence */
685                    /* calculate single shot-to-shot delay */
686                    if (me->dSTS->dSingle.n >= 0)
687                    {
688                        if (me->debug)
689                        {
690                            fprintf(me->fRt, "rtPERF: [#%ld] Single shot-to-shot[0x%lX]: %.3g s\n",
691                                    me->dSTS->dSingle.n + 1, me->dSTS->size_min, 1e-6 * TIME_DELTA(perf->time, me->dSTS->dSingle.last_timestamp));
692                        }
693                        delay_delta(&me->dSTS->dSingle, perf);
694                    }
695                }
696
697                if (me->dSTS->dBurst.n >= 0)
698                {
699                    if (me->debug)
700                    {
701                        fprintf(me->fRt, "rtPERF: [#%ld] Raw burst shot-to-shot[0x%lX]: %.3g s\n",
702                                me->dSTS->dBurst.n + 1, me->dSTS->size_min, 1e-6 * TIME_DELTA(perf->time, me->dSTS->dBurst.last_timestamp));
703                    }
704                    delay_add(&me->dSTS->dABurst, TIME_DELTA(perf->time, me->dSTS->dBurst.last_timestamp));
705                }
706                delay_delta(&me->dSTS->dBurst, perf);
707
708                /* keep last captured image time stamp for single shot-to-shot */
709                TIME_COPY(me->dSTS->dSingle.last_timestamp, perf->time);
710                if (me->dSTS->dSingle.n < 0)
711                {
712                    me->dSTS->dSingle.n = 0;  /* captured first time stamp */
713                }
714            }
715        }
716    }
717
718    /* ------------------------ UPTIME METRICS ------------------------ */
719    if (0 && me->dUptime && me->dUptime->measuring)
720    {
721        /* see if we passed our granularity.  if yes, calculate uptime */
722        int steps = TIME_DELTA(perf->time, me->dUptime->last_reporting);
723        if (steps >= me->granularity)
724        {
725            steps /= me->granularity;
726
727            double uptime, idletime, load = 0;
728
729            /* calculate MHz load */
730            get_uptime(&uptime, &idletime);
731            if (uptime > 0 && me->dUptime->success)
732            {
733                me->dUptime->last_idletime = idletime - me->dUptime->last_idletime;
734                me->dUptime->last_uptime = uptime - me->dUptime->last_uptime;
735                if (me->dUptime->last_uptime > 0)
736                {
737                    load = 100. * ((me->dUptime->last_uptime - me->dUptime->last_idletime) /
738                                   me->dUptime->last_uptime);
739
740                    me->dUptime->n += steps;
741                    me->dUptime->x += load * steps;
742                    me->dUptime->xx += load * load * steps;
743                }
744            }
745
746            TIME_INCREASE(me->dUptime->last_reporting, steps * me->granularity);
747
748            if (uptime > 0 && me->dUptime->success)
749            {
750                me->dUptime->last_uptime = uptime;
751                me->dUptime->last_idletime = idletime;
752                if (me->debug)
753                {
754                    fprintf(me->fRt, "rtPERF: [%ld] ARM CPU-load is %.3g%%\n",
755                            TIME_DELTA(perf->time, me->first_time)/1000000,
756                            load);
757                }
758            }
759            else
760            {
761                me->dUptime->success = 0;
762            }
763        }
764    }
765}
766
767void __rt_Command(PERF_Private *perf,
768                  unsigned long ulCommand,
769                  unsigned long ulArgument,
770                  PERF_MODULETYPE eModule)
771{
772    /* get real-time private structure */
773    /* PERF_RT_Private *me = perf->cip.pRT; */
774
775    /* there is nothing to do at this point */
776}
777
778void __rt_Log(PERF_Private *perf,
779              unsigned long ulData1, unsigned long ulData2,
780              unsigned long ulData3)
781{
782    /* get real-time private structure */
783    /* PERF_RT_Private *me = perf->cip.pRT; */
784
785    /* there is nothing to do at this point */
786}
787
788void __rt_SyncAV(PERF_Private *perf,
789                 float pfTimeAudio,
790                 float pfTimeVideo,
791                 PERF_SYNCOPTYPE eSyncOperation)
792{
793    /* get real-time private structure */
794    /* PERF_RT_Private *me = perf->cip.pRT; */
795
796    /* there is nothing to do at this point */
797}
798
799void __rt_ThreadCreated(PERF_Private *perf,
800                        unsigned long ulThreadID,
801                        unsigned long ulThreadName)
802{
803    /* get real-time private structure */
804    /* PERF_RT_Private *me = perf->cip.pRT; */
805
806    /* there is nothing to do at this point. Perhaps we can enable uptime if
807       we still have not created it and it is an audio thread. */
808}
809
810void __rt_Done(PERF_Private *perf)
811{
812    /* get real-time private structure */
813    PERF_RT_Private *me = perf->cip.pRT;
814
815    /* print summaries if required */
816    if (me->summary)
817    {
818        /* uptime summary */
819        if (me->dUptime)
820        {
821            /* get last uptime */
822            start_stop_uptime(me->dUptime, 0);
823
824            fprintf(me->fRt, "rtPERF: ARM CPU-load for%s %c%c%c%c component: ",
825                    me->needSteadyState ? " steady state of" : "",
826                    PERF_FOUR_CHARS(perf->ulID));
827
828            if (me->dUptime->success && me->dUptime->start_uptime)
829            {
830                double load = (100. * (me->dUptime->start_uptime -
831                                      me->dUptime->start_idletime) /
832                               me->dUptime->start_uptime);
833                if (me->dUptime->n)
834                {
835                    double x = me->dUptime->x / me->dUptime->n;
836                    double xx = me->dUptime->xx / me->dUptime->n;
837                    xx = my_sqrt(xx - x * x);
838                    if (me->debug & 2)
839                    {
840                        fprintf(me->fRt, ": %.3g +- %.3g%%\n"
841                                "(temporal difference is: %.3g)\n",
842                                load, xx, x - load);
843                    }
844                    else
845                    {
846                        fprintf(me->fRt, ": %.3g +- %.3g%%\n",
847                                load, xx);
848                    }
849                }
850                else
851                {
852                    fprintf(me->fRt, "%.3g%%\n", load);
853                }
854            }
855            else
856            {
857                fprintf(me->fRt, "FAILED TO CALCULATE\n");
858            }
859        }
860
861        /* rate summary */
862        if (me->nDRate)
863        {
864            int i;
865            for (i = 0; i < me->nDRate; i++)
866            {
867                if (me->dRate[i].n >= MIN_FRAMES_FOR_RATE &&
868                    ((me->debug & 4) || me->dRate[i].tn0 >= MIN_FRAMES_FOR_RATE))
869                {
870
871                    double x = me->dRate[i].x * 1e-6 / me->dRate[i].n;
872
873                    double s = (me->dRate[i].xx ?
874                                (me->dRate[i].x * (double) me->dRate[i].x /
875                                 me->dRate[i].xx / me->dRate[i].n) : 1);
876
877                    fprintf(me->fRt, "rtPERF: ");
878                    print_rate_info(me->fRt,
879                                    perf->ulID, me->dRate[i].modulesAndFlags,
880                                    me->dRate[i].size, me->dRate[i].n);
881                    if (x > 0)
882                    {
883                        if (me->dRate[i].an)
884                        {
885                            double x2 = me->dRate[i].ax / me->dRate[i].an;
886                            double xx = me->dRate[i].axx / me->dRate[i].an;
887                            xx = my_sqrt(xx - x2 * x2);
888                            if (me->debug & 2)
889                            {
890                                fprintf(me->fRt, ": %.3g +- %.3g fps (s=%.3g)\n"
891                                        "(temporal difference is: %.3g)\n",
892                                        1/x, xx, s, x2-1/x);
893                            }
894                            else
895                            {
896                                fprintf(me->fRt, ": %.3g +- %.3g fps (s=%.3g)\n",
897                                        1/x, xx, s);
898                            }
899                        }
900                        else
901                        {
902                            fprintf(me->fRt, ": %.3g fps (s=%.3g)\n", 1/x, s);
903                        }
904                    }
905                    else
906                    {
907                        fprintf(me->fRt, ": FAILED TO CALCULATE\n");
908                    }
909                }
910            }
911        }
912
913        /* shot-to-shot summary */
914        if (me->dSTS)
915        {
916            if (me->dSTS->dABurst2.n > 0)
917            {
918                count_delay(me, "Avg. modified burst shot-to-shot", &me->dSTS->dABurst2, 0);
919            }
920            if (me->dSTS->dABurst.n > 0)
921            {
922                count_delay(me, "Avg. raw burst shot-to-shot", &me->dSTS->dABurst, 0);
923            }
924            if (me->dSTS->dSingle.n > 0)
925            {
926                count_delay(me, "Avg. single shot-to-shot", &me->dSTS->dSingle, -1);
927            }
928        }
929    }
930}
931
932
933#endif
934