1 /*
2  * Copyright (c) 2011-2012, The Linux Foundation. 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 are
6  * 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
10  *     copyright notice, this list of conditions and the following
11  *     disclaimer in the documentation and/or other materials provided
12  *     with the distribution.
13  *   * Neither the name of The Linux Foundation nor the names of its
14  *     contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #define LOG_NDDEBUG 0
31 #define __STDC_FORMAT_MACROS 1
32 #include <inttypes.h>
33 
34 #include "profiler.h"
35 
36 #ifdef DEBUG_CALC_FPS
37 
38 
39 ANDROID_SINGLETON_STATIC_INSTANCE(qdutils::CalcFps) ;
40 
41 namespace qdutils {
42 
CalcFps()43 CalcFps::CalcFps() {
44     debug_fps_level = 0;
45     Init();
46 }
47 
~CalcFps()48 CalcFps::~CalcFps() {
49 }
50 
Init()51 void CalcFps::Init() {
52     char prop[PROPERTY_VALUE_MAX];
53     property_get("debug.gr.calcfps", prop, "0");
54     debug_fps_level = atoi(prop);
55     if (debug_fps_level > MAX_DEBUG_FPS_LEVEL) {
56         ALOGW("out of range value for debug.gr.calcfps, using 0");
57         debug_fps_level = 0;
58     }
59 
60     ALOGD("DEBUG_CALC_FPS: %d", debug_fps_level);
61     populate_debug_fps_metadata();
62 }
63 
Fps()64 void CalcFps::Fps() {
65     if (debug_fps_level > 0)
66         calc_fps(ns2us(systemTime()));
67 }
68 
populate_debug_fps_metadata(void)69 void CalcFps::populate_debug_fps_metadata(void)
70 {
71     char prop[PROPERTY_VALUE_MAX];
72 
73     /*defaults calculation of fps to based on number of frames*/
74     property_get("debug.gr.calcfps.type", prop, "0");
75     debug_fps_metadata.type = (debug_fps_metadata_t::DfmType) atoi(prop);
76 
77     /*defaults to 1000ms*/
78     property_get("debug.gr.calcfps.timeperiod", prop, "1000");
79     debug_fps_metadata.time_period = atoi(prop);
80 
81     property_get("debug.gr.calcfps.period", prop, "10");
82     debug_fps_metadata.period = atoi(prop);
83 
84     if (debug_fps_metadata.period > MAX_FPS_CALC_PERIOD_IN_FRAMES) {
85         debug_fps_metadata.period = MAX_FPS_CALC_PERIOD_IN_FRAMES;
86     }
87 
88     /* default ignorethresh_us: 500 milli seconds */
89     property_get("debug.gr.calcfps.ignorethresh_us", prop, "500000");
90     debug_fps_metadata.ignorethresh_us = atoi(prop);
91 
92     debug_fps_metadata.framearrival_steps =
93         (unsigned int)(debug_fps_metadata.ignorethresh_us / 16666);
94 
95     if (debug_fps_metadata.framearrival_steps > MAX_FRAMEARRIVAL_STEPS) {
96         debug_fps_metadata.framearrival_steps = MAX_FRAMEARRIVAL_STEPS;
97         debug_fps_metadata.ignorethresh_us =
98             debug_fps_metadata.framearrival_steps * 16666;
99     }
100 
101     /* 2ms margin of error for the gettimeofday */
102     debug_fps_metadata.margin_us = 2000;
103 
104     for (unsigned int i = 0; i < MAX_FRAMEARRIVAL_STEPS; i++)
105         debug_fps_metadata.accum_framearrivals[i] = 0;
106 
107     debug_fps_metadata.curr_frame = 0;
108 
109     ALOGD("period: %u", debug_fps_metadata.period);
110     ALOGD("ignorethresh_us: %" PRId64, debug_fps_metadata.ignorethresh_us);
111 }
112 
print_fps(float fps)113 void CalcFps::print_fps(float fps)
114 {
115     if (debug_fps_metadata_t::DFM_FRAMES == debug_fps_metadata.type)
116         ALOGD("FPS for last %d frames: %3.2f", debug_fps_metadata.period, fps);
117     else
118         ALOGD("FPS for last (%f ms, %d frames): %3.2f",
119               debug_fps_metadata.time_elapsed,
120               debug_fps_metadata.curr_frame, fps);
121 
122     debug_fps_metadata.curr_frame = 0;
123     debug_fps_metadata.time_elapsed = 0.0;
124 
125     if (debug_fps_level > 1) {
126         ALOGD("Frame Arrival Distribution:");
127         for (unsigned int i = 0;
128              i < ((debug_fps_metadata.framearrival_steps / 6) + 1);
129              i++) {
130             ALOGD("%" PRId64" %" PRId64" %" PRId64" %" PRId64" %" PRId64" %" PRId64,
131                   debug_fps_metadata.accum_framearrivals[i*6],
132                   debug_fps_metadata.accum_framearrivals[i*6+1],
133                   debug_fps_metadata.accum_framearrivals[i*6+2],
134                   debug_fps_metadata.accum_framearrivals[i*6+3],
135                   debug_fps_metadata.accum_framearrivals[i*6+4],
136                   debug_fps_metadata.accum_framearrivals[i*6+5]);
137         }
138 
139         /* We are done with displaying, now clear the stats */
140         for (unsigned int i = 0;
141              i < debug_fps_metadata.framearrival_steps;
142              i++)
143             debug_fps_metadata.accum_framearrivals[i] = 0;
144     }
145     return;
146 }
147 
calc_fps(nsecs_t currtime_us)148 void CalcFps::calc_fps(nsecs_t currtime_us)
149 {
150     static nsecs_t oldtime_us = 0;
151 
152     nsecs_t diff = currtime_us - oldtime_us;
153 
154     oldtime_us = currtime_us;
155 
156     if (debug_fps_metadata_t::DFM_FRAMES == debug_fps_metadata.type &&
157         diff > debug_fps_metadata.ignorethresh_us) {
158         return;
159     }
160 
161     if (debug_fps_metadata.curr_frame < MAX_FPS_CALC_PERIOD_IN_FRAMES) {
162         debug_fps_metadata.framearrivals[debug_fps_metadata.curr_frame] = diff;
163     }
164 
165     debug_fps_metadata.curr_frame++;
166 
167     if (debug_fps_level > 1) {
168         unsigned int currstep =
169             (unsigned int)(diff + debug_fps_metadata.margin_us) / 16666;
170 
171         if (currstep < debug_fps_metadata.framearrival_steps) {
172             debug_fps_metadata.accum_framearrivals[currstep-1]++;
173         }
174     }
175 
176     if (debug_fps_metadata_t::DFM_FRAMES == debug_fps_metadata.type) {
177         if (debug_fps_metadata.curr_frame == debug_fps_metadata.period) {
178             /* time to calculate and display FPS */
179             nsecs_t sum = 0;
180             for (unsigned int i = 0; i < debug_fps_metadata.period; i++)
181                 sum += debug_fps_metadata.framearrivals[i];
182             print_fps(float(float(debug_fps_metadata.period * 1000000) /
183                                                               (float)sum));
184         }
185     }
186     else if (debug_fps_metadata_t::DFM_TIME == debug_fps_metadata.type) {
187         debug_fps_metadata.time_elapsed += (float)((float)diff/1000.0);
188         if (debug_fps_metadata.time_elapsed >= debug_fps_metadata.time_period) {
189             float fps = float(1000.0 * debug_fps_metadata.curr_frame/
190                                             debug_fps_metadata.time_elapsed);
191             print_fps(fps);
192         }
193     }
194     return;
195 }
196 };//namespace qomutils
197 #endif
198