xref: /rockchip-linux_mpp/osal/mpp_time.c (revision 437bfbeb9567cca9cd9080e3f6954aa9d6a94f18)
1*437bfbebSnyanmisaka /* SPDX-License-Identifier: Apache-2.0 OR MIT */
2*437bfbebSnyanmisaka /*
3*437bfbebSnyanmisaka  * Copyright (c) 2015 Rockchip Electronics Co., Ltd.
4*437bfbebSnyanmisaka  */
5*437bfbebSnyanmisaka 
6*437bfbebSnyanmisaka #define MODULE_TAG "mpp_time"
7*437bfbebSnyanmisaka 
8*437bfbebSnyanmisaka #include <time.h>
9*437bfbebSnyanmisaka #include <errno.h>
10*437bfbebSnyanmisaka #include <string.h>
11*437bfbebSnyanmisaka #include <sys/timerfd.h>
12*437bfbebSnyanmisaka #include <sys/epoll.h>
13*437bfbebSnyanmisaka 
14*437bfbebSnyanmisaka #include "mpp_mem.h"
15*437bfbebSnyanmisaka #include "mpp_time.h"
16*437bfbebSnyanmisaka #include "mpp_debug.h"
17*437bfbebSnyanmisaka #include "mpp_common.h"
18*437bfbebSnyanmisaka #include "mpp_thread.h"
19*437bfbebSnyanmisaka 
mpp_time()20*437bfbebSnyanmisaka rk_s64 mpp_time()
21*437bfbebSnyanmisaka {
22*437bfbebSnyanmisaka     struct timespec time = {0, 0};
23*437bfbebSnyanmisaka 
24*437bfbebSnyanmisaka     clock_gettime(CLOCK_MONOTONIC, &time);
25*437bfbebSnyanmisaka     return (rk_s64)time.tv_sec * 1000000 + (rk_s64)time.tv_nsec / 1000;
26*437bfbebSnyanmisaka }
27*437bfbebSnyanmisaka 
mpp_time_diff(rk_s64 start,rk_s64 end,rk_s64 limit,const char * fmt)28*437bfbebSnyanmisaka void mpp_time_diff(rk_s64 start, rk_s64 end, rk_s64 limit, const char *fmt)
29*437bfbebSnyanmisaka {
30*437bfbebSnyanmisaka     rk_s64 diff = end - start;
31*437bfbebSnyanmisaka 
32*437bfbebSnyanmisaka     if (diff >= limit)
33*437bfbebSnyanmisaka         mpp_dbg(MPP_DBG_TIMING, "%s timing %lld us\n", fmt, diff);
34*437bfbebSnyanmisaka }
35*437bfbebSnyanmisaka 
36*437bfbebSnyanmisaka typedef struct MppClockImpl_t {
37*437bfbebSnyanmisaka     const char *check;
38*437bfbebSnyanmisaka     char    name[16];
39*437bfbebSnyanmisaka     rk_u32  enable;
40*437bfbebSnyanmisaka     rk_s64  base;
41*437bfbebSnyanmisaka     rk_s64  time;
42*437bfbebSnyanmisaka     rk_s64  sum;
43*437bfbebSnyanmisaka     rk_s64  count;
44*437bfbebSnyanmisaka } MppClockImpl;
45*437bfbebSnyanmisaka 
46*437bfbebSnyanmisaka static const char *clock_name = "mpp_clock";
47*437bfbebSnyanmisaka 
check_is_mpp_clock(void * clock)48*437bfbebSnyanmisaka MPP_RET check_is_mpp_clock(void *clock)
49*437bfbebSnyanmisaka {
50*437bfbebSnyanmisaka     if (clock && ((MppClockImpl*)clock)->check == clock_name)
51*437bfbebSnyanmisaka         return MPP_OK;
52*437bfbebSnyanmisaka 
53*437bfbebSnyanmisaka     mpp_err_f("pointer %p failed on check\n", clock);
54*437bfbebSnyanmisaka     mpp_abort();
55*437bfbebSnyanmisaka     return MPP_NOK;
56*437bfbebSnyanmisaka }
57*437bfbebSnyanmisaka 
mpp_clock_get(const char * name)58*437bfbebSnyanmisaka MppClock mpp_clock_get(const char *name)
59*437bfbebSnyanmisaka {
60*437bfbebSnyanmisaka     MppClockImpl *impl = mpp_calloc(MppClockImpl, 1);
61*437bfbebSnyanmisaka 
62*437bfbebSnyanmisaka     if (impl) {
63*437bfbebSnyanmisaka         impl->check = clock_name;
64*437bfbebSnyanmisaka         snprintf(impl->name, sizeof(impl->name) - 1, name, NULL);
65*437bfbebSnyanmisaka     } else
66*437bfbebSnyanmisaka         mpp_err_f("malloc failed\n");
67*437bfbebSnyanmisaka 
68*437bfbebSnyanmisaka     return impl;
69*437bfbebSnyanmisaka }
70*437bfbebSnyanmisaka 
mpp_clock_put(MppClock clock)71*437bfbebSnyanmisaka void mpp_clock_put(MppClock clock)
72*437bfbebSnyanmisaka {
73*437bfbebSnyanmisaka     if (check_is_mpp_clock(clock)) {
74*437bfbebSnyanmisaka         mpp_err_f("invalid clock %p\n", clock);
75*437bfbebSnyanmisaka         return;
76*437bfbebSnyanmisaka     }
77*437bfbebSnyanmisaka 
78*437bfbebSnyanmisaka     mpp_free(clock);
79*437bfbebSnyanmisaka }
80*437bfbebSnyanmisaka 
mpp_clock_enable(MppClock clock,rk_u32 enable)81*437bfbebSnyanmisaka void mpp_clock_enable(MppClock clock, rk_u32 enable)
82*437bfbebSnyanmisaka {
83*437bfbebSnyanmisaka     if (check_is_mpp_clock(clock)) {
84*437bfbebSnyanmisaka         mpp_err_f("invalid clock %p\n", clock);
85*437bfbebSnyanmisaka     } else {
86*437bfbebSnyanmisaka         MppClockImpl *p = (MppClockImpl *)clock;
87*437bfbebSnyanmisaka 
88*437bfbebSnyanmisaka         p->enable = (enable) ? (1) : (0);
89*437bfbebSnyanmisaka     }
90*437bfbebSnyanmisaka }
91*437bfbebSnyanmisaka 
mpp_clock_start(MppClock clock)92*437bfbebSnyanmisaka rk_s64 mpp_clock_start(MppClock clock)
93*437bfbebSnyanmisaka {
94*437bfbebSnyanmisaka     MppClockImpl *p = (MppClockImpl *)clock;
95*437bfbebSnyanmisaka 
96*437bfbebSnyanmisaka     if (check_is_mpp_clock(p)) {
97*437bfbebSnyanmisaka         mpp_err_f("invalid clock %p\n", p);
98*437bfbebSnyanmisaka         return 0;
99*437bfbebSnyanmisaka     }
100*437bfbebSnyanmisaka 
101*437bfbebSnyanmisaka     if (!p->enable)
102*437bfbebSnyanmisaka         return 0;
103*437bfbebSnyanmisaka 
104*437bfbebSnyanmisaka     p->base = mpp_time();
105*437bfbebSnyanmisaka     p->time = 0;
106*437bfbebSnyanmisaka     return p->base;
107*437bfbebSnyanmisaka }
108*437bfbebSnyanmisaka 
mpp_clock_pause(MppClock clock)109*437bfbebSnyanmisaka rk_s64 mpp_clock_pause(MppClock clock)
110*437bfbebSnyanmisaka {
111*437bfbebSnyanmisaka     MppClockImpl *p = (MppClockImpl *)clock;
112*437bfbebSnyanmisaka     rk_s64 time;
113*437bfbebSnyanmisaka 
114*437bfbebSnyanmisaka     if (check_is_mpp_clock(p)) {
115*437bfbebSnyanmisaka         mpp_err_f("invalid clock %p\n", p);
116*437bfbebSnyanmisaka         return 0;
117*437bfbebSnyanmisaka     }
118*437bfbebSnyanmisaka 
119*437bfbebSnyanmisaka     if (!p->enable)
120*437bfbebSnyanmisaka         return 0;
121*437bfbebSnyanmisaka 
122*437bfbebSnyanmisaka     time = mpp_time();
123*437bfbebSnyanmisaka 
124*437bfbebSnyanmisaka     if (!p->time) {
125*437bfbebSnyanmisaka         // first pause after start
126*437bfbebSnyanmisaka         p->sum += time - p->base;
127*437bfbebSnyanmisaka         p->count++;
128*437bfbebSnyanmisaka     }
129*437bfbebSnyanmisaka 
130*437bfbebSnyanmisaka     p->time = time;
131*437bfbebSnyanmisaka 
132*437bfbebSnyanmisaka     return p->time - p->base;
133*437bfbebSnyanmisaka }
134*437bfbebSnyanmisaka 
mpp_clock_reset(MppClock clock)135*437bfbebSnyanmisaka rk_s64 mpp_clock_reset(MppClock clock)
136*437bfbebSnyanmisaka {
137*437bfbebSnyanmisaka     MppClockImpl *p = (MppClockImpl *)clock;
138*437bfbebSnyanmisaka 
139*437bfbebSnyanmisaka     if (check_is_mpp_clock(p)) {
140*437bfbebSnyanmisaka         mpp_err_f("invalid clock %p\n", p);
141*437bfbebSnyanmisaka     } else {
142*437bfbebSnyanmisaka         p->base = 0;
143*437bfbebSnyanmisaka         p->time = 0;
144*437bfbebSnyanmisaka         p->sum = 0;
145*437bfbebSnyanmisaka         p->count = 0;
146*437bfbebSnyanmisaka     }
147*437bfbebSnyanmisaka 
148*437bfbebSnyanmisaka     return 0;
149*437bfbebSnyanmisaka }
150*437bfbebSnyanmisaka 
mpp_clock_get_sum(MppClock clock)151*437bfbebSnyanmisaka rk_s64 mpp_clock_get_sum(MppClock clock)
152*437bfbebSnyanmisaka {
153*437bfbebSnyanmisaka     MppClockImpl *p = (MppClockImpl *)clock;
154*437bfbebSnyanmisaka 
155*437bfbebSnyanmisaka     if (check_is_mpp_clock(p)) {
156*437bfbebSnyanmisaka         mpp_err_f("invalid clock %p\n", p);
157*437bfbebSnyanmisaka         return 0;
158*437bfbebSnyanmisaka     }
159*437bfbebSnyanmisaka 
160*437bfbebSnyanmisaka     return (p->enable) ? (p->sum) : (0);
161*437bfbebSnyanmisaka }
162*437bfbebSnyanmisaka 
mpp_clock_get_count(MppClock clock)163*437bfbebSnyanmisaka rk_s64 mpp_clock_get_count(MppClock clock)
164*437bfbebSnyanmisaka {
165*437bfbebSnyanmisaka     MppClockImpl *p = (MppClockImpl *)clock;
166*437bfbebSnyanmisaka 
167*437bfbebSnyanmisaka     if (check_is_mpp_clock(p)) {
168*437bfbebSnyanmisaka         mpp_err_f("invalid clock %p\n", p);
169*437bfbebSnyanmisaka         return 0;
170*437bfbebSnyanmisaka     }
171*437bfbebSnyanmisaka 
172*437bfbebSnyanmisaka     return (p->enable) ? (p->count) : (0);
173*437bfbebSnyanmisaka }
174*437bfbebSnyanmisaka 
mpp_clock_get_name(MppClock clock)175*437bfbebSnyanmisaka const char *mpp_clock_get_name(MppClock clock)
176*437bfbebSnyanmisaka {
177*437bfbebSnyanmisaka     MppClockImpl *p = (MppClockImpl *)clock;
178*437bfbebSnyanmisaka 
179*437bfbebSnyanmisaka     if (check_is_mpp_clock(p)) {
180*437bfbebSnyanmisaka         mpp_err_f("invalid clock %p\n", p);
181*437bfbebSnyanmisaka         return NULL;
182*437bfbebSnyanmisaka     }
183*437bfbebSnyanmisaka 
184*437bfbebSnyanmisaka     return p->name;
185*437bfbebSnyanmisaka }
186*437bfbebSnyanmisaka 
187*437bfbebSnyanmisaka typedef struct MppTimerImpl_t {
188*437bfbebSnyanmisaka     const char          *check;
189*437bfbebSnyanmisaka     char                name[16];
190*437bfbebSnyanmisaka 
191*437bfbebSnyanmisaka     rk_s32              enabled;
192*437bfbebSnyanmisaka     rk_s32              initial;
193*437bfbebSnyanmisaka     rk_s32              interval;
194*437bfbebSnyanmisaka     rk_s32              timer_fd;
195*437bfbebSnyanmisaka     rk_s32              epoll_fd;
196*437bfbebSnyanmisaka 
197*437bfbebSnyanmisaka     MppThread           *thd;
198*437bfbebSnyanmisaka     MppThreadFunc       func;
199*437bfbebSnyanmisaka     void                *ctx;
200*437bfbebSnyanmisaka } MppTimerImpl;
201*437bfbebSnyanmisaka 
202*437bfbebSnyanmisaka static const char *timer_name = "mpp_timer";
203*437bfbebSnyanmisaka 
check_is_mpp_timer(void * timer)204*437bfbebSnyanmisaka MPP_RET check_is_mpp_timer(void *timer)
205*437bfbebSnyanmisaka {
206*437bfbebSnyanmisaka     if (timer && ((MppTimerImpl*)timer)->check == timer_name)
207*437bfbebSnyanmisaka         return MPP_OK;
208*437bfbebSnyanmisaka 
209*437bfbebSnyanmisaka     mpp_err_f("pointer %p failed on check\n", timer);
210*437bfbebSnyanmisaka     mpp_abort();
211*437bfbebSnyanmisaka     return MPP_NOK;
212*437bfbebSnyanmisaka }
213*437bfbebSnyanmisaka 
mpp_timer_thread(void * ctx)214*437bfbebSnyanmisaka static void *mpp_timer_thread(void *ctx)
215*437bfbebSnyanmisaka {
216*437bfbebSnyanmisaka     struct itimerspec ts;
217*437bfbebSnyanmisaka     MppTimerImpl *impl = (MppTimerImpl *)ctx;
218*437bfbebSnyanmisaka     MppThread *thd = impl->thd;
219*437bfbebSnyanmisaka     rk_s32 timer_fd = impl->timer_fd;
220*437bfbebSnyanmisaka     rk_s32 ret = 0;
221*437bfbebSnyanmisaka 
222*437bfbebSnyanmisaka     // first expire time
223*437bfbebSnyanmisaka     ts.it_value.tv_sec = impl->initial / 1000;
224*437bfbebSnyanmisaka     ts.it_value.tv_nsec = (impl->initial % 1000) * 1000;
225*437bfbebSnyanmisaka 
226*437bfbebSnyanmisaka     // last expire time
227*437bfbebSnyanmisaka     ts.it_interval.tv_sec = impl->interval / 1000;
228*437bfbebSnyanmisaka     ts.it_interval.tv_nsec = (impl->interval % 1000) * 1000 * 1000;
229*437bfbebSnyanmisaka 
230*437bfbebSnyanmisaka     ret = timerfd_settime(timer_fd, 0, &ts, NULL);
231*437bfbebSnyanmisaka     if (ret < 0) {
232*437bfbebSnyanmisaka         mpp_err("timerfd_settime error, Error:[%d:%s]", errno, strerror(errno));
233*437bfbebSnyanmisaka         return NULL;
234*437bfbebSnyanmisaka     }
235*437bfbebSnyanmisaka 
236*437bfbebSnyanmisaka     while (1) {
237*437bfbebSnyanmisaka         struct epoll_event events;
238*437bfbebSnyanmisaka         rk_s32 fd_cnt;
239*437bfbebSnyanmisaka 
240*437bfbebSnyanmisaka         if (MPP_THREAD_RUNNING != mpp_thread_get_status(thd, THREAD_WORK))
241*437bfbebSnyanmisaka             break;
242*437bfbebSnyanmisaka 
243*437bfbebSnyanmisaka         memset(&events, 0, sizeof(events));
244*437bfbebSnyanmisaka 
245*437bfbebSnyanmisaka         /* wait epoll event */
246*437bfbebSnyanmisaka         fd_cnt = epoll_wait(impl->epoll_fd, &events, 1, 500);
247*437bfbebSnyanmisaka         if (fd_cnt && (events.events & EPOLLIN) && (events.data.fd == timer_fd)) {
248*437bfbebSnyanmisaka             rk_u64 exp = 0;
249*437bfbebSnyanmisaka             ssize_t cnt = read(timer_fd, &exp, sizeof(exp));
250*437bfbebSnyanmisaka 
251*437bfbebSnyanmisaka             mpp_assert(cnt == sizeof(exp));
252*437bfbebSnyanmisaka             impl->func(impl->ctx);
253*437bfbebSnyanmisaka         }
254*437bfbebSnyanmisaka     }
255*437bfbebSnyanmisaka 
256*437bfbebSnyanmisaka     return NULL;
257*437bfbebSnyanmisaka }
258*437bfbebSnyanmisaka 
mpp_timer_get(const char * name)259*437bfbebSnyanmisaka MppTimer mpp_timer_get(const char *name)
260*437bfbebSnyanmisaka {
261*437bfbebSnyanmisaka     MppTimerImpl *impl = NULL;
262*437bfbebSnyanmisaka     rk_s32 timer_fd = -1;
263*437bfbebSnyanmisaka     rk_s32 epoll_fd = -1;
264*437bfbebSnyanmisaka 
265*437bfbebSnyanmisaka     do {
266*437bfbebSnyanmisaka         struct epoll_event event;
267*437bfbebSnyanmisaka 
268*437bfbebSnyanmisaka         impl = mpp_calloc(MppTimerImpl, 1);
269*437bfbebSnyanmisaka         if (!impl) {
270*437bfbebSnyanmisaka             mpp_err_f("malloc failed\n");
271*437bfbebSnyanmisaka             break;
272*437bfbebSnyanmisaka         }
273*437bfbebSnyanmisaka 
274*437bfbebSnyanmisaka         timer_fd = timerfd_create(CLOCK_REALTIME, 0);
275*437bfbebSnyanmisaka         if (timer_fd < 0)
276*437bfbebSnyanmisaka             break;
277*437bfbebSnyanmisaka 
278*437bfbebSnyanmisaka         epoll_fd = epoll_create(1);
279*437bfbebSnyanmisaka         if (epoll_fd < 0)
280*437bfbebSnyanmisaka             break;
281*437bfbebSnyanmisaka 
282*437bfbebSnyanmisaka         memset(&event, 0, sizeof(event));
283*437bfbebSnyanmisaka         event.data.fd = timer_fd;
284*437bfbebSnyanmisaka         event.events = EPOLLIN | EPOLLET;
285*437bfbebSnyanmisaka 
286*437bfbebSnyanmisaka         if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, timer_fd, &event) < 0)
287*437bfbebSnyanmisaka             break;
288*437bfbebSnyanmisaka 
289*437bfbebSnyanmisaka         impl->timer_fd = timer_fd;
290*437bfbebSnyanmisaka         impl->epoll_fd = epoll_fd;
291*437bfbebSnyanmisaka         /* default 1 second (1000ms) looper */
292*437bfbebSnyanmisaka         impl->initial  = 1000;
293*437bfbebSnyanmisaka         impl->interval = 1000;
294*437bfbebSnyanmisaka         impl->check = timer_name;
295*437bfbebSnyanmisaka         snprintf(impl->name, sizeof(impl->name) - 1, name, NULL);
296*437bfbebSnyanmisaka 
297*437bfbebSnyanmisaka         return impl;
298*437bfbebSnyanmisaka     } while (0);
299*437bfbebSnyanmisaka 
300*437bfbebSnyanmisaka     mpp_err_f("failed to create timer\n");
301*437bfbebSnyanmisaka 
302*437bfbebSnyanmisaka     if (impl) {
303*437bfbebSnyanmisaka         mpp_free(impl);
304*437bfbebSnyanmisaka         impl = NULL;
305*437bfbebSnyanmisaka     }
306*437bfbebSnyanmisaka 
307*437bfbebSnyanmisaka     if (timer_fd >= 0) {
308*437bfbebSnyanmisaka         close(timer_fd);
309*437bfbebSnyanmisaka         timer_fd = -1;
310*437bfbebSnyanmisaka     }
311*437bfbebSnyanmisaka 
312*437bfbebSnyanmisaka     if (epoll_fd >= 0) {
313*437bfbebSnyanmisaka         close(epoll_fd);
314*437bfbebSnyanmisaka         epoll_fd = -1;
315*437bfbebSnyanmisaka     }
316*437bfbebSnyanmisaka 
317*437bfbebSnyanmisaka     return NULL;
318*437bfbebSnyanmisaka }
319*437bfbebSnyanmisaka 
mpp_timer_set_callback(MppTimer timer,MppThreadFunc func,void * ctx)320*437bfbebSnyanmisaka void mpp_timer_set_callback(MppTimer timer, MppThreadFunc func, void *ctx)
321*437bfbebSnyanmisaka {
322*437bfbebSnyanmisaka     MppTimerImpl *impl = (MppTimerImpl *)timer;
323*437bfbebSnyanmisaka 
324*437bfbebSnyanmisaka     if (check_is_mpp_timer(impl)) {
325*437bfbebSnyanmisaka         mpp_err_f("invalid timer %p\n", impl);
326*437bfbebSnyanmisaka         return;
327*437bfbebSnyanmisaka     }
328*437bfbebSnyanmisaka 
329*437bfbebSnyanmisaka     if (!func) {
330*437bfbebSnyanmisaka         mpp_err_f("invalid NULL callback\n");
331*437bfbebSnyanmisaka         return;
332*437bfbebSnyanmisaka     }
333*437bfbebSnyanmisaka 
334*437bfbebSnyanmisaka     impl->func = func;
335*437bfbebSnyanmisaka     impl->ctx = ctx;
336*437bfbebSnyanmisaka }
337*437bfbebSnyanmisaka 
mpp_timer_set_timing(MppTimer timer,rk_s32 initial,rk_s32 interval)338*437bfbebSnyanmisaka void mpp_timer_set_timing(MppTimer timer, rk_s32 initial, rk_s32 interval)
339*437bfbebSnyanmisaka {
340*437bfbebSnyanmisaka     MppTimerImpl *impl = (MppTimerImpl *)timer;
341*437bfbebSnyanmisaka 
342*437bfbebSnyanmisaka     if (check_is_mpp_timer(impl)) {
343*437bfbebSnyanmisaka         mpp_err_f("invalid timer %p\n", impl);
344*437bfbebSnyanmisaka         return;
345*437bfbebSnyanmisaka     }
346*437bfbebSnyanmisaka 
347*437bfbebSnyanmisaka     impl->initial = initial;
348*437bfbebSnyanmisaka     impl->interval = interval;
349*437bfbebSnyanmisaka }
350*437bfbebSnyanmisaka 
mpp_timer_set_enable(MppTimer timer,rk_s32 enable)351*437bfbebSnyanmisaka void mpp_timer_set_enable(MppTimer timer, rk_s32 enable)
352*437bfbebSnyanmisaka {
353*437bfbebSnyanmisaka     MppTimerImpl *impl = (MppTimerImpl *)timer;
354*437bfbebSnyanmisaka 
355*437bfbebSnyanmisaka     if (check_is_mpp_timer(impl)) {
356*437bfbebSnyanmisaka         mpp_err_f("invalid timer %p\n", impl);
357*437bfbebSnyanmisaka         return;
358*437bfbebSnyanmisaka     }
359*437bfbebSnyanmisaka 
360*437bfbebSnyanmisaka     if (!impl->func || impl->initial < 0 || impl->interval < 0) {
361*437bfbebSnyanmisaka         mpp_err_f("invalid func %p initial %d interval %d\n",
362*437bfbebSnyanmisaka                   impl->func, impl->initial, impl->interval);
363*437bfbebSnyanmisaka         return;
364*437bfbebSnyanmisaka     }
365*437bfbebSnyanmisaka 
366*437bfbebSnyanmisaka     if (enable) {
367*437bfbebSnyanmisaka         if (!impl->enabled && !impl->thd) {
368*437bfbebSnyanmisaka             MppThread *thd = mpp_thread_create(mpp_timer_thread, impl, impl->name);
369*437bfbebSnyanmisaka 
370*437bfbebSnyanmisaka             if (thd) {
371*437bfbebSnyanmisaka                 impl->thd = thd;
372*437bfbebSnyanmisaka                 impl->enabled = 1;
373*437bfbebSnyanmisaka                 mpp_thread_start(impl->thd);
374*437bfbebSnyanmisaka             }
375*437bfbebSnyanmisaka         }
376*437bfbebSnyanmisaka     } else {
377*437bfbebSnyanmisaka         if (impl->enabled && impl->thd) {
378*437bfbebSnyanmisaka             mpp_thread_stop(impl->thd);
379*437bfbebSnyanmisaka             impl->enabled = 0;
380*437bfbebSnyanmisaka         }
381*437bfbebSnyanmisaka     }
382*437bfbebSnyanmisaka }
383*437bfbebSnyanmisaka 
mpp_timer_put(MppTimer timer)384*437bfbebSnyanmisaka void mpp_timer_put(MppTimer timer)
385*437bfbebSnyanmisaka {
386*437bfbebSnyanmisaka     MppTimerImpl *impl = (MppTimerImpl *)timer;
387*437bfbebSnyanmisaka 
388*437bfbebSnyanmisaka     if (check_is_mpp_timer(impl)) {
389*437bfbebSnyanmisaka         mpp_err_f("invalid timer %p\n", impl);
390*437bfbebSnyanmisaka         return;
391*437bfbebSnyanmisaka     }
392*437bfbebSnyanmisaka 
393*437bfbebSnyanmisaka     if (impl->enabled)
394*437bfbebSnyanmisaka         mpp_timer_set_enable(impl, 0);
395*437bfbebSnyanmisaka 
396*437bfbebSnyanmisaka     if (impl->timer_fd >= 0) {
397*437bfbebSnyanmisaka         close(impl->timer_fd);
398*437bfbebSnyanmisaka         impl->timer_fd = -1;
399*437bfbebSnyanmisaka     }
400*437bfbebSnyanmisaka 
401*437bfbebSnyanmisaka     if (impl->epoll_fd >= 0) {
402*437bfbebSnyanmisaka         close(impl->epoll_fd);
403*437bfbebSnyanmisaka         impl->epoll_fd = -1;
404*437bfbebSnyanmisaka     }
405*437bfbebSnyanmisaka 
406*437bfbebSnyanmisaka     if (impl->thd) {
407*437bfbebSnyanmisaka         mpp_thread_destroy(impl->thd);
408*437bfbebSnyanmisaka         impl->thd = NULL;
409*437bfbebSnyanmisaka     }
410*437bfbebSnyanmisaka 
411*437bfbebSnyanmisaka     if (impl) {
412*437bfbebSnyanmisaka         mpp_free(impl);
413*437bfbebSnyanmisaka         impl = NULL;
414*437bfbebSnyanmisaka     }
415*437bfbebSnyanmisaka }
416*437bfbebSnyanmisaka 
417*437bfbebSnyanmisaka #define STOPWATCH_TRACE_STR_LEN 64
418*437bfbebSnyanmisaka 
419*437bfbebSnyanmisaka typedef struct MppStopwatchNode_t {
420*437bfbebSnyanmisaka     char                event[STOPWATCH_TRACE_STR_LEN];
421*437bfbebSnyanmisaka     rk_s64              time;
422*437bfbebSnyanmisaka } MppStopwatchNode;
423*437bfbebSnyanmisaka 
424*437bfbebSnyanmisaka typedef struct MppStopwatchImpl_t {
425*437bfbebSnyanmisaka     const char          *check;
426*437bfbebSnyanmisaka     char                name[STOPWATCH_TRACE_STR_LEN];
427*437bfbebSnyanmisaka 
428*437bfbebSnyanmisaka     rk_s32              max_count;
429*437bfbebSnyanmisaka     rk_s32              filled_count;
430*437bfbebSnyanmisaka     rk_s32              show_on_exit;
431*437bfbebSnyanmisaka     rk_s32              log_len;
432*437bfbebSnyanmisaka     rk_s64              time_elipsed;
433*437bfbebSnyanmisaka 
434*437bfbebSnyanmisaka     MppStopwatchNode    *nodes;
435*437bfbebSnyanmisaka } MppStopwatchImpl;
436*437bfbebSnyanmisaka 
437*437bfbebSnyanmisaka static const char *stopwatch_name = "mpp_stopwatch";
438*437bfbebSnyanmisaka 
check_is_mpp_stopwatch(void * stopwatch)439*437bfbebSnyanmisaka MPP_RET check_is_mpp_stopwatch(void *stopwatch)
440*437bfbebSnyanmisaka {
441*437bfbebSnyanmisaka     if (stopwatch && ((MppStopwatchImpl*)stopwatch)->check == stopwatch_name)
442*437bfbebSnyanmisaka         return MPP_OK;
443*437bfbebSnyanmisaka 
444*437bfbebSnyanmisaka     mpp_err_f("pointer %p failed on check\n", stopwatch);
445*437bfbebSnyanmisaka     mpp_abort();
446*437bfbebSnyanmisaka     return MPP_NOK;
447*437bfbebSnyanmisaka }
448*437bfbebSnyanmisaka 
mpp_stopwatch_get(const char * name)449*437bfbebSnyanmisaka MppStopwatch mpp_stopwatch_get(const char *name)
450*437bfbebSnyanmisaka {
451*437bfbebSnyanmisaka     MppStopwatchImpl *impl = mpp_calloc(MppStopwatchImpl, 1);
452*437bfbebSnyanmisaka     MppStopwatchNode *nodes = mpp_calloc(MppStopwatchNode, 8);
453*437bfbebSnyanmisaka 
454*437bfbebSnyanmisaka     if (impl && nodes) {
455*437bfbebSnyanmisaka         impl->check = stopwatch_name;
456*437bfbebSnyanmisaka         snprintf(impl->name, sizeof(impl->name) - 1, name, NULL);
457*437bfbebSnyanmisaka         impl->nodes = nodes;
458*437bfbebSnyanmisaka         impl->max_count = 8;
459*437bfbebSnyanmisaka     } else {
460*437bfbebSnyanmisaka         mpp_err_f("malloc failed\n");
461*437bfbebSnyanmisaka         MPP_FREE(impl);
462*437bfbebSnyanmisaka         MPP_FREE(nodes);
463*437bfbebSnyanmisaka     }
464*437bfbebSnyanmisaka 
465*437bfbebSnyanmisaka     return impl;
466*437bfbebSnyanmisaka }
467*437bfbebSnyanmisaka 
mpp_stopwatch_set_show_on_exit(MppStopwatch stopwatch,rk_s32 show_on_exit)468*437bfbebSnyanmisaka void mpp_stopwatch_set_show_on_exit(MppStopwatch stopwatch, rk_s32 show_on_exit)
469*437bfbebSnyanmisaka {
470*437bfbebSnyanmisaka     MppStopwatchImpl *impl = (MppStopwatchImpl *)stopwatch;
471*437bfbebSnyanmisaka 
472*437bfbebSnyanmisaka     if (check_is_mpp_stopwatch(impl)) {
473*437bfbebSnyanmisaka         mpp_err_f("invalid stopwatch %p\n", impl);
474*437bfbebSnyanmisaka         return;
475*437bfbebSnyanmisaka     }
476*437bfbebSnyanmisaka 
477*437bfbebSnyanmisaka     impl->show_on_exit = show_on_exit;
478*437bfbebSnyanmisaka }
479*437bfbebSnyanmisaka 
mpp_stopwatch_record(MppStopwatch stopwatch,const char * event)480*437bfbebSnyanmisaka void mpp_stopwatch_record(MppStopwatch stopwatch, const char *event)
481*437bfbebSnyanmisaka {
482*437bfbebSnyanmisaka     MppStopwatchImpl *impl = (MppStopwatchImpl *)stopwatch;
483*437bfbebSnyanmisaka 
484*437bfbebSnyanmisaka     /* do not print noisy log */
485*437bfbebSnyanmisaka     if (!impl)
486*437bfbebSnyanmisaka         return;
487*437bfbebSnyanmisaka 
488*437bfbebSnyanmisaka     if (check_is_mpp_stopwatch(impl)) {
489*437bfbebSnyanmisaka         mpp_err_f("invalid stopwatch %p on %s\n", impl, event);
490*437bfbebSnyanmisaka         return;
491*437bfbebSnyanmisaka     }
492*437bfbebSnyanmisaka 
493*437bfbebSnyanmisaka     if (impl->filled_count >= impl->max_count) {
494*437bfbebSnyanmisaka         rk_s32 max_count = impl->max_count * 2;
495*437bfbebSnyanmisaka         MppStopwatchNode *nodes = mpp_realloc(impl->nodes, MppStopwatchNode,
496*437bfbebSnyanmisaka                                               max_count);
497*437bfbebSnyanmisaka 
498*437bfbebSnyanmisaka         if (nodes) {
499*437bfbebSnyanmisaka             impl->nodes = nodes;
500*437bfbebSnyanmisaka             impl->max_count = max_count;
501*437bfbebSnyanmisaka         }
502*437bfbebSnyanmisaka     }
503*437bfbebSnyanmisaka 
504*437bfbebSnyanmisaka     if (impl->filled_count < impl->max_count) {
505*437bfbebSnyanmisaka         MppStopwatchNode *node = impl->nodes + impl->filled_count;
506*437bfbebSnyanmisaka 
507*437bfbebSnyanmisaka         node->time = mpp_time();
508*437bfbebSnyanmisaka         if (event) {
509*437bfbebSnyanmisaka             rk_s32 len = snprintf(node->event, sizeof(node->event) - 1, "%s", event);
510*437bfbebSnyanmisaka 
511*437bfbebSnyanmisaka             if (len > impl->log_len)
512*437bfbebSnyanmisaka                 impl->log_len = len;
513*437bfbebSnyanmisaka         }
514*437bfbebSnyanmisaka         impl->filled_count++;
515*437bfbebSnyanmisaka     }
516*437bfbebSnyanmisaka }
517*437bfbebSnyanmisaka 
mpp_stopwatch_put(MppStopwatch stopwatch)518*437bfbebSnyanmisaka void mpp_stopwatch_put(MppStopwatch stopwatch)
519*437bfbebSnyanmisaka {
520*437bfbebSnyanmisaka     MppStopwatchImpl *impl = (MppStopwatchImpl *)stopwatch;
521*437bfbebSnyanmisaka 
522*437bfbebSnyanmisaka     if (check_is_mpp_stopwatch(impl)) {
523*437bfbebSnyanmisaka         mpp_err_f("invalid stopwatch %p\n", impl);
524*437bfbebSnyanmisaka         return;
525*437bfbebSnyanmisaka     }
526*437bfbebSnyanmisaka 
527*437bfbebSnyanmisaka     if (impl->show_on_exit && impl->nodes && impl->filled_count) {
528*437bfbebSnyanmisaka         MppStopwatchNode *node = impl->nodes;
529*437bfbebSnyanmisaka         rk_s64 last_time = node->time;
530*437bfbebSnyanmisaka         rk_s32 i;
531*437bfbebSnyanmisaka         char fmt[32];
532*437bfbebSnyanmisaka 
533*437bfbebSnyanmisaka         snprintf(fmt, sizeof(fmt) - 1, "%%s %%-%ds: %%6.2f\n", impl->log_len);
534*437bfbebSnyanmisaka         node++;
535*437bfbebSnyanmisaka 
536*437bfbebSnyanmisaka         for (i = 1; i < impl->filled_count; i++) {
537*437bfbebSnyanmisaka             mpp_log(fmt, impl->name, node->event,
538*437bfbebSnyanmisaka                     (float)(node->time - last_time) / 1000);
539*437bfbebSnyanmisaka             last_time = node->time;
540*437bfbebSnyanmisaka             node++;
541*437bfbebSnyanmisaka         }
542*437bfbebSnyanmisaka     }
543*437bfbebSnyanmisaka     MPP_FREE(impl->nodes);
544*437bfbebSnyanmisaka     MPP_FREE(impl);
545*437bfbebSnyanmisaka }
546*437bfbebSnyanmisaka 
mpp_stopwatch_elapsed_time(MppStopwatch stopwatch)547*437bfbebSnyanmisaka rk_s64 mpp_stopwatch_elapsed_time(MppStopwatch stopwatch)
548*437bfbebSnyanmisaka {
549*437bfbebSnyanmisaka     MppStopwatchImpl *impl = (MppStopwatchImpl *)stopwatch;
550*437bfbebSnyanmisaka 
551*437bfbebSnyanmisaka     if (check_is_mpp_stopwatch(impl)) {
552*437bfbebSnyanmisaka         mpp_err_f("invalid stopwatch %p\n", impl);
553*437bfbebSnyanmisaka         return 0;
554*437bfbebSnyanmisaka     }
555*437bfbebSnyanmisaka 
556*437bfbebSnyanmisaka     if (impl->filled_count < 2)
557*437bfbebSnyanmisaka         return 0;
558*437bfbebSnyanmisaka 
559*437bfbebSnyanmisaka     rk_s64 base_time = impl->nodes[0].time;
560*437bfbebSnyanmisaka     rk_s64 curr_time = impl->nodes[impl->filled_count - 1].time;
561*437bfbebSnyanmisaka     rk_s64 elapsed_time = curr_time - base_time;
562*437bfbebSnyanmisaka     return elapsed_time;
563*437bfbebSnyanmisaka }
564