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/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/base.h b/include/mxnet/base.h index 92d9c2699d63..f88b22784a1b 100644 --- a/include/mxnet/base.h +++ b/include/mxnet/base.h @@ -25,47 +25,18 @@ #ifndef MXNET_BASE_H_ #define MXNET_BASE_H_ -#include -#include -#include -#include -#include -// nnvm headers for symbolic construction. -#include -#include -#include +#include "dmlc/base.h" #include +#include "dmlc/io.h" +#include "dmlc/type_traits.h" +#include "dmlc/parameter.h" +#include "mshadow/tensor.h" +// nnvm headers for symbolic construction. +#include "nnvm/op.h" +#include "nnvm/tuple.h" +#include "nnvm/symbolic.h" +#include "mxfeatures.h" -/*! - *\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/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/include/mxnet/io.h b/include/mxnet/io.h index 3c806d85d56a..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 -#include #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 new file mode 100644 index 000000000000..10f9b3656692 --- /dev/null +++ b/include/mxnet/mxfeatures.h @@ -0,0 +1,188 @@ +/* + * 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 "dmlc/base.h" +#include "mshadow/base.h" + +/*! + *\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 + +#ifndef MXNET_USE_NCCL +#define MXNET_USE_NCCL 0 +#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_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_LAPACK +#define MXNET_USE_LAPACK 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 + + + +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 +}; + + +/*! + * \return true if the given feature is supported + */ +bool is_enabled(uint32_t feat); + +} // namespace features +} // namespace mxnet 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 new file mode 100644 index 000000000000..c546151ab06d --- /dev/null +++ b/python/mxnet/mxfeatures.py @@ -0,0 +1,103 @@ +# 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=not-an-iterable + +"""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(): + """ + Returns + ------- + features: list of Feature + list of enabled features in the back-end + """ + res = [] + for f in Feature: + if has_feature(f.value): + res.append(f) + 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())) diff --git a/src/c_api/c_api.cc b/src/c_api/c_api.cc index 80bd60538ff5..b436e8ca601b 100644 --- a/src/c_api/c_api.cc +++ b/src/c_api/c_api.cc @@ -22,20 +22,6 @@ * \file c_api.cc * \brief C API of mxnet */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include @@ -43,6 +29,21 @@ #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 "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/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" diff --git a/src/mxfeatures.cc b/src/mxfeatures.cc new file mode 100644 index 000000000000..7a435d7c81c9 --- /dev/null +++ b/src/mxfeatures.cc @@ -0,0 +1,112 @@ +/* + * 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 + +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" +#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(const unsigned feat) const { + CHECK_LT(feat, MAX_FEATURES); + return feature_bits.test(feat); + } + + private: + std::bitset feature_bits; +}; + +static FeatureSet featureSet; + +bool is_enabled(const unsigned feat) { + return featureSet.is_enabled(feat); +} + +} // namespace features +} // namespace mxnet diff --git a/tests/python/unittest/test_features.py b/tests/python/unittest/test_features.py new file mode 100644 index 000000000000..ff9118100e41 --- /dev/null +++ b/tests/python/unittest/test_features.py @@ -0,0 +1,40 @@ +# 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 +import sys +from mxnet.mxfeatures import * +from mxnet.base import MXNetError +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())) + +@raises(MXNetError) +def test_has_feature_2large(): + has_feature(sys.maxsize) + + +if __name__ == "__main__": + import nose + nose.runmodule()