xref: /third_party/ffmpeg/libavutil/timer.h (revision cabdff1a)
1/*
2 * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg 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 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21/**
22 * @file
23 * high precision timer, useful to profile code
24 */
25
26#ifndef AVUTIL_TIMER_H
27#define AVUTIL_TIMER_H
28
29#include "config.h"
30
31#if CONFIG_LINUX_PERF
32# ifndef _GNU_SOURCE
33#  define _GNU_SOURCE
34# endif
35# include <unistd.h> // read(3)
36# include <sys/ioctl.h>
37# include <asm/unistd.h>
38# include <linux/perf_event.h>
39#endif
40
41#include <stdlib.h>
42#include <stdint.h>
43#include <inttypes.h>
44
45#if CONFIG_MACOS_KPERF
46#include "macos_kperf.h"
47#elif HAVE_MACH_ABSOLUTE_TIME
48#include <mach/mach_time.h>
49#endif
50
51#include "common.h"
52#include "log.h"
53
54#if   ARCH_AARCH64
55#   include "aarch64/timer.h"
56#elif ARCH_ARM
57#   include "arm/timer.h"
58#elif ARCH_PPC
59#   include "ppc/timer.h"
60#elif ARCH_X86
61#   include "x86/timer.h"
62#endif
63
64#if !defined(AV_READ_TIME)
65#   if HAVE_GETHRTIME
66#       define AV_READ_TIME gethrtime
67#   elif HAVE_MACH_ABSOLUTE_TIME
68#       define AV_READ_TIME mach_absolute_time
69#   endif
70#endif
71
72#ifndef FF_TIMER_UNITS
73#   define FF_TIMER_UNITS "UNITS"
74#endif
75
76#define TIMER_REPORT(id, tdiff)                                           \
77    {                                                                     \
78        static uint64_t tsum   = 0;                                       \
79        static int tcount      = 0;                                       \
80        static int tskip_count = 0;                                       \
81        static int thistogram[32] = {0};                                  \
82        thistogram[av_log2(tdiff)]++;                                     \
83        if (tcount < 2                ||                                  \
84            (tdiff) < 8 * tsum / tcount ||                                \
85            (tdiff) < 2000) {                                             \
86            tsum += (tdiff);                                              \
87            tcount++;                                                     \
88        } else                                                            \
89            tskip_count++;                                                \
90        if (((tcount + tskip_count) & (tcount + tskip_count - 1)) == 0) { \
91            int i;                                                        \
92            av_log(NULL, AV_LOG_ERROR,                                    \
93                   "%7" PRIu64 " " FF_TIMER_UNITS " in %s,%8d runs,%7d skips",\
94                   tsum * 10 / tcount, id, tcount, tskip_count);          \
95            for (i = 0; i < 32; i++)                                      \
96                av_log(NULL, AV_LOG_VERBOSE, " %2d", av_log2(2*thistogram[i]));\
97            av_log(NULL, AV_LOG_ERROR, "\n");                             \
98        }                                                                 \
99    }
100
101#if CONFIG_LINUX_PERF
102
103#define START_TIMER                                                         \
104    static int linux_perf_fd;                                               \
105    uint64_t tperf;                                                         \
106    if (!linux_perf_fd) {                                                   \
107        struct perf_event_attr attr = {                                     \
108            .type           = PERF_TYPE_HARDWARE,                           \
109            .size           = sizeof(struct perf_event_attr),               \
110            .config         = PERF_COUNT_HW_CPU_CYCLES,                     \
111            .disabled       = 1,                                            \
112            .exclude_kernel = 1,                                            \
113            .exclude_hv     = 1,                                            \
114        };                                                                  \
115        linux_perf_fd = syscall(__NR_perf_event_open, &attr,                \
116                                0, -1, -1, 0);                              \
117    }                                                                       \
118    if (linux_perf_fd == -1) {                                              \
119        av_log(NULL, AV_LOG_ERROR, "perf_event_open failed: %s\n",          \
120               av_err2str(AVERROR(errno)));                                 \
121    } else {                                                                \
122        ioctl(linux_perf_fd, PERF_EVENT_IOC_RESET, 0);                      \
123        ioctl(linux_perf_fd, PERF_EVENT_IOC_ENABLE, 0);                     \
124    }
125
126#define STOP_TIMER(id)                                                      \
127    ioctl(linux_perf_fd, PERF_EVENT_IOC_DISABLE, 0);                        \
128    read(linux_perf_fd, &tperf, sizeof(tperf));                             \
129    TIMER_REPORT(id, tperf)
130
131#elif CONFIG_MACOS_KPERF
132
133#define START_TIMER                                                         \
134    uint64_t tperf;                                                         \
135    ff_kperf_init();                                                        \
136    tperf = ff_kperf_cycles();
137
138#define STOP_TIMER(id)                                                      \
139    TIMER_REPORT(id, ff_kperf_cycles() - tperf);
140
141#elif defined(AV_READ_TIME)
142#define START_TIMER                             \
143    uint64_t tend;                              \
144    uint64_t tstart = AV_READ_TIME();           \
145
146#define STOP_TIMER(id)                                                    \
147    tend = AV_READ_TIME();                                                \
148    TIMER_REPORT(id, tend - tstart)
149#else
150#define START_TIMER
151#define STOP_TIMER(id) { }
152#endif
153
154#endif /* AVUTIL_TIMER_H */
155