2 * This file is part of FFmpeg.
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #if HAVE_SCHED_GETAFFINITY
30 #include <stdatomic.h>
32 #include "attributes.h"
34 #include "cpu_internal.h"
38 #if HAVE_GETPROCESSAFFINITYMASK || HAVE_WINRT
43 #include <sys/param.h>
45 #include <sys/types.h>
46 #include <sys/sysctl.h>
52 #if HAVE_GETAUXVAL || HAVE_ELF_AUX_INFO
56 static atomic_int cpu_flags
= -1;
57 static atomic_int cpu_count
= -1;
59 static int get_cpu_flags(void)
62 return ff_get_cpu_flags_mips();
64 return ff_get_cpu_flags_aarch64();
66 return ff_get_cpu_flags_arm();
68 return ff_get_cpu_flags_ppc();
70 return ff_get_cpu_flags_riscv();
72 return ff_get_cpu_flags_wasm();
74 return ff_get_cpu_flags_x86();
76 return ff_get_cpu_flags_loongarch();
81 void av_force_cpu_flags(int arg
){
83 (arg
& ( AV_CPU_FLAG_3DNOW
|
84 AV_CPU_FLAG_3DNOWEXT
|
88 AV_CPU_FLAG_SSE2SLOW
|
90 AV_CPU_FLAG_SSE3SLOW
|
100 AV_CPU_FLAG_AVX512
))
101 && !(arg
& AV_CPU_FLAG_MMX
)) {
102 av_log(NULL
, AV_LOG_WARNING
, "MMX implied by specified flags\n");
103 arg
|= AV_CPU_FLAG_MMX
;
106 atomic_store_explicit(&cpu_flags
, arg
, memory_order_relaxed
);
109 int av_get_cpu_flags(void)
111 int flags
= atomic_load_explicit(&cpu_flags
, memory_order_relaxed
);
113 flags
= get_cpu_flags();
114 atomic_store_explicit(&cpu_flags
, flags
, memory_order_relaxed
);
119 int av_parse_cpu_caps(unsigned *flags
, const char *s
)
121 static const AVOption cpuflags_opts
[] = {
122 { "flags" , NULL
, 0, AV_OPT_TYPE_FLAGS
, { .i64
= 0 }, INT64_MIN
, INT64_MAX
, .unit
= "flags" },
124 { "altivec" , NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_ALTIVEC
}, .unit
= "flags" },
125 { "vsx" , NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_VSX
}, .unit
= "flags" },
126 { "power8" , NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_POWER8
}, .unit
= "flags" },
128 { "mmx" , NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_MMX
}, .unit
= "flags" },
129 { "mmx2" , NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_MMX2
}, .unit
= "flags" },
130 { "mmxext" , NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_MMX2
}, .unit
= "flags" },
131 { "sse" , NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_SSE
}, .unit
= "flags" },
132 { "sse2" , NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_SSE2
}, .unit
= "flags" },
133 { "sse2slow", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_SSE2SLOW
}, .unit
= "flags" },
134 { "sse3" , NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_SSE3
}, .unit
= "flags" },
135 { "sse3slow", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_SSE3SLOW
}, .unit
= "flags" },
136 { "ssse3" , NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_SSSE3
}, .unit
= "flags" },
137 { "atom" , NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_ATOM
}, .unit
= "flags" },
138 { "sse4.1" , NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_SSE4
}, .unit
= "flags" },
139 { "sse4.2" , NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_SSE42
}, .unit
= "flags" },
140 { "avx" , NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_AVX
}, .unit
= "flags" },
141 { "avxslow" , NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_AVXSLOW
}, .unit
= "flags" },
142 { "xop" , NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_XOP
}, .unit
= "flags" },
143 { "fma3" , NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_FMA3
}, .unit
= "flags" },
144 { "fma4" , NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_FMA4
}, .unit
= "flags" },
145 { "avx2" , NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_AVX2
}, .unit
= "flags" },
146 { "bmi1" , NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_BMI1
}, .unit
= "flags" },
147 { "bmi2" , NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_BMI2
}, .unit
= "flags" },
148 { "3dnow" , NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_3DNOW
}, .unit
= "flags" },
149 { "3dnowext", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_3DNOWEXT
}, .unit
= "flags" },
150 { "cmov", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_CMOV
}, .unit
= "flags" },
151 { "aesni", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_AESNI
}, .unit
= "flags" },
152 { "avx512" , NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_AVX512
}, .unit
= "flags" },
153 { "avx512icl", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_AVX512ICL
}, .unit
= "flags" },
154 { "slowgather", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_SLOW_GATHER
}, .unit
= "flags" },
156 #define CPU_FLAG_P2 AV_CPU_FLAG_CMOV | AV_CPU_FLAG_MMX
157 #define CPU_FLAG_P3 CPU_FLAG_P2 | AV_CPU_FLAG_MMX2 | AV_CPU_FLAG_SSE
158 #define CPU_FLAG_P4 CPU_FLAG_P3| AV_CPU_FLAG_SSE2
159 { "pentium2", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= CPU_FLAG_P2
}, .unit
= "flags" },
160 { "pentium3", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= CPU_FLAG_P3
}, .unit
= "flags" },
161 { "pentium4", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= CPU_FLAG_P4
}, .unit
= "flags" },
163 #define CPU_FLAG_K62 AV_CPU_FLAG_MMX | AV_CPU_FLAG_3DNOW
164 #define CPU_FLAG_ATHLON CPU_FLAG_K62 | AV_CPU_FLAG_CMOV | AV_CPU_FLAG_3DNOWEXT | AV_CPU_FLAG_MMX2
165 #define CPU_FLAG_ATHLONXP CPU_FLAG_ATHLON | AV_CPU_FLAG_SSE
166 #define CPU_FLAG_K8 CPU_FLAG_ATHLONXP | AV_CPU_FLAG_SSE2
167 { "k6", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_MMX
}, .unit
= "flags" },
168 { "k62", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= CPU_FLAG_K62
}, .unit
= "flags" },
169 { "athlon", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= CPU_FLAG_ATHLON
}, .unit
= "flags" },
170 { "athlonxp", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= CPU_FLAG_ATHLONXP
}, .unit
= "flags" },
171 { "k8", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= CPU_FLAG_K8
}, .unit
= "flags" },
173 { "armv5te", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_ARMV5TE
}, .unit
= "flags" },
174 { "armv6", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_ARMV6
}, .unit
= "flags" },
175 { "armv6t2", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_ARMV6T2
}, .unit
= "flags" },
176 { "vfp", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_VFP
}, .unit
= "flags" },
177 { "vfp_vm", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_VFP_VM
}, .unit
= "flags" },
178 { "vfpv3", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_VFPV3
}, .unit
= "flags" },
179 { "neon", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_NEON
}, .unit
= "flags" },
180 { "setend", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_SETEND
}, .unit
= "flags" },
182 { "armv8", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_ARMV8
}, .unit
= "flags" },
183 { "neon", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_NEON
}, .unit
= "flags" },
184 { "vfp", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_VFP
}, .unit
= "flags" },
185 { "dotprod", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_DOTPROD
}, .unit
= "flags" },
186 { "i8mm", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_I8MM
}, .unit
= "flags" },
187 { "sve", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_SVE
}, .unit
= "flags" },
188 { "sve2", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_SVE2
}, .unit
= "flags" },
190 { "mmi", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_MMI
}, .unit
= "flags" },
191 { "msa", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_MSA
}, .unit
= "flags" },
193 { "lsx", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_LSX
}, .unit
= "flags" },
194 { "lasx", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_LASX
}, .unit
= "flags" },
196 { "rvi", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_RVI
}, .unit
= "flags" },
197 { "rvb", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_RVB
}, .unit
= "flags" },
198 { "zve32x", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_RVV_I32
}, .unit
= "flags" },
199 { "zve32f", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_RVV_F32
}, .unit
= "flags" },
200 { "zve64x", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_RVV_I64
}, .unit
= "flags" },
201 { "zve64d", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_RVV_F64
}, .unit
= "flags" },
202 { "zbb", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_RVB_BASIC
}, .unit
= "flags" },
203 { "zvbb", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_RV_ZVBB
}, .unit
= "flags" },
204 { "misaligned", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_RV_MISALIGNED
}, .unit
= "flags" },
206 { "simd128", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= AV_CPU_FLAG_SIMD128
}, .unit
= "flags" },
210 static const AVClass
class = {
211 .class_name
= "cpuflags",
212 .item_name
= av_default_item_name
,
213 .option
= cpuflags_opts
,
214 .version
= LIBAVUTIL_VERSION_INT
,
216 const AVClass
*pclass
= &class;
218 return av_opt_eval_flags(&pclass
, &cpuflags_opts
[0], s
, flags
);
221 int av_cpu_count(void)
223 static atomic_int printed
= 0;
230 #if HAVE_SCHED_GETAFFINITY && defined(CPU_COUNT)
235 if (!sched_getaffinity(0, sizeof(cpuset
), &cpuset
))
236 nb_cpus
= CPU_COUNT(&cpuset
);
237 #elif HAVE_GETPROCESSAFFINITYMASK
238 DWORD_PTR proc_aff
, sys_aff
;
239 if (GetProcessAffinityMask(GetCurrentProcess(), &proc_aff
, &sys_aff
))
240 nb_cpus
= av_popcount64(proc_aff
);
241 #elif HAVE_SYSCTL && defined(HW_NCPUONLINE)
242 int mib
[2] = { CTL_HW
, HW_NCPUONLINE
};
243 size_t len
= sizeof(nb_cpus
);
245 if (sysctl(mib
, 2, &nb_cpus
, &len
, NULL
, 0) == -1)
247 #elif HAVE_SYSCTL && defined(HW_NCPU)
248 int mib
[2] = { CTL_HW
, HW_NCPU
};
249 size_t len
= sizeof(nb_cpus
);
251 if (sysctl(mib
, 2, &nb_cpus
, &len
, NULL
, 0) == -1)
253 #elif HAVE_SYSCONF && defined(_SC_NPROC_ONLN)
254 nb_cpus
= sysconf(_SC_NPROC_ONLN
);
255 #elif HAVE_SYSCONF && defined(_SC_NPROCESSORS_ONLN)
256 nb_cpus
= sysconf(_SC_NPROCESSORS_ONLN
);
258 GetNativeSystemInfo(&sysinfo
);
259 nb_cpus
= sysinfo
.dwNumberOfProcessors
;
262 if (!atomic_exchange_explicit(&printed
, 1, memory_order_relaxed
))
263 av_log(NULL
, AV_LOG_DEBUG
, "detected %d logical cores\n", nb_cpus
);
265 count
= atomic_load_explicit(&cpu_count
, memory_order_relaxed
);
269 av_log(NULL
, AV_LOG_DEBUG
, "overriding to %d logical cores\n", nb_cpus
);
275 void av_cpu_force_count(int count
)
277 atomic_store_explicit(&cpu_count
, count
, memory_order_relaxed
);
280 size_t av_cpu_max_align(void)
283 return ff_get_cpu_max_align_mips();
285 return ff_get_cpu_max_align_aarch64();
287 return ff_get_cpu_max_align_arm();
289 return ff_get_cpu_max_align_ppc();
291 return ff_get_cpu_max_align_wasm();
293 return ff_get_cpu_max_align_x86();
295 return ff_get_cpu_max_align_loongarch();
302 unsigned long ff_getauxval(unsigned long type
)
305 return getauxval(type
);
306 #elif HAVE_ELF_AUX_INFO
307 unsigned long aux
= 0;
308 int ret
= elf_aux_info(type
, &aux
, sizeof(aux
));