1/* 2 * This file is part of FFmpeg. 3 * 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. 8 * 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. 13 * 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 17 */ 18 19#include <stdint.h> 20 21#include "cpu.h" 22#include "cpu_internal.h" 23#include "config.h" 24#include "opt.h" 25#include "common.h" 26 27#if HAVE_SCHED_GETAFFINITY 28#ifndef _GNU_SOURCE 29# define _GNU_SOURCE 30#endif 31#include <sched.h> 32#endif 33#if HAVE_GETPROCESSAFFINITYMASK 34#include <windows.h> 35#endif 36#if HAVE_SYSCTL 37#if HAVE_SYS_PARAM_H 38#include <sys/param.h> 39#endif 40#include <sys/types.h> 41#include <sys/sysctl.h> 42#endif 43#if HAVE_UNISTD_H 44#include <unistd.h> 45#endif 46 47static int flags, checked; 48 49void av_force_cpu_flags(int arg){ 50 if ( (arg & ( AV_CPU_FLAG_3DNOW | 51 AV_CPU_FLAG_3DNOWEXT | 52 AV_CPU_FLAG_SSE | 53 AV_CPU_FLAG_SSE2 | 54 AV_CPU_FLAG_SSE2SLOW | 55 AV_CPU_FLAG_SSE3 | 56 AV_CPU_FLAG_SSE3SLOW | 57 AV_CPU_FLAG_SSSE3 | 58 AV_CPU_FLAG_SSE4 | 59 AV_CPU_FLAG_SSE42 | 60 AV_CPU_FLAG_AVX | 61 AV_CPU_FLAG_XOP | 62 AV_CPU_FLAG_FMA3 | 63 AV_CPU_FLAG_FMA4 | 64 AV_CPU_FLAG_AVX2 )) 65 && !(arg & AV_CPU_FLAG_MMX)) { 66 av_log(NULL, AV_LOG_WARNING, "MMX implied by specified flags\n"); 67 arg |= AV_CPU_FLAG_MMX; 68 } 69 70 flags = arg; 71 checked = arg != -1; 72} 73 74int av_get_cpu_flags(void) 75{ 76 if (checked) 77 return flags; 78 79 if (ARCH_AARCH64) 80 flags = ff_get_cpu_flags_aarch64(); 81 if (ARCH_ARM) 82 flags = ff_get_cpu_flags_arm(); 83 if (ARCH_PPC) 84 flags = ff_get_cpu_flags_ppc(); 85 if (ARCH_X86) 86 flags = ff_get_cpu_flags_x86(); 87 88 checked = 1; 89 return flags; 90} 91 92void av_set_cpu_flags_mask(int mask) 93{ 94 checked = 0; 95 flags = av_get_cpu_flags() & mask; 96 checked = 1; 97} 98 99int av_parse_cpu_flags(const char *s) 100{ 101#define CPUFLAG_MMXEXT (AV_CPU_FLAG_MMX | AV_CPU_FLAG_MMXEXT | AV_CPU_FLAG_CMOV) 102#define CPUFLAG_3DNOW (AV_CPU_FLAG_3DNOW | AV_CPU_FLAG_MMX) 103#define CPUFLAG_3DNOWEXT (AV_CPU_FLAG_3DNOWEXT | CPUFLAG_3DNOW) 104#define CPUFLAG_SSE (AV_CPU_FLAG_SSE | CPUFLAG_MMXEXT) 105#define CPUFLAG_SSE2 (AV_CPU_FLAG_SSE2 | CPUFLAG_SSE) 106#define CPUFLAG_SSE2SLOW (AV_CPU_FLAG_SSE2SLOW | CPUFLAG_SSE2) 107#define CPUFLAG_SSE3 (AV_CPU_FLAG_SSE3 | CPUFLAG_SSE2) 108#define CPUFLAG_SSE3SLOW (AV_CPU_FLAG_SSE3SLOW | CPUFLAG_SSE3) 109#define CPUFLAG_SSSE3 (AV_CPU_FLAG_SSSE3 | CPUFLAG_SSE3) 110#define CPUFLAG_SSE4 (AV_CPU_FLAG_SSE4 | CPUFLAG_SSSE3) 111#define CPUFLAG_SSE42 (AV_CPU_FLAG_SSE42 | CPUFLAG_SSE4) 112#define CPUFLAG_AVX (AV_CPU_FLAG_AVX | CPUFLAG_SSE42) 113#define CPUFLAG_XOP (AV_CPU_FLAG_XOP | CPUFLAG_AVX) 114#define CPUFLAG_FMA3 (AV_CPU_FLAG_FMA3 | CPUFLAG_AVX) 115#define CPUFLAG_FMA4 (AV_CPU_FLAG_FMA4 | CPUFLAG_AVX) 116#define CPUFLAG_AVX2 (AV_CPU_FLAG_AVX2 | CPUFLAG_AVX) 117#define CPUFLAG_BMI1 (AV_CPU_FLAG_BMI1) 118#define CPUFLAG_BMI2 (AV_CPU_FLAG_BMI2 | CPUFLAG_BMI1) 119 static const AVOption cpuflags_opts[] = { 120 { "flags" , NULL, 0, AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT64_MIN, INT64_MAX, .unit = "flags" }, 121#if ARCH_PPC 122 { "altivec" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ALTIVEC }, .unit = "flags" }, 123#elif ARCH_X86 124 { "mmx" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MMX }, .unit = "flags" }, 125 { "mmxext" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_MMXEXT }, .unit = "flags" }, 126 { "sse" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_SSE }, .unit = "flags" }, 127 { "sse2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_SSE2 }, .unit = "flags" }, 128 { "sse2slow", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_SSE2SLOW }, .unit = "flags" }, 129 { "sse3" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_SSE3 }, .unit = "flags" }, 130 { "sse3slow", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_SSE3SLOW }, .unit = "flags" }, 131 { "ssse3" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_SSSE3 }, .unit = "flags" }, 132 { "atom" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ATOM }, .unit = "flags" }, 133 { "sse4.1" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_SSE4 }, .unit = "flags" }, 134 { "sse4.2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_SSE42 }, .unit = "flags" }, 135 { "avx" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_AVX }, .unit = "flags" }, 136 { "xop" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_XOP }, .unit = "flags" }, 137 { "fma3" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_FMA3 }, .unit = "flags" }, 138 { "fma4" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_FMA4 }, .unit = "flags" }, 139 { "avx2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_AVX2 }, .unit = "flags" }, 140 { "bmi1" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_BMI1 }, .unit = "flags" }, 141 { "bmi2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_BMI2 }, .unit = "flags" }, 142 { "3dnow" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_3DNOW }, .unit = "flags" }, 143 { "3dnowext", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_3DNOWEXT }, .unit = "flags" }, 144 { "cmov", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_CMOV }, .unit = "flags" }, 145#elif ARCH_ARM 146 { "armv5te", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV5TE }, .unit = "flags" }, 147 { "armv6", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV6 }, .unit = "flags" }, 148 { "armv6t2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV6T2 }, .unit = "flags" }, 149 { "vfp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_VFP }, .unit = "flags" }, 150 { "vfpv3", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_VFPV3 }, .unit = "flags" }, 151 { "neon", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_NEON }, .unit = "flags" }, 152#elif ARCH_AARCH64 153 { "armv8", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV8 }, .unit = "flags" }, 154 { "neon", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_NEON }, .unit = "flags" }, 155 { "vfp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_VFP }, .unit = "flags" }, 156#endif 157 { NULL }, 158 }; 159 static const AVClass class = { 160 .class_name = "cpuflags", 161 .item_name = av_default_item_name, 162 .option = cpuflags_opts, 163 .version = LIBAVUTIL_VERSION_INT, 164 }; 165 166 int flags = 0, ret; 167 const AVClass *pclass = &class; 168 169 if ((ret = av_opt_eval_flags(&pclass, &cpuflags_opts[0], s, &flags)) < 0) 170 return ret; 171 172 return flags & INT_MAX; 173} 174 175int av_parse_cpu_caps(unsigned *flags, const char *s) 176{ 177 static const AVOption cpuflags_opts[] = { 178 { "flags" , NULL, 0, AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT64_MIN, INT64_MAX, .unit = "flags" }, 179#if ARCH_PPC 180 { "altivec" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ALTIVEC }, .unit = "flags" }, 181#elif ARCH_X86 182 { "mmx" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MMX }, .unit = "flags" }, 183 { "mmx2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MMX2 }, .unit = "flags" }, 184 { "mmxext" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MMX2 }, .unit = "flags" }, 185 { "sse" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE }, .unit = "flags" }, 186 { "sse2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE2 }, .unit = "flags" }, 187 { "sse2slow", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE2SLOW }, .unit = "flags" }, 188 { "sse3" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE3 }, .unit = "flags" }, 189 { "sse3slow", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE3SLOW }, .unit = "flags" }, 190 { "ssse3" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSSE3 }, .unit = "flags" }, 191 { "atom" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ATOM }, .unit = "flags" }, 192 { "sse4.1" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE4 }, .unit = "flags" }, 193 { "sse4.2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE42 }, .unit = "flags" }, 194 { "avx" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_AVX }, .unit = "flags" }, 195 { "xop" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_XOP }, .unit = "flags" }, 196 { "fma3" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_FMA3 }, .unit = "flags" }, 197 { "fma4" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_FMA4 }, .unit = "flags" }, 198 { "avx2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_AVX2 }, .unit = "flags" }, 199 { "bmi1" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_BMI1 }, .unit = "flags" }, 200 { "bmi2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_BMI2 }, .unit = "flags" }, 201 { "3dnow" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_3DNOW }, .unit = "flags" }, 202 { "3dnowext", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_3DNOWEXT }, .unit = "flags" }, 203 { "cmov", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_CMOV }, .unit = "flags" }, 204 205#define CPU_FLAG_P2 AV_CPU_FLAG_CMOV | AV_CPU_FLAG_MMX 206#define CPU_FLAG_P3 CPU_FLAG_P2 | AV_CPU_FLAG_MMX2 | AV_CPU_FLAG_SSE 207#define CPU_FLAG_P4 CPU_FLAG_P3| AV_CPU_FLAG_SSE2 208 { "pentium2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_P2 }, .unit = "flags" }, 209 { "pentium3", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_P3 }, .unit = "flags" }, 210 { "pentium4", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_P4 }, .unit = "flags" }, 211 212#define CPU_FLAG_K62 AV_CPU_FLAG_MMX | AV_CPU_FLAG_3DNOW 213#define CPU_FLAG_ATHLON CPU_FLAG_K62 | AV_CPU_FLAG_CMOV | AV_CPU_FLAG_3DNOWEXT | AV_CPU_FLAG_MMX2 214#define CPU_FLAG_ATHLONXP CPU_FLAG_ATHLON | AV_CPU_FLAG_SSE 215#define CPU_FLAG_K8 CPU_FLAG_ATHLONXP | AV_CPU_FLAG_SSE2 216 { "k6", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MMX }, .unit = "flags" }, 217 { "k62", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_K62 }, .unit = "flags" }, 218 { "athlon", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_ATHLON }, .unit = "flags" }, 219 { "athlonxp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_ATHLONXP }, .unit = "flags" }, 220 { "k8", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_K8 }, .unit = "flags" }, 221#elif ARCH_ARM 222 { "armv5te", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV5TE }, .unit = "flags" }, 223 { "armv6", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV6 }, .unit = "flags" }, 224 { "armv6t2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV6T2 }, .unit = "flags" }, 225 { "vfp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_VFP }, .unit = "flags" }, 226 { "vfpv3", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_VFPV3 }, .unit = "flags" }, 227 { "neon", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_NEON }, .unit = "flags" }, 228#elif ARCH_AARCH64 229 { "armv8", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV8 }, .unit = "flags" }, 230 { "neon", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_NEON }, .unit = "flags" }, 231 { "vfp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_VFP }, .unit = "flags" }, 232#endif 233 { NULL }, 234 }; 235 static const AVClass class = { 236 .class_name = "cpuflags", 237 .item_name = av_default_item_name, 238 .option = cpuflags_opts, 239 .version = LIBAVUTIL_VERSION_INT, 240 }; 241 const AVClass *pclass = &class; 242 243 return av_opt_eval_flags(&pclass, &cpuflags_opts[0], s, flags); 244} 245 246int av_cpu_count(void) 247{ 248 static volatile int printed; 249 250 int nb_cpus = 1; 251#if HAVE_SCHED_GETAFFINITY && defined(CPU_COUNT) 252 cpu_set_t cpuset; 253 254 CPU_ZERO(&cpuset); 255 256 if (!sched_getaffinity(0, sizeof(cpuset), &cpuset)) 257 nb_cpus = CPU_COUNT(&cpuset); 258#elif HAVE_GETPROCESSAFFINITYMASK 259 DWORD_PTR proc_aff, sys_aff; 260 if (GetProcessAffinityMask(GetCurrentProcess(), &proc_aff, &sys_aff)) 261 nb_cpus = av_popcount64(proc_aff); 262#elif HAVE_SYSCTL && defined(HW_NCPU) 263 int mib[2] = { CTL_HW, HW_NCPU }; 264 size_t len = sizeof(nb_cpus); 265 266 if (sysctl(mib, 2, &nb_cpus, &len, NULL, 0) == -1) 267 nb_cpus = 0; 268#elif HAVE_SYSCONF && defined(_SC_NPROC_ONLN) 269 nb_cpus = sysconf(_SC_NPROC_ONLN); 270#elif HAVE_SYSCONF && defined(_SC_NPROCESSORS_ONLN) 271 nb_cpus = sysconf(_SC_NPROCESSORS_ONLN); 272#endif 273 274 if (!printed) { 275 av_log(NULL, AV_LOG_DEBUG, "detected %d logical cores\n", nb_cpus); 276 printed = 1; 277 } 278 279 return nb_cpus; 280} 281 282#ifdef TEST 283 284#include <stdio.h> 285 286static const struct { 287 int flag; 288 const char *name; 289} cpu_flag_tab[] = { 290#if ARCH_AARCH64 291 { AV_CPU_FLAG_ARMV8, "armv8" }, 292 { AV_CPU_FLAG_NEON, "neon" }, 293 { AV_CPU_FLAG_VFP, "vfp" }, 294#elif ARCH_ARM 295 { AV_CPU_FLAG_ARMV5TE, "armv5te" }, 296 { AV_CPU_FLAG_ARMV6, "armv6" }, 297 { AV_CPU_FLAG_ARMV6T2, "armv6t2" }, 298 { AV_CPU_FLAG_VFP, "vfp" }, 299 { AV_CPU_FLAG_VFPV3, "vfpv3" }, 300 { AV_CPU_FLAG_NEON, "neon" }, 301#elif ARCH_PPC 302 { AV_CPU_FLAG_ALTIVEC, "altivec" }, 303#elif ARCH_X86 304 { AV_CPU_FLAG_MMX, "mmx" }, 305 { AV_CPU_FLAG_MMXEXT, "mmxext" }, 306 { AV_CPU_FLAG_SSE, "sse" }, 307 { AV_CPU_FLAG_SSE2, "sse2" }, 308 { AV_CPU_FLAG_SSE2SLOW, "sse2(slow)" }, 309 { AV_CPU_FLAG_SSE3, "sse3" }, 310 { AV_CPU_FLAG_SSE3SLOW, "sse3(slow)" }, 311 { AV_CPU_FLAG_SSSE3, "ssse3" }, 312 { AV_CPU_FLAG_ATOM, "atom" }, 313 { AV_CPU_FLAG_SSE4, "sse4.1" }, 314 { AV_CPU_FLAG_SSE42, "sse4.2" }, 315 { AV_CPU_FLAG_AVX, "avx" }, 316 { AV_CPU_FLAG_XOP, "xop" }, 317 { AV_CPU_FLAG_FMA3, "fma3" }, 318 { AV_CPU_FLAG_FMA4, "fma4" }, 319 { AV_CPU_FLAG_3DNOW, "3dnow" }, 320 { AV_CPU_FLAG_3DNOWEXT, "3dnowext" }, 321 { AV_CPU_FLAG_CMOV, "cmov" }, 322 { AV_CPU_FLAG_AVX2, "avx2" }, 323 { AV_CPU_FLAG_BMI1, "bmi1" }, 324 { AV_CPU_FLAG_BMI2, "bmi2" }, 325#endif 326 { 0 } 327}; 328 329int main(void) 330{ 331 int cpu_flags = av_get_cpu_flags(); 332 int i; 333 334 printf("cpu_flags = 0x%08X\n", cpu_flags); 335 printf("cpu_flags ="); 336 for (i = 0; cpu_flag_tab[i].flag; i++) 337 if (cpu_flags & cpu_flag_tab[i].flag) 338 printf(" %s", cpu_flag_tab[i].name); 339 printf("\n"); 340 341 return 0; 342} 343 344#endif 345