1# SPDX-FileCopyrightText: 2018 Helder Eijs <helderijs@gmail.com>
2# SPDX-License-Identifier: BSD-2-Clause
3
4from __future__ import annotations
5
6import os
7
8from Crypto.Util._raw_api import load_pycryptodome_raw_lib
9
10_raw_cpuid_lib = load_pycryptodome_raw_lib(
11 "Crypto.Util._cpuid_c",
12 """
13 int have_aes_ni(void);
14 int have_clmul(void);
15 int have_avx2(void);
16 int have_bmi1(void);
17 int have_bmi2(void);
18 int have_sha_ni(void);
19 int have_adx(void);
20 """,
21)
22
23
24def have_aes_ni() -> int:
25 return _raw_cpuid_lib.have_aes_ni()
26
27
28def have_clmul() -> int:
29 return _raw_cpuid_lib.have_clmul()
30
31
32def have_avx2() -> int:
33 return _raw_cpuid_lib.have_avx2()
34
35
36def have_bmi1() -> int:
37 return _raw_cpuid_lib.have_bmi1()
38
39
40def have_bmi2() -> int:
41 return _raw_cpuid_lib.have_bmi2()
42
43
44def have_sha_ni() -> int:
45 return _raw_cpuid_lib.have_sha_ni()
46
47
48def have_adx() -> int:
49 return _raw_cpuid_lib.have_adx()
50
51
52def load_avx2_bmi2_lib(name: str, cdecl: str):
53 """Load the functions in ``cdecl`` from the module ``name``,
54 compiled for AVX2, BMI1 and BMI2.
55
56 Return None if the CPU does not support all three instruction sets,
57 or if the module was not compiled in.
58 """
59
60 if not (have_avx2() and have_bmi1() and have_bmi2()):
61 return None
62 try:
63 return load_pycryptodome_raw_lib(name, cdecl)
64 except OSError:
65 return None
66
67
68def available_cores() -> int:
69 """Return the number of CPU cores this process can run on."""
70
71 count: int | None
72 # Python 3.13+: it takes into account CPU affinity and -X cpu_count
73 if hasattr(os, "process_cpu_count"):
74 count = os.process_cpu_count()
75 elif hasattr(os, "sched_getaffinity"):
76 count = len(os.sched_getaffinity(0))
77 elif hasattr(os, "cpu_count"):
78 count = os.cpu_count()
79 else:
80 import multiprocessing
81
82 try:
83 count = multiprocessing.cpu_count()
84 except NotImplementedError:
85 count = None
86 return count or 1