FFmpeg
Loading...
Searching...
No Matches
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
47static int (*kpc_get_thread_counters)(int, unsigned int, void *);
48static int kperf_init;
49
50static 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
59static uint64_t perf_start(void)
60{
61 return kperf_cycles();
62}
63
64static 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;
125done:
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 */
#define CONFIG_COUNT
Definition macos_kperf.c:71
#define CPMU_CORE_CYCLE
Definition macos_kperf.c:54
static void kperf_init(void)
Definition macos_kperf.c:74
#define CFGWORD_EL0A64EN_MASK
Definition macos_kperf.c:48
#define KPC_MASK
Definition macos_kperf.c:72
uint64_t(* start)(void)
Start timing measurement.
Definition test.h:534
const char * unit
Unit of measurement (e.g., "ns", "cycles")
Definition test.h:547
const char * name
Name of the timing mechanism (e.g., "clock_gettime")
Definition test.h:544
uint64_t(* stop)(uint64_t start_time)
Stop timing measurement.
Definition test.h:541
int checkasm_perf_init_macos(CheckasmPerf *perf)
#define COLD
Definition internal.h:45
int checkasm_perf_validate_start(const CheckasmPerf *perf)
Definition perf.c:128