FFmpeg
arm.c
Go to the documentation of this file.
1 /*
2  * Copyright © 2025, Niklas Haas
3  * Copyright © 2018, VideoLAN and dav1d authors
4  * Copyright © 2018, Two Orioles, LLC
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice, this
11  * list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright notice,
14  * this list of conditions and the following disclaimer in the documentation
15  * and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
21  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "checkasm_config.h"
30 
31 #include "internal.h"
32 
33 #if ARCH_AARCH64 && (!defined(_MSC_VER) || defined(__clang__))
34 
35 static inline uint64_t checkasm_cntvct(void)
36 {
37  uint64_t tick_counter;
38  /* A different timer register, that usually (always?) is readable.
39  * On older ARM architectures, this would have a system specified
40  * frequency (1-50 MHz), while on newer ARM architectures, it has a
41  * fixed frequency of 1 GHz, making it quite usable. */
42  __asm__ __volatile__("isb\nmrs %0, cntvct_el0" : "=r"(tick_counter)::"memory");
43  return tick_counter;
44 }
45 
46 static inline uint64_t checkasm_cntfrq(void)
47 {
48  uint64_t frequency;
49  __asm__ __volatile__("mrs %0, cntfrq_el0" : "=r"(frequency));
50  return frequency;
51 }
52 
53 static uint64_t perf_start(void)
54 {
55  return checkasm_cntvct();
56 }
57 
58 static uint64_t perf_stop(uint64_t t)
59 {
60  return checkasm_cntvct() - t;
61 }
62 
64 {
65  /* Try using the alternative timing register. */
68  checkasm_cntvct();
69  uint64_t frequency = checkasm_cntfrq();
71 
72  /* If the timer has a frequency less than 100 MHz, let's not
73  * use it and stick to the default gettime() fallback. */
74  if (frequency < 100000000)
75  return 1;
76 
77  perf->start = perf_start;
78  perf->stop = perf_stop;
79  perf->name = "aarch64 (cntvct)";
80  if (frequency == 1000000000) /* 1 GHz */
81  perf->unit = "nsec";
82  else
83  perf->unit = "tick";
84 
85  return checkasm_perf_validate_start(perf);
86  }
87  return 1;
88 }
89 #elif ARCH_ARM && !defined(_MSC_VER) && defined(__ARM_ARCH) && __ARM_ARCH <= 6 \
90  && (!defined(__thumb__) || defined(__thumb2__))
91 
92 static inline uint64_t checkasm_ccnt(void)
93 {
94  uint32_t cycle_counter;
95  /* Flush Prefetch Buffer */
96  __asm__ __volatile__("mcr p15, 0, %0, c7, c5, 4" ::"r"(0) : "memory");
97  /* ARM1176 specific, possibly available on other ARM11 such as ARM1136
98  * as well. */
99  __asm__ __volatile__("mrc p15, 0, %0, c15, c12, 1" : "=r"(cycle_counter)::"memory");
100  return cycle_counter;
101 }
102 
103 static inline void checkasm_ccnt_start(void)
104 {
105  __asm__ __volatile__("mcr p15, 0, %0, c15, c12, 0" ::"r"(1));
106 }
107 
108 static uint64_t perf_start(void)
109 {
110  return checkasm_ccnt();
111 }
112 
113 static uint64_t perf_stop(uint64_t t)
114 {
115  return checkasm_ccnt() - t;
116 }
117 
119 {
120  /* Try using the ARMv6 cycle counter register. */
123  checkasm_ccnt();
125 
126  /* Try starting the timer, if possible */
129  checkasm_ccnt_start();
131 
132  /* If starting the timer seems to work, run that on all cores. */
133  checkasm_run_on_all_cores(checkasm_ccnt_start);
134  }
135 
136  perf->start = perf_start;
137  perf->stop = perf_stop;
138  perf->name = "armv6 (ccnt)";
139  perf->unit = "cycle";
140 
141  return checkasm_perf_validate_start(perf);
142  }
143 
144  fprintf(stderr, "checkasm: unable to access ARM11 cycle counter\n");
145  return 1;
146 }
147 #else
149 {
150  /* Nothing to try; no timer chosen. */
151  return 1;
152 }
153 #endif
COLD
#define COLD
Definition: internal.h:45
checkasm_config.h
checkasm_perf_validate_start
int checkasm_perf_validate_start(const CheckasmPerf *perf)
Definition: perf.c:128
checkasm_context
checkasm_jmp_buf checkasm_context
Definition: signal.c:46
CheckasmPerf::start
uint64_t(* start)(void)
Start timing measurement.
Definition: test.h:533
checkasm_save_context
#define checkasm_save_context(ctx)
Definition: longjmp.h:67
checkasm_perf_init_arm
COLD int checkasm_perf_init_arm(CheckasmPerf *perf)
Definition: arm.c:148
CheckasmPerf
Definition: test.h:527
checkasm_run_on_all_cores
int checkasm_run_on_all_cores(void(*func)(void))
Definition: checkasm.c:601
CheckasmPerf::stop
uint64_t(* stop)(uint64_t start_time)
Stop timing measurement.
Definition: test.h:540
CheckasmPerf::name
const char * name
Name of the timing mechanism (e.g., "clock_gettime")
Definition: test.h:543
checkasm_set_signal_handler_state
CHECKASM_API void checkasm_set_signal_handler_state(int enabled)
Enable or disable signal handling.
Definition: signal.c:52
CheckasmPerf::unit
const char * unit
Unit of measurement (e.g., "ns", "cycles")
Definition: test.h:546
__asm__
__asm__(".macro parse_r var r\n\t" "\\var = -1\n\t" _IFC_REG(0) _IFC_REG(1) _IFC_REG(2) _IFC_REG(3) _IFC_REG(4) _IFC_REG(5) _IFC_REG(6) _IFC_REG(7) _IFC_REG(8) _IFC_REG(9) _IFC_REG(10) _IFC_REG(11) _IFC_REG(12) _IFC_REG(13) _IFC_REG(14) _IFC_REG(15) _IFC_REG(16) _IFC_REG(17) _IFC_REG(18) _IFC_REG(19) _IFC_REG(20) _IFC_REG(21) _IFC_REG(22) _IFC_REG(23) _IFC_REG(24) _IFC_REG(25) _IFC_REG(26) _IFC_REG(27) _IFC_REG(28) _IFC_REG(29) _IFC_REG(30) _IFC_REG(31) ".iflt \\var\n\t" ".error \"Unable to parse register name \\r\"\n\t" ".endif\n\t" ".endm")