FFmpeg
macos_kperf.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 "perf_internal.h"
32 
33 #if HAVE_MACOS_KPERF
34 
35  #include <dlfcn.h>
36 
37  #include "internal.h"
38 
39  #define CFGWORD_EL0A64EN_MASK (0x20000)
40  #define CPMU_CORE_CYCLE 0x02
41  #define KPC_CLASS_FIXED_MASK (1 << 0)
42  #define KPC_CLASS_CONFIGURABLE_MASK (1 << 1)
43  #define COUNTERS_COUNT 10
44  #define CONFIG_COUNT 8
45  #define KPC_MASK (KPC_CLASS_CONFIGURABLE_MASK | KPC_CLASS_FIXED_MASK)
46 
47 static int (*kpc_get_thread_counters)(int, unsigned int, void *);
48 static int kperf_init;
49 
50 static inline uint64_t kperf_cycles(void)
51 {
52  uint64_t counters[COUNTERS_COUNT];
53  if (kpc_get_thread_counters(0, COUNTERS_COUNT, counters))
54  return -1;
55 
56  return counters[0];
57 }
58 
59 static uint64_t perf_start(void)
60 {
61  return kperf_cycles();
62 }
63 
64 static uint64_t perf_stop(uint64_t t)
65 {
66  return kperf_cycles() - t;
67 }
68 
70 {
71  uint64_t config[COUNTERS_COUNT] = { 0 };
72 
73  if (kperf_init)
74  goto done;
75 
76  void *kperf
77  = dlopen("/System/Library/PrivateFrameworks/kperf.framework/kperf", RTLD_LAZY);
78  if (!kperf) {
79  fprintf(stderr, "checkasm: Unable to load kperf: %s\n", dlerror());
80  return 1;
81  }
82 
83  int (*kpc_force_all_ctrs_set)(int) = dlsym(kperf, "kpc_force_all_ctrs_set");
84  int (*kpc_set_counting)(uint32_t) = dlsym(kperf, "kpc_set_counting");
85  int (*kpc_set_thread_counting)(uint32_t) = dlsym(kperf, "kpc_set_thread_counting");
86  int (*kpc_set_config)(uint32_t, void *) = dlsym(kperf, "kpc_set_config");
87  uint32_t (*kpc_get_counter_count)(uint32_t) = dlsym(kperf, "kpc_get_counter_count");
88  uint32_t (*kpc_get_config_count)(uint32_t) = dlsym(kperf, "kpc_get_config_count");
89  kpc_get_thread_counters = dlsym(kperf, "kpc_get_thread_counters");
90 
91  if (!kpc_get_thread_counters) {
92  fprintf(stderr, "checkasm: Unable to load kpc_get_thread_counters\n");
93  return 1;
94  }
95 
96  if (!kpc_get_counter_count || kpc_get_counter_count(KPC_MASK) != COUNTERS_COUNT) {
97  fprintf(stderr, "checkasm: Unexpected kpc_get_counter_count\n");
98  return 1;
99  }
100  if (!kpc_get_config_count || kpc_get_config_count(KPC_MASK) != CONFIG_COUNT) {
101  fprintf(stderr, "checkasm: Unexpected kpc_get_config_count\n");
102  return 1;
103  }
104 
106 
107  if (!kpc_set_config || kpc_set_config(KPC_MASK, config)) {
108  fprintf(stderr, "checkasm: The kperf API needs to be run as root\n");
109  return 1;
110  }
111  if (!kpc_force_all_ctrs_set || kpc_force_all_ctrs_set(1)) {
112  fprintf(stderr, "checkasm: kpc_force_all_ctrs_set failed\n");
113  return 1;
114  }
115  if (!kpc_set_counting || kpc_set_counting(KPC_MASK)) {
116  fprintf(stderr, "checkasm: kpc_set_counting failed\n");
117  return 1;
118  }
119  if (!kpc_set_counting || kpc_set_thread_counting(KPC_MASK)) {
120  fprintf(stderr, "checkasm: kpc_set_thread_counting failed\n");
121  return 1;
122  }
123 
124  kperf_init = 1;
125 done:
126  perf->start = perf_start;
127  perf->stop = perf_stop;
128  perf->name = "macOS (kperf)";
129  perf->unit = "cycle";
130  return checkasm_perf_validate_start(perf);
131 }
132 
133 #endif /* HAVE_MACOS_KPERF */
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
CheckasmPerf::start
uint64_t(* start)(void)
Start timing measurement.
Definition: test.h:533
tf_sess_config.config
config
Definition: tf_sess_config.py:33
CFGWORD_EL0A64EN_MASK
#define CFGWORD_EL0A64EN_MASK
Definition: macos_kperf.c:48
CheckasmPerf
Definition: test.h:527
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
kperf_init
static void kperf_init(void)
Definition: macos_kperf.c:74
perf_internal.h
KPC_MASK
#define KPC_MASK
Definition: macos_kperf.c:72
CONFIG_COUNT
#define CONFIG_COUNT
Definition: macos_kperf.c:71
CPMU_CORE_CYCLE
#define CPMU_CORE_CYCLE
Definition: macos_kperf.c:54
CheckasmPerf::unit
const char * unit
Unit of measurement (e.g., "ns", "cycles")
Definition: test.h:546
checkasm_perf_init_macos
int checkasm_perf_init_macos(CheckasmPerf *perf)