From ff109f520534a544a244e8f67c32fb1d4b0f33b6 Mon Sep 17 00:00:00 2001 From: Pedro Larroy Date: Wed, 5 Dec 2018 18:48:24 +0100 Subject: [PATCH 01/12] Prototype for runtime feature detection --- CMakeLists.txt | 2 + include/mxnet/base.h | 32 +------- include/mxnet/mxfeatures.h | 146 +++++++++++++++++++++++++++++++++++++ src/mxfeatures.cc | 91 +++++++++++++++++++++++ 4 files changed, 241 insertions(+), 30 deletions(-) create mode 100644 include/mxnet/mxfeatures.h create mode 100644 src/mxfeatures.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 23609e5ec243..18092fb4778d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -409,12 +409,14 @@ if(USE_OPENMP) endif() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + add_definitions(-DMXNET_USE_OPENMP=1) else() if(OPENMP_FOUND) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") + add_definitions(-DMXNET_USE_OPENMP=1) endif() endif() elseif(UNIX AND NOT ANDROID) diff --git a/include/mxnet/base.h b/include/mxnet/base.h index 92d9c2699d63..7fbd078bda59 100644 --- a/include/mxnet/base.h +++ b/include/mxnet/base.h @@ -25,6 +25,7 @@ #ifndef MXNET_BASE_H_ #define MXNET_BASE_H_ +#include "mxfeatures.h" #include #include #include @@ -36,36 +37,6 @@ #include #include -/*! - *\brief whether to use opencv support - */ -#ifndef MXNET_USE_OPENCV -#define MXNET_USE_OPENCV 1 -#endif - -/*! - *\brief whether to use cuda support - */ -#ifndef MXNET_USE_CUDA -#define MXNET_USE_CUDA MSHADOW_USE_CUDA -#endif - -/*! - *\brief whether to use cudnn library for convolution - */ -#ifndef MXNET_USE_CUDNN -#define MXNET_USE_CUDNN MSHADOW_USE_CUDNN -#endif - -/*! - *\brief whether to use cusolver library - */ -#ifndef MXNET_USE_CUSOLVER -#define MXNET_USE_CUSOLVER MSHADOW_USE_CUSOLVER -#endif - -/*! \brief Error message for using gpu when MXNET_USE_CUDA==0 */ -#define MXNET_GPU_NOT_ENABLED_ERROR "GPU is not enabled" /*! * \brief define compatible keywords in g++ @@ -412,6 +383,7 @@ inline std::ostream& operator<<(std::ostream &out, const Context &ctx) { #define MXNET_DESCRIBE(...) describe(__VA_ARGS__ "\n\nFrom:" __FILE__ ":" STRINGIZE(__LINE__)) #define ADD_FILELINE "\n\nDefined in " __FILE__ ":L" STRINGIZE(__LINE__) + #if MXNET_USE_MKLDNN == 1 constexpr size_t kMKLDNNAlign = 64; #endif diff --git a/include/mxnet/mxfeatures.h b/include/mxnet/mxfeatures.h new file mode 100644 index 000000000000..7ae1ca46c3c4 --- /dev/null +++ b/include/mxnet/mxfeatures.h @@ -0,0 +1,146 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/*! + * Copyright (c) 2018 by Contributors + * \file mxfeatures.h + * \brief check MXNet features including compile time support + */ + +#pragma once + +#include +#include + +/*! + *\brief whether to use opencv support + */ +#ifndef MXNET_USE_OPENCV +#define MXNET_USE_OPENCV 1 +#endif + +/*! + *\brief whether to use cuda support + */ +#ifndef MXNET_USE_CUDA +#define MXNET_USE_CUDA MSHADOW_USE_CUDA +#endif + +/*! + *\brief whether to use cudnn library for convolution + */ +#ifndef MXNET_USE_CUDNN +#define MXNET_USE_CUDNN MSHADOW_USE_CUDNN +#endif + +/*! + *\brief whether to use cusolver library + */ +#ifndef MXNET_USE_CUSOLVER +#define MXNET_USE_CUSOLVER MSHADOW_USE_CUSOLVER +#endif + +#ifndef MXNET_ENABLE_CUDA_RTC +#define MXNET_ENABLE_CUDA_RTC 0 +#endif + +/*! \brief Error message for using gpu when MXNET_USE_CUDA==0 */ +#define MXNET_GPU_NOT_ENABLED_ERROR "GPU is not enabled" + + +#ifndef MXNET_USE_TENSORRT +#define MXNET_USE_TENSORRT 0 +#endif + +#ifndef MXNET_USE_MKLDNN +#define MXNET_USE_MKLDNN 0 +#endif + +#ifndef MXNET_USE_OPENMP +#define MXNET_USE_OPENMP 0 +#endif + +#ifndef MXNET_USE_F16C +#define MXNET_USE_F16C MSHADOW_USE_F16C +#endif + +#ifndef MXNET_USE_CAFFE +#define MXNET_USE_CAFFE 0 +#endif + +#ifndef MXNET_USE_DIST_KVSTORE +#define MXNET_USE_DIST_KVSTORE 0 +#endif + +#ifndef MXNET_USE_SIGNAL_HANDLER +#define MXNET_USE_SIGNAL_HANDLER 0 +#endif + +#ifndef MXNET_USE_NCCL +#define MXNET_USE_NCCL 0 +#endif + + + +namespace mxnet { +namespace features { +// Check compile flags such as CMakeLists.txt + +/// Compile time features +enum : uint32_t { + // NVIDIA, CUDA + CUDA=0, + CUDNN, + NCCL, + CUDA_RTC, + TENSORRT, + + // Multiprocessing / CPU / System + OPENMP, + SSE, + F16C, + JEMALLOC, + + // Math libraries + LAPACK, + MKLDNN, + + // Image processing + OPENCV, + + // Misc + CAFFE, + PROFILER, + DIST_KVSTORE, + CXX14, + SIGNAL_HANDLER, + DEBUG, + + // size indicator + MAX_FEATURES +}; + + +/*! + * \return true if the given feature is supported + */ +bool is_enabled(uint32_t feat); + +} // namespace features +} // namespace mxnet diff --git a/src/mxfeatures.cc b/src/mxfeatures.cc new file mode 100644 index 000000000000..d4ec84369e09 --- /dev/null +++ b/src/mxfeatures.cc @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/*! + * Copyright (c) 2018 by Contributors + * \file mxfeatures.cc + * \brief check MXNet features including compile time support + */ + +#include "mxnet/mxfeatures.h" +#include "dmlc/logging.h" +#include + + +namespace mxnet { +namespace features { + +class Storage { +public: + Storage(): + feature_bits() + { + if (MXNET_USE_CUDA) + feature_bits.set(CUDA); + if (MXNET_USE_CUDNN) + feature_bits.set(CUDNN); + if (MXNET_USE_NCCL) + feature_bits.set(NCCL); + if (MXNET_USE_OPENCV) + feature_bits.set(OPENCV); + if (MXNET_ENABLE_CUDA_RTC) + feature_bits.set(CUDA_RTC); + if (MXNET_USE_TENSORRT) + feature_bits.set(TENSORRT); + if (MXNET_USE_OPENMP) + feature_bits.set(OPENMP); + if (MXNET_USE_F16C) + feature_bits.set(F16C); + if (MXNET_USE_LAPACK) + feature_bits.set(LAPACK); + if (MXNET_USE_MKLDNN) + feature_bits.set(MKLDNN); + if (MXNET_USE_OPENCV) + feature_bits.set(OPENCV); + if (MXNET_USE_CAFFE) + feature_bits.set(CAFFE); + if (MXNET_USE_DIST_KVSTORE) + feature_bits.set(DIST_KVSTORE); + if (MXNET_USE_SIGNAL_HANDLER) + feature_bits.set(SIGNAL_HANDLER); +#ifndef NDEBUG + feature_bits.set(DEBUG); +#endif + + +#if USE_JEMALLOC == 1 + feature_bits.set(JEMALLOC); +#endif + } + bool is_enabled(unsigned feat) { + CHECK_LT(feat, MAX_FEATURES); + return feature_bits.test(feat); + } +private: + std::bitset feature_bits; +}; + +static Storage storage; + +bool is_enabled(unsigned feat) { + return storage.is_enabled(feat); +} + +} // namespace features +} // namespace mxnet From 5ebc7a248879434fecec45f73af304e0462bd999 Mon Sep 17 00:00:00 2001 From: Pedro Larroy Date: Wed, 5 Dec 2018 19:35:57 +0100 Subject: [PATCH 02/12] Includes from diamond to quotes --- include/mxnet/base.h | 18 +++++++++--------- include/mxnet/io.h | 4 ++-- src/c_api/c_api.cc | 28 ++++++++++++++-------------- src/c_api/c_api_symbolic.cc | 12 ++++++------ 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/include/mxnet/base.h b/include/mxnet/base.h index 7fbd078bda59..ca837145e83d 100644 --- a/include/mxnet/base.h +++ b/include/mxnet/base.h @@ -25,17 +25,17 @@ #ifndef MXNET_BASE_H_ #define MXNET_BASE_H_ -#include "mxfeatures.h" -#include -#include -#include -#include -#include +#include "dmlc/base.h" +#include "dmlc/io.h" +#include "dmlc/type_traits.h" +#include "dmlc/parameter.h" +#include "mshadow/tensor.h" // nnvm headers for symbolic construction. -#include -#include -#include +#include "nnvm/op.h" +#include "nnvm/tuple.h" +#include "nnvm/symbolic.h" #include +#include "mxfeatures.h" /*! diff --git a/include/mxnet/io.h b/include/mxnet/io.h index 3c806d85d56a..e61568bba0e7 100644 --- a/include/mxnet/io.h +++ b/include/mxnet/io.h @@ -25,8 +25,8 @@ #ifndef MXNET_IO_H_ #define MXNET_IO_H_ -#include -#include +#include "dmlc/data.h" +#include "dmlc/registry.h" #include #include #include diff --git a/src/c_api/c_api.cc b/src/c_api/c_api.cc index 80bd60538ff5..a9a36ca53c6c 100644 --- a/src/c_api/c_api.cc +++ b/src/c_api/c_api.cc @@ -22,20 +22,20 @@ * \file c_api.cc * \brief C API of mxnet */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "dmlc/base.h" +#include "dmlc/logging.h" +#include "dmlc/io.h" +#include "dmlc/memory_io.h" +#include "dmlc/recordio.h" +#include "dmlc/omp.h" +#include "mxnet/base.h" +#include "mxnet/ndarray.h" +#include "mxnet/operator.h" +#include "mxnet/io.h" +#include "mxnet/c_api.h" +#include "mxnet/kvstore.h" +#include "mxnet/rtc.h" +#include "mxnet/storage.h" #include #include #include diff --git a/src/c_api/c_api_symbolic.cc b/src/c_api/c_api_symbolic.cc index 73a8a7ca6f86..8517c9c8f99b 100644 --- a/src/c_api/c_api_symbolic.cc +++ b/src/c_api/c_api_symbolic.cc @@ -22,12 +22,12 @@ * \file c_api_symbolic.cc * \brief C API of mxnet */ -#include -#include -#include -#include -#include -#include +#include "mxnet/base.h" +#include "mxnet/c_api.h" +#include "nnvm/c_api.h" +#include "nnvm/pass.h" +#include "nnvm/pass_functions.h" +#include "nnvm/symbolic.h" #include "./c_api_common.h" #include "../operator/operator_common.h" #include "../executor/exec_pass.h" From 30f057f18420c0563c7fb6660345d1640fe19674 Mon Sep 17 00:00:00 2001 From: Pedro Larroy Date: Tue, 8 Jan 2019 15:56:03 +0100 Subject: [PATCH 03/12] Add CPU feature and BLAS flavour flags --- include/mxnet/mxfeatures.h | 22 +++++++++++++++++++++- src/mxfeatures.cc | 1 + 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/include/mxnet/mxfeatures.h b/include/mxnet/mxfeatures.h index 7ae1ca46c3c4..75cdf4106346 100644 --- a/include/mxnet/mxfeatures.h +++ b/include/mxnet/mxfeatures.h @@ -111,14 +111,33 @@ enum : uint32_t { CUDA_RTC, TENSORRT, + // CPU Features / optimizations + CPU_SSE, + CPU_SSE2, + CPU_SSE3, + CPU_SSE4_1, + CPU_SSE4_2, + CPU_SSE4A, // AMD extensions to SSE4 + CPU_AVX, + CPU_AVX2, + + // Multiprocessing / CPU / System OPENMP, SSE, F16C, JEMALLOC, - // Math libraries + // Math libraries & BLAS + // Flavour of BLAS + BLAS_OPEN, + BLAS_ATLAS, + // Intel(R) Math Kernel Library + BLAS_MKL, + // Other math libraries: + // Linear Algebra PACKage LAPACK, + // Intel(R) Math Kernel Library for Deep Neural Networks MKLDNN, // Image processing @@ -129,6 +148,7 @@ enum : uint32_t { PROFILER, DIST_KVSTORE, CXX14, + // Signal handler to print stack traces on exceptions SIGNAL_HANDLER, DEBUG, diff --git a/src/mxfeatures.cc b/src/mxfeatures.cc index d4ec84369e09..4d471044621d 100644 --- a/src/mxfeatures.cc +++ b/src/mxfeatures.cc @@ -31,6 +31,7 @@ namespace mxnet { namespace features { + class Storage { public: Storage(): From e9eff40d9fcf19c991547cb86aaff3d8abb4c313 Mon Sep 17 00:00:00 2001 From: Pedro Larroy Date: Tue, 8 Jan 2019 16:39:46 +0100 Subject: [PATCH 04/12] Add BLAS flavour and CPU SSE and AVX flags --- Makefile | 10 +++++ cmake/ChooseBlas.cmake | 4 ++ include/mxnet/mxfeatures.h | 26 ++++++++++-- src/mxfeatures.cc | 87 ++++++++++++++++++++++++-------------- 4 files changed, 92 insertions(+), 35 deletions(-) diff --git a/Makefile b/Makefile index 42010e42b08c..f4769c36fe6a 100644 --- a/Makefile +++ b/Makefile @@ -212,6 +212,16 @@ ifeq ($(USE_CUDNN), 1) LDFLAGS += -lcudnn endif +ifeq ($(use_blas), open) + CFLAGS += -DMXNET_USE_BLAS_OPEN=1 +else ifeq ($(use_blas), atlas) + CFLAGS += -DMXNET_USE_BLAS_ATLAS=1 +else ifeq ($(use_blas), mkl) + CFLAGS += -DMXNET_USE_BLAS_MKL=1 +else ifeq ($(use_blas), apple) + CFLAGS += -DMXNET_USE_BLAS_APPLE=1 +endif + # whether to use F16C instruction set extension for fast fp16 compute on CPU # if cross compiling you may want to explicitly turn it off if target system does not support it ifndef USE_F16C diff --git a/cmake/ChooseBlas.cmake b/cmake/ChooseBlas.cmake index 13d7083f3d12..5f4af2d89c91 100644 --- a/cmake/ChooseBlas.cmake +++ b/cmake/ChooseBlas.cmake @@ -37,22 +37,26 @@ if(BLAS STREQUAL "Atlas" OR BLAS STREQUAL "atlas") list(APPEND mshadow_LINKER_LIBS ${Atlas_LIBRARIES}) add_definitions(-DMSHADOW_USE_CBLAS=1) add_definitions(-DMSHADOW_USE_MKL=0) + add_definitions(-DMXNET_USE_BLAS_ATLAS=1) elseif(BLAS STREQUAL "Open" OR BLAS STREQUAL "open") find_package(OpenBLAS REQUIRED) include_directories(SYSTEM ${OpenBLAS_INCLUDE_DIR}) list(APPEND mshadow_LINKER_LIBS ${OpenBLAS_LIB}) add_definitions(-DMSHADOW_USE_CBLAS=1) add_definitions(-DMSHADOW_USE_MKL=0) + add_definitions(-DMXNET_USE_BLAS_OPEN=1) elseif(BLAS STREQUAL "MKL" OR BLAS STREQUAL "mkl") find_package(MKL REQUIRED) include_directories(SYSTEM ${MKL_INCLUDE_DIR}) list(APPEND mshadow_LINKER_LIBS ${MKL_LIBRARIES}) add_definitions(-DMSHADOW_USE_CBLAS=0) add_definitions(-DMSHADOW_USE_MKL=1) + add_definitions(-DMXNET_USE_BLAS_MKL=1) elseif(BLAS STREQUAL "apple") find_package(Accelerate REQUIRED) include_directories(SYSTEM ${Accelerate_INCLUDE_DIR}) list(APPEND mshadow_LINKER_LIBS ${Accelerate_LIBRARIES}) add_definitions(-DMSHADOW_USE_MKL=0) add_definitions(-DMSHADOW_USE_CBLAS=1) + add_definitions(-DMXNET_USE_BLAS_APPLE=1) endif() diff --git a/include/mxnet/mxfeatures.h b/include/mxnet/mxfeatures.h index 75cdf4106346..ebc996f9dd24 100644 --- a/include/mxnet/mxfeatures.h +++ b/include/mxnet/mxfeatures.h @@ -49,6 +49,10 @@ #define MXNET_USE_CUDNN MSHADOW_USE_CUDNN #endif +#ifndef MXNET_USE_NCCL +#define MXNET_USE_NCCL 0 +#endif + /*! *\brief whether to use cusolver library */ @@ -68,6 +72,23 @@ #define MXNET_USE_TENSORRT 0 #endif + +#ifndef MXNET_USE_BLAS_ATLAS +#define MXNET_USE_BLAS_ATLAS 0 +#endif + +#ifndef MXNET_USE_BLAS_OPEN +#define MXNET_USE_BLAS_OPEN 0 +#endif + +#ifndef MXNET_USE_BLAS_MKL +#define MXNET_USE_BLAS_MKL 0 +#endif + +#ifndef MXNET_USE_BLAS_APPLE +#define MXNET_USE_BLAS_APPLE 0 +#endif + #ifndef MXNET_USE_MKLDNN #define MXNET_USE_MKLDNN 0 #endif @@ -92,9 +113,7 @@ #define MXNET_USE_SIGNAL_HANDLER 0 #endif -#ifndef MXNET_USE_NCCL -#define MXNET_USE_NCCL 0 -#endif + @@ -134,6 +153,7 @@ enum : uint32_t { BLAS_ATLAS, // Intel(R) Math Kernel Library BLAS_MKL, + BLAS_APPLE, // Other math libraries: // Linear Algebra PACKage LAPACK, diff --git a/src/mxfeatures.cc b/src/mxfeatures.cc index 4d471044621d..d365ef183a90 100644 --- a/src/mxfeatures.cc +++ b/src/mxfeatures.cc @@ -1,4 +1,4 @@ -/* + /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -37,44 +37,67 @@ class Storage { Storage(): feature_bits() { - if (MXNET_USE_CUDA) - feature_bits.set(CUDA); - if (MXNET_USE_CUDNN) - feature_bits.set(CUDNN); - if (MXNET_USE_NCCL) - feature_bits.set(NCCL); - if (MXNET_USE_OPENCV) - feature_bits.set(OPENCV); - if (MXNET_ENABLE_CUDA_RTC) - feature_bits.set(CUDA_RTC); - if (MXNET_USE_TENSORRT) - feature_bits.set(TENSORRT); - if (MXNET_USE_OPENMP) - feature_bits.set(OPENMP); - if (MXNET_USE_F16C) - feature_bits.set(F16C); - if (MXNET_USE_LAPACK) - feature_bits.set(LAPACK); - if (MXNET_USE_MKLDNN) - feature_bits.set(MKLDNN); - if (MXNET_USE_OPENCV) - feature_bits.set(OPENCV); - if (MXNET_USE_CAFFE) - feature_bits.set(CAFFE); - if (MXNET_USE_DIST_KVSTORE) - feature_bits.set(DIST_KVSTORE); - if (MXNET_USE_SIGNAL_HANDLER) - feature_bits.set(SIGNAL_HANDLER); + // GPU + feature_bits.set(CUDA, MXNET_USE_CUDA); + feature_bits.set(CUDNN, MXNET_USE_CUDNN); + feature_bits.set(NCCL, MXNET_USE_NCCL); + feature_bits.set(CUDA_RTC, MXNET_ENABLE_CUDA_RTC); + feature_bits.set(TENSORRT, MXNET_USE_TENSORRT); + + // Check flags for example with gcc -msse3 -mavx2 -dM -E - < /dev/null | egrep "SSE|AVX" +#if __SSE__ + feature_bits.set(CPU_SSE); +#endif +#if __SSE2__ + feature_bits.set(CPU_SSE2); +#endif +#if __SSE3__ + feature_bits.set(CPU_SSE3); +#endif +#if __SSE4_1__ + feature_bits.set(CPU_SSE4_1); +#endif +#if __SSE4_2__ + feature_bits.set(CPU_SSE4_2); +#endif +#if __SSE4A__ + feature_bits.set(CPU_SSE4A); +#endif +#if __AVX__ + feature_bits.set(CPU_AVX); +#endif +#if __AVX2__ + feature_bits.set(CPU_AVX2); +#endif + + // CPU + feature_bits.set(OPENMP, MXNET_USE_OPENMP); + feature_bits.set(F16C, MXNET_USE_F16C); + + // Math + feature_bits.set(BLAS_OPEN, MXNET_USE_BLAS_OPEN); + feature_bits.set(BLAS_ATLAS, MXNET_USE_BLAS_ATLAS); + feature_bits.set(BLAS_MKL, MXNET_USE_BLAS_MKL); + feature_bits.set(BLAS_APPLE, MXNET_USE_BLAS_APPLE); + feature_bits.set(LAPACK, MXNET_USE_LAPACK); + feature_bits.set(MKLDNN, MXNET_USE_MKLDNN); + + // Image + feature_bits.set(OPENCV, MXNET_USE_OPENCV); + + // Misc + feature_bits.set(CAFFE, MXNET_USE_CAFFE); + feature_bits.set(DIST_KVSTORE, MXNET_USE_DIST_KVSTORE); + feature_bits.set(SIGNAL_HANDLER, MXNET_USE_SIGNAL_HANDLER); #ifndef NDEBUG feature_bits.set(DEBUG); #endif - #if USE_JEMALLOC == 1 feature_bits.set(JEMALLOC); #endif } - bool is_enabled(unsigned feat) { + bool is_enabled(const unsigned feat) const { CHECK_LT(feat, MAX_FEATURES); return feature_bits.test(feat); } @@ -84,7 +107,7 @@ class Storage { static Storage storage; -bool is_enabled(unsigned feat) { +bool is_enabled(const unsigned feat) { return storage.is_enabled(feat); } From 2e60d236156295e19eeeb0455b7e0469c2d64b9e Mon Sep 17 00:00:00 2001 From: Pedro Larroy Date: Tue, 8 Jan 2019 22:12:56 +0100 Subject: [PATCH 05/12] MXNET_USE_LAPACK --- include/mxnet/mxfeatures.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/mxnet/mxfeatures.h b/include/mxnet/mxfeatures.h index ebc996f9dd24..b43f77d54d7d 100644 --- a/include/mxnet/mxfeatures.h +++ b/include/mxnet/mxfeatures.h @@ -89,6 +89,10 @@ #define MXNET_USE_BLAS_APPLE 0 #endif +#ifndef MXNET_USE_LAPACK +#define MXNET_USE_LAPACK 0 +#endif + #ifndef MXNET_USE_MKLDNN #define MXNET_USE_MKLDNN 0 #endif From d9130332602053fe377890c51512c7f82bc2e0cd Mon Sep 17 00:00:00 2001 From: Pedro Larroy Date: Tue, 8 Jan 2019 23:50:19 +0100 Subject: [PATCH 06/12] Fix C++ linting errors --- include/mxnet/base.h | 2 +- include/mxnet/io.h | 4 ++-- include/mxnet/mxfeatures.h | 6 +++--- src/mxfeatures.cc | 10 +++++----- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/mxnet/base.h b/include/mxnet/base.h index ca837145e83d..f88b22784a1b 100644 --- a/include/mxnet/base.h +++ b/include/mxnet/base.h @@ -26,6 +26,7 @@ #define MXNET_BASE_H_ #include "dmlc/base.h" +#include #include "dmlc/io.h" #include "dmlc/type_traits.h" #include "dmlc/parameter.h" @@ -34,7 +35,6 @@ #include "nnvm/op.h" #include "nnvm/tuple.h" #include "nnvm/symbolic.h" -#include #include "mxfeatures.h" diff --git a/include/mxnet/io.h b/include/mxnet/io.h index e61568bba0e7..e18f03ed0ef3 100644 --- a/include/mxnet/io.h +++ b/include/mxnet/io.h @@ -25,12 +25,12 @@ #ifndef MXNET_IO_H_ #define MXNET_IO_H_ -#include "dmlc/data.h" -#include "dmlc/registry.h" #include #include #include #include +#include "dmlc/data.h" +#include "dmlc/registry.h" #include "./base.h" #include "./ndarray.h" diff --git a/include/mxnet/mxfeatures.h b/include/mxnet/mxfeatures.h index b43f77d54d7d..c40fc1933f27 100644 --- a/include/mxnet/mxfeatures.h +++ b/include/mxnet/mxfeatures.h @@ -25,8 +25,8 @@ #pragma once -#include -#include +#include "dmlc/base.h" +#include "mshadow/base.h" /*! *\brief whether to use opencv support @@ -128,7 +128,7 @@ namespace features { /// Compile time features enum : uint32_t { // NVIDIA, CUDA - CUDA=0, + CUDA = 0, CUDNN, NCCL, CUDA_RTC, diff --git a/src/mxfeatures.cc b/src/mxfeatures.cc index d365ef183a90..705de1e50142 100644 --- a/src/mxfeatures.cc +++ b/src/mxfeatures.cc @@ -24,8 +24,8 @@ */ #include "mxnet/mxfeatures.h" -#include "dmlc/logging.h" #include +#include "dmlc/logging.h" namespace mxnet { @@ -33,10 +33,9 @@ namespace features { class Storage { -public: + public: Storage(): - feature_bits() - { + feature_bits() { // GPU feature_bits.set(CUDA, MXNET_USE_CUDA); feature_bits.set(CUDNN, MXNET_USE_CUDNN); @@ -101,7 +100,8 @@ class Storage { CHECK_LT(feat, MAX_FEATURES); return feature_bits.test(feat); } -private: + + private: std::bitset feature_bits; }; From 939d76c8f18960d1e832cb45b6e651d0834d786a Mon Sep 17 00:00:00 2001 From: Pedro Larroy Date: Wed, 9 Jan 2019 01:38:49 +0100 Subject: [PATCH 07/12] Expose runtime feature detection in the public C API and in the Python API --- include/mxnet/c_api.h | 10 +++ python/mxnet/mxfeatures.py | 91 ++++++++++++++++++++++++++ src/c_api/c_api.cc | 22 +++++-- tests/python/unittest/test_features.py | 34 ++++++++++ 4 files changed, 150 insertions(+), 7 deletions(-) create mode 100644 python/mxnet/mxfeatures.py create mode 100644 tests/python/unittest/test_features.py diff --git a/include/mxnet/c_api.h b/include/mxnet/c_api.h index e9f1e2d6cccc..79f2bf518696 100644 --- a/include/mxnet/c_api.h +++ b/include/mxnet/c_api.h @@ -208,6 +208,15 @@ MXNET_DLL const char *MXGetLastError(); //------------------------------------- // Part 0: Global State setups //------------------------------------- + +/*! + * \brief + * \param feature to check mxfeatures.h + * \param out set to true if the feature is enabled, false otherwise + * \return 0 when success, -1 when failure happens. + */ +MXNET_DLL int MXHasFeature(const mx_uint feature, bool* out); + /*! * \brief Seed all global random number generators in mxnet. * \param seed the random number seed. @@ -465,6 +474,7 @@ MXNET_DLL int MXGetGPUMemoryInformation64(int dev, uint64_t *free_mem, uint64_t */ MXNET_DLL int MXGetVersion(int *out); + //------------------------------------- // Part 1: NDArray creation and deletion //------------------------------------- diff --git a/python/mxnet/mxfeatures.py b/python/mxnet/mxfeatures.py new file mode 100644 index 000000000000..eb03ba660033 --- /dev/null +++ b/python/mxnet/mxfeatures.py @@ -0,0 +1,91 @@ + # Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# coding: utf-8 +# pylint: disable=invalid-name, no-member, trailing-comma-tuple, bad-mcs-classmethod-argument + +"""runtime detection of compile time features in the native library""" + +import ctypes +import enum +from .base import _LIB, check_call, mx_uint + +feature_names = [ + "CUDA", + "CUDNN", + "NCCL", + "CUDA_RTC", + "TENSORRT", + "CPU_SSE", + "CPU_SSE2", + "CPU_SSE3", + "CPU_SSE4_1", + "CPU_SSE4_2", + "CPU_SSE4A", + "CPU_AVX", + "CPU_AVX2", + "OPENMP", + "SSE", + "F16C", + "JEMALLOC", + "BLAS_OPEN", + "BLAS_ATLAS", + "BLAS_MKL", + "BLAS_APPLE", + "LAPACK", + "MKLDNN", + "OPENCV", + "CAFFE", + "PROFILER", + "DIST_KVSTORE", + "CXX14", + "SIGNAL_HANDLER", + "DEBUG" +] + + +Feature = enum.Enum('Feature', {name: index for index, name in enumerate(feature_names)}) + + +def has_feature(feature): + """ + Check the library for compile-time feature at runtime + + Parameters + ---------- + feature : int + An integer representing the feature to check + + Returns + ------- + boolean + True if the feature is enabled, false otherwise + """ + res = ctypes.c_bool() + check_call(_LIB.MXHasFeature(mx_uint(feature), ctypes.byref(res))) + return res.value + + +def features_enabled(): + res = [] + for f in Feature: + if has_feature(f.value): + res.append(f) + return res + +def features_enabled_str(sep=', '): + return sep.join(map(lambda x: x.name, features_enabled())) diff --git a/src/c_api/c_api.cc b/src/c_api/c_api.cc index a9a36ca53c6c..b436e8ca601b 100644 --- a/src/c_api/c_api.cc +++ b/src/c_api/c_api.cc @@ -22,6 +22,13 @@ * \file c_api.cc * \brief C API of mxnet */ +#include +#include +#include +#include +#include +#include +#include #include "dmlc/base.h" #include "dmlc/logging.h" #include "dmlc/io.h" @@ -36,13 +43,7 @@ #include "mxnet/kvstore.h" #include "mxnet/rtc.h" #include "mxnet/storage.h" -#include -#include -#include -#include -#include -#include -#include +#include "mxnet/mxfeatures.h" #include "./c_api_common.h" #include "../operator/custom/custom-inl.h" #include "../operator/tensor/matrix_op-inl.h" @@ -85,6 +86,13 @@ inline int MXAPIGetFunctionRegInfo(const FunRegType *e, } // NOTE: return value is added in API_END + +int MXHasFeature(const mx_uint feature, bool* out) { + API_BEGIN(); + *out = features::is_enabled(feature); + API_END(); +} + int MXRandomSeed(int seed) { API_BEGIN(); mxnet::RandomSeed(seed); diff --git a/tests/python/unittest/test_features.py b/tests/python/unittest/test_features.py new file mode 100644 index 000000000000..34f7f07868a3 --- /dev/null +++ b/tests/python/unittest/test_features.py @@ -0,0 +1,34 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +import mxnet as mx +from mxnet.mxfeatures import * +from nose.tools import * + +def test_runtime_features(): + for f in Feature: + res = has_feature(f.value) + ok_(type(res) is bool) + for f in features_enabled(): + ok_(type(f) is Feature) + ok_(type(features_enabled_str()) is str) + print("Features enabled: {}".format(features_enabled_str())) + + +if __name__ == "__main__": + import nose + nose.runmodule() From 80ae05e28ec38248c3cd6f8569ffc05326e347e6 Mon Sep 17 00:00:00 2001 From: Pedro Larroy Date: Wed, 9 Jan 2019 01:47:20 +0100 Subject: [PATCH 08/12] Refactor Storage -> FeatureSet --- src/mxfeatures.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mxfeatures.cc b/src/mxfeatures.cc index 705de1e50142..0397826a8457 100644 --- a/src/mxfeatures.cc +++ b/src/mxfeatures.cc @@ -32,9 +32,9 @@ namespace mxnet { namespace features { -class Storage { +class FeatureSet { public: - Storage(): + FeatureSet(): feature_bits() { // GPU feature_bits.set(CUDA, MXNET_USE_CUDA); @@ -105,10 +105,10 @@ class Storage { std::bitset feature_bits; }; -static Storage storage; +static FeatureSet featureSet; bool is_enabled(const unsigned feat) { - return storage.is_enabled(feat); + return featureSet.is_enabled(feat); } } // namespace features From c6bdb54f0767ed559e1f22df287fcd5be6ae65ee Mon Sep 17 00:00:00 2001 From: Pedro Larroy Date: Wed, 9 Jan 2019 01:58:10 +0100 Subject: [PATCH 09/12] Refine documentation --- python/mxnet/mxfeatures.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/python/mxnet/mxfeatures.py b/python/mxnet/mxfeatures.py index eb03ba660033..54c9ddfe622b 100644 --- a/python/mxnet/mxfeatures.py +++ b/python/mxnet/mxfeatures.py @@ -81,6 +81,12 @@ def has_feature(feature): def features_enabled(): + """ + Returns + ------- + features: list of Feature + list of enabled features in the back-end + """ res = [] for f in Feature: if has_feature(f.value): @@ -88,4 +94,10 @@ def features_enabled(): return res def features_enabled_str(sep=', '): + """ + Returns + ------- + string with a comma separated list of enabled features in the back-end. For example: + "CPU_SSE, OPENMP, F16C, LAPACK, MKLDNN, OPENCV, SIGNAL_HANDLER, DEBUG" + """ return sep.join(map(lambda x: x.name, features_enabled())) From a27af1052961b1572bb6e6e4c71f22993cfb9a82 Mon Sep 17 00:00:00 2001 From: Pedro Larroy Date: Wed, 9 Jan 2019 02:08:18 +0100 Subject: [PATCH 10/12] Add failure case --- tests/python/unittest/test_features.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/python/unittest/test_features.py b/tests/python/unittest/test_features.py index 34f7f07868a3..ff9118100e41 100644 --- a/tests/python/unittest/test_features.py +++ b/tests/python/unittest/test_features.py @@ -16,7 +16,9 @@ # under the License. import mxnet as mx +import sys from mxnet.mxfeatures import * +from mxnet.base import MXNetError from nose.tools import * def test_runtime_features(): @@ -28,6 +30,10 @@ def test_runtime_features(): ok_(type(features_enabled_str()) is str) print("Features enabled: {}".format(features_enabled_str())) +@raises(MXNetError) +def test_has_feature_2large(): + has_feature(sys.maxsize) + if __name__ == "__main__": import nose From 799a567313abaca684912291b8d07502816e58ea Mon Sep 17 00:00:00 2001 From: Pedro Larroy Date: Wed, 9 Jan 2019 02:47:42 +0100 Subject: [PATCH 11/12] Fix pylint --- python/mxnet/gluon/utils.py | 2 +- python/mxnet/mxfeatures.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python/mxnet/gluon/utils.py b/python/mxnet/gluon/utils.py index 78324986760a..55edd950d223 100644 --- a/python/mxnet/gluon/utils.py +++ b/python/mxnet/gluon/utils.py @@ -222,7 +222,7 @@ def _replace_atomic(src, dst): _MOVEFILE_WRITE_THROUGH = 0x8 _windows_default_flags = _MOVEFILE_WRITE_THROUGH - text_type = unicode if sys.version_info[0] == 2 else str # noqa + text_type = unicode if sys.version_info[0] == 2 else str # pylint: disable=undefined-variable def _str_to_unicode(x): """Handle text decoding. Internal use only""" diff --git a/python/mxnet/mxfeatures.py b/python/mxnet/mxfeatures.py index 54c9ddfe622b..22c94f423c59 100644 --- a/python/mxnet/mxfeatures.py +++ b/python/mxnet/mxfeatures.py @@ -16,7 +16,7 @@ # under the License. # coding: utf-8 -# pylint: disable=invalid-name, no-member, trailing-comma-tuple, bad-mcs-classmethod-argument +# pylint: disable=not-an-iterable """runtime detection of compile time features in the native library""" From ba356cfb2dfebf602e484e54303f153ee2adaf25 Mon Sep 17 00:00:00 2001 From: Pedro Larroy Date: Tue, 15 Jan 2019 12:24:19 +0100 Subject: [PATCH 12/12] Address CR comments --- include/mxnet/mxfeatures.h | 104 ++++++++++++++++++------------------- python/mxnet/mxfeatures.py | 2 +- src/mxfeatures.cc | 97 +++++++++++++++++----------------- 3 files changed, 99 insertions(+), 104 deletions(-) diff --git a/include/mxnet/mxfeatures.h b/include/mxnet/mxfeatures.h index c40fc1933f27..10f9b3656692 100644 --- a/include/mxnet/mxfeatures.h +++ b/include/mxnet/mxfeatures.h @@ -119,65 +119,63 @@ - - namespace mxnet { namespace features { // Check compile flags such as CMakeLists.txt /// Compile time features enum : uint32_t { - // NVIDIA, CUDA - CUDA = 0, - CUDNN, - NCCL, - CUDA_RTC, - TENSORRT, - - // CPU Features / optimizations - CPU_SSE, - CPU_SSE2, - CPU_SSE3, - CPU_SSE4_1, - CPU_SSE4_2, - CPU_SSE4A, // AMD extensions to SSE4 - CPU_AVX, - CPU_AVX2, - - - // Multiprocessing / CPU / System - OPENMP, - SSE, - F16C, - JEMALLOC, - - // Math libraries & BLAS - // Flavour of BLAS - BLAS_OPEN, - BLAS_ATLAS, - // Intel(R) Math Kernel Library - BLAS_MKL, - BLAS_APPLE, - // Other math libraries: - // Linear Algebra PACKage - LAPACK, - // Intel(R) Math Kernel Library for Deep Neural Networks - MKLDNN, - - // Image processing - OPENCV, - - // Misc - CAFFE, - PROFILER, - DIST_KVSTORE, - CXX14, - // Signal handler to print stack traces on exceptions - SIGNAL_HANDLER, - DEBUG, - - // size indicator - MAX_FEATURES + // NVIDIA, CUDA + CUDA = 0, + CUDNN, + NCCL, + CUDA_RTC, + TENSORRT, + + // CPU Features / optimizations + CPU_SSE, + CPU_SSE2, + CPU_SSE3, + CPU_SSE4_1, + CPU_SSE4_2, + CPU_SSE4A, // AMD extensions to SSE4 + CPU_AVX, + CPU_AVX2, + + + // Multiprocessing / CPU / System + OPENMP, + SSE, + F16C, + JEMALLOC, + + // Math libraries & BLAS + // Flavour of BLAS + BLAS_OPEN, + BLAS_ATLAS, + // Intel(R) Math Kernel Library + BLAS_MKL, + BLAS_APPLE, + // Other math libraries: + // Linear Algebra PACKage + LAPACK, + // Intel(R) Math Kernel Library for Deep Neural Networks + MKLDNN, + + // Image processing + OPENCV, + + // Misc + CAFFE, + PROFILER, + DIST_KVSTORE, + CXX14, + // Signal handler to print stack traces on exceptions + SIGNAL_HANDLER, + DEBUG, + + // size indicator + MAX_FEATURES }; diff --git a/python/mxnet/mxfeatures.py b/python/mxnet/mxfeatures.py index 22c94f423c59..c546151ab06d 100644 --- a/python/mxnet/mxfeatures.py +++ b/python/mxnet/mxfeatures.py @@ -1,4 +1,4 @@ - # Licensed to the Apache Software Foundation (ASF) under one +# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file diff --git a/src/mxfeatures.cc b/src/mxfeatures.cc index 0397826a8457..7a435d7c81c9 100644 --- a/src/mxfeatures.cc +++ b/src/mxfeatures.cc @@ -1,4 +1,4 @@ - /* +/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -25,90 +25,87 @@ #include "mxnet/mxfeatures.h" #include -#include "dmlc/logging.h" - namespace mxnet { namespace features { - class FeatureSet { public: - FeatureSet(): - feature_bits() { - // GPU - feature_bits.set(CUDA, MXNET_USE_CUDA); - feature_bits.set(CUDNN, MXNET_USE_CUDNN); - feature_bits.set(NCCL, MXNET_USE_NCCL); - feature_bits.set(CUDA_RTC, MXNET_ENABLE_CUDA_RTC); - feature_bits.set(TENSORRT, MXNET_USE_TENSORRT); - - // Check flags for example with gcc -msse3 -mavx2 -dM -E - < /dev/null | egrep "SSE|AVX" + FeatureSet() : + feature_bits() { + // GPU + feature_bits.set(CUDA, MXNET_USE_CUDA); + feature_bits.set(CUDNN, MXNET_USE_CUDNN); + feature_bits.set(NCCL, MXNET_USE_NCCL); + feature_bits.set(CUDA_RTC, MXNET_ENABLE_CUDA_RTC); + feature_bits.set(TENSORRT, MXNET_USE_TENSORRT); + + // Check flags for example with gcc -msse3 -mavx2 -dM -E - < /dev/null | egrep "SSE|AVX" #if __SSE__ - feature_bits.set(CPU_SSE); + feature_bits.set(CPU_SSE); #endif #if __SSE2__ - feature_bits.set(CPU_SSE2); + feature_bits.set(CPU_SSE2); #endif #if __SSE3__ - feature_bits.set(CPU_SSE3); + feature_bits.set(CPU_SSE3); #endif #if __SSE4_1__ - feature_bits.set(CPU_SSE4_1); + feature_bits.set(CPU_SSE4_1); #endif #if __SSE4_2__ - feature_bits.set(CPU_SSE4_2); + feature_bits.set(CPU_SSE4_2); #endif #if __SSE4A__ - feature_bits.set(CPU_SSE4A); + feature_bits.set(CPU_SSE4A); #endif #if __AVX__ - feature_bits.set(CPU_AVX); + feature_bits.set(CPU_AVX); #endif #if __AVX2__ - feature_bits.set(CPU_AVX2); + feature_bits.set(CPU_AVX2); #endif - // CPU - feature_bits.set(OPENMP, MXNET_USE_OPENMP); - feature_bits.set(F16C, MXNET_USE_F16C); - - // Math - feature_bits.set(BLAS_OPEN, MXNET_USE_BLAS_OPEN); - feature_bits.set(BLAS_ATLAS, MXNET_USE_BLAS_ATLAS); - feature_bits.set(BLAS_MKL, MXNET_USE_BLAS_MKL); - feature_bits.set(BLAS_APPLE, MXNET_USE_BLAS_APPLE); - feature_bits.set(LAPACK, MXNET_USE_LAPACK); - feature_bits.set(MKLDNN, MXNET_USE_MKLDNN); - - // Image - feature_bits.set(OPENCV, MXNET_USE_OPENCV); - - // Misc - feature_bits.set(CAFFE, MXNET_USE_CAFFE); - feature_bits.set(DIST_KVSTORE, MXNET_USE_DIST_KVSTORE); - feature_bits.set(SIGNAL_HANDLER, MXNET_USE_SIGNAL_HANDLER); + // CPU + feature_bits.set(OPENMP, MXNET_USE_OPENMP); + feature_bits.set(F16C, MXNET_USE_F16C); + + // Math + feature_bits.set(BLAS_OPEN, MXNET_USE_BLAS_OPEN); + feature_bits.set(BLAS_ATLAS, MXNET_USE_BLAS_ATLAS); + feature_bits.set(BLAS_MKL, MXNET_USE_BLAS_MKL); + feature_bits.set(BLAS_APPLE, MXNET_USE_BLAS_APPLE); + feature_bits.set(LAPACK, MXNET_USE_LAPACK); + feature_bits.set(MKLDNN, MXNET_USE_MKLDNN); + + // Image + feature_bits.set(OPENCV, MXNET_USE_OPENCV); + + // Misc + feature_bits.set(CAFFE, MXNET_USE_CAFFE); + feature_bits.set(DIST_KVSTORE, MXNET_USE_DIST_KVSTORE); + feature_bits.set(SIGNAL_HANDLER, MXNET_USE_SIGNAL_HANDLER); #ifndef NDEBUG - feature_bits.set(DEBUG); + feature_bits.set(DEBUG); #endif #if USE_JEMALLOC == 1 - feature_bits.set(JEMALLOC); + feature_bits.set(JEMALLOC); #endif - } - bool is_enabled(const unsigned feat) const { - CHECK_LT(feat, MAX_FEATURES); - return feature_bits.test(feat); - } + } + bool is_enabled(const unsigned feat) const { + CHECK_LT(feat, MAX_FEATURES); + return feature_bits.test(feat); + } private: - std::bitset feature_bits; + std::bitset feature_bits; }; static FeatureSet featureSet; bool is_enabled(const unsigned feat) { - return featureSet.is_enabled(feat); + return featureSet.is_enabled(feat); } } // namespace features