joebruce1313's picture
Upload 38004 files
1f5470c verified
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
import platform
import subprocess
import logging
import os
def Version(v):
return [int(x) for x in v.split('.')]
def supported_instruction_sets():
"""
Returns the set of supported CPU features, see
https://github.com/numpy/numpy/blob/master/numpy/core/src/common/npy_cpu_features.h
for the list of features that this set may contain per architecture.
Example:
>>> supported_instruction_sets() # for x86
{"SSE2", "AVX2", "AVX512", ...}
>>> supported_instruction_sets() # for PPC
{"VSX", "VSX2", ...}
>>> supported_instruction_sets() # for ARM
{"NEON", "ASIMD", ...}
"""
# Old numpy.core._multiarray_umath.__cpu_features__ doesn't support Arm SVE,
# so let's read Features in numpy.distutils.cpuinfo and search 'sve' entry
def is_sve_supported():
if platform.machine() != "aarch64":
return False
# Currently SVE is only supported on Linux
if platform.system() != "Linux":
return False
# Numpy 2.0 supports SVE detection by __cpu_features__, so just skip
import numpy
if Version(numpy.__version__) >= Version("2.0"):
return False
# platform-dependent legacy fallback using numpy.distutils.cpuinfo
import numpy.distutils.cpuinfo
return "sve" in numpy.distutils.cpuinfo.cpu.info[0].get('Features', "").split()
import numpy
if Version(numpy.__version__) >= Version("1.19"):
# use private API as next-best thing until numpy/numpy#18058 is solved
from numpy.core._multiarray_umath import __cpu_features__
# __cpu_features__ is a dictionary with CPU features
# as keys, and True / False as values
supported = {k for k, v in __cpu_features__.items() if v}
if is_sve_supported():
supported.add("SVE")
for f in os.getenv("FAISS_DISABLE_CPU_FEATURES", "").split(", \t\n\r"):
supported.discard(f)
return supported
# platform-dependent legacy fallback before numpy 1.19, no windows
if platform.system() == "Darwin":
if subprocess.check_output(["/usr/sbin/sysctl", "hw.optional.avx2_0"])[-1] == '1':
return {"AVX2"}
elif platform.system() == "Linux":
import numpy.distutils.cpuinfo
result = set()
if "avx2" in numpy.distutils.cpuinfo.cpu.info[0].get('flags', ""):
result.add("AVX2")
if "avx512" in numpy.distutils.cpuinfo.cpu.info[0].get('flags', ""):
result.add("AVX512")
if "avx512_fp16" in numpy.distutils.cpuinfo.cpu.info[0].get('flags', ""):
# avx512_fp16 is supported starting SPR
result.add("AVX512_SPR")
if is_sve_supported():
result.add("SVE")
for f in os.getenv("FAISS_DISABLE_CPU_FEATURES", "").split(", \t\n\r"):
result.discard(f)
return result
return set()
logger = logging.getLogger(__name__)
instruction_sets = None
# try to load optimization level from env variable
opt_env_variable_name = "FAISS_OPT_LEVEL"
opt_level = os.environ.get(opt_env_variable_name, None)
if opt_level is None:
logger.debug(f"Environment variable {opt_env_variable_name} is not set, " \
"so let's pick the instruction set according to the current CPU")
instruction_sets = supported_instruction_sets()
else:
logger.debug(f"Using {opt_level} as an instruction set.")
instruction_sets = set()
instruction_sets.add(opt_level)
loaded = False
has_AVX512_SPR = any("AVX512_SPR" in x.upper() for x in instruction_sets)
if has_AVX512_SPR:
try:
logger.info("Loading faiss with AVX512-SPR support.")
from .swigfaiss_avx512_spr import *
logger.info("Successfully loaded faiss with AVX512-SPR support.")
loaded = True
except ImportError as e:
logger.info(f"Could not load library with AVX512-SPR support due to:\n{e!r}")
# reset so that we load without AVX512 below
loaded = False
has_AVX512 = any("AVX512" in x.upper() for x in instruction_sets)
if has_AVX512 and not loaded:
try:
logger.info("Loading faiss with AVX512 support.")
from .swigfaiss_avx512 import *
logger.info("Successfully loaded faiss with AVX512 support.")
loaded = True
except ImportError as e:
logger.info(f"Could not load library with AVX512 support due to:\n{e!r}")
# reset so that we load without AVX512 below
loaded = False
has_AVX2 = "AVX2" in instruction_sets
if has_AVX2 and not loaded:
try:
logger.info("Loading faiss with AVX2 support.")
from .swigfaiss_avx2 import *
logger.info("Successfully loaded faiss with AVX2 support.")
loaded = True
except ImportError as e:
logger.info(f"Could not load library with AVX2 support due to:\n{e!r}")
# reset so that we load without AVX2 below
loaded = False
has_SVE = "SVE" in instruction_sets
if has_SVE and not loaded:
try:
logger.info("Loading faiss with SVE support.")
from .swigfaiss_sve import *
logger.info("Successfully loaded faiss with SVE support.")
loaded = True
except ImportError as e:
logger.info(f"Could not load library with SVE support due to:\n{e!r}")
# reset so that we load without SVE below
loaded = False
if not loaded:
# we import * so that the symbol X can be accessed as faiss.X
logger.info("Loading faiss.")
from .swigfaiss import *
logger.info("Successfully loaded faiss.")