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