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