You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mxnet.apache.org by zh...@apache.org on 2019/02/12 01:57:11 UTC
[incubator-mxnet] branch master updated: Addresses comments in
runtime feature discovery API (#13964)
This is an automated email from the ASF dual-hosted git repository.
zhasheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-mxnet.git
The following commit(s) were added to refs/heads/master by this push:
new f5ba735 Addresses comments in runtime feature discovery API (#13964)
f5ba735 is described below
commit f5ba7358d7ff0629f48445cf9dc1ce7fe2fd8e84
Author: Pedro Larroy <pe...@gmail.com>
AuthorDate: Tue Feb 12 02:56:49 2019 +0100
Addresses comments in runtime feature discovery API (#13964)
* Prototype for runtime feature detection
* Includes from diamond to quotes
* Add CPU feature and BLAS flavour flags
* Add BLAS flavour and CPU SSE and AVX flags
* MXNET_USE_LAPACK
* Fix C++ linting errors
* Expose runtime feature detection in the public C API and in the Python API
* Refactor Storage -> FeatureSet
* Refine documentation
* Add failure case
* Fix pylint
* Address CR comments
* Address CR comments
* Address CR
* Address CR
* Address CR
* Address CR
* remove old files
* Fix unit test
* Port CMake blas change from #13957
* Fix lint
* mxruntime -> libinfo
* Fix comments
* restore libinfo.py
* Rework API for feature detection / libinfo
* Refine documentation
* Fix lint
* Fix lint
* Define make_unique only for C++ std < 14
* Add memory include
* remove old tests
* make_unique fiasco
* Fix lint
---
CMakeLists.txt | 2 +-
include/mxnet/base.h | 9 +-
include/mxnet/c_api.h | 14 ++-
include/mxnet/{mxfeatures.h => libinfo.h} | 34 +++++--
python/mxnet/mxfeatures.py | 103 ---------------------
python/mxnet/runtime.py | 48 ++++++++++
src/c_api/c_api.cc | 9 +-
src/c_api/c_api_profile.cc | 10 +-
src/{mxfeatures.cc => libinfo.cc} | 55 ++++++++++-
tests/cpp/misc/libinfo_test.cc | 33 +++++++
tests/python/unittest/test_features.py | 40 --------
.../unittest/{test_libinfo.py => test_runtime.py} | 20 ++--
12 files changed, 203 insertions(+), 174 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2f974e8..d8ef524 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -294,8 +294,8 @@ else()
add_definitions(-DMXNET_USE_NCCL=0)
endif()
+include(cmake/ChooseBlas.cmake)
if(USE_CUDA AND FIRST_CUDA)
- include(cmake/ChooseBlas.cmake)
include(3rdparty/mshadow/cmake/Utils.cmake)
include(cmake/FirstClassLangCuda.cmake)
include_directories(${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES})
diff --git a/include/mxnet/base.h b/include/mxnet/base.h
index 7f12643..26c1a1b 100644
--- a/include/mxnet/base.h
+++ b/include/mxnet/base.h
@@ -35,7 +35,7 @@
#include "nnvm/op.h"
#include "nnvm/tuple.h"
#include "nnvm/symbolic.h"
-#include "mxfeatures.h"
+#include "libinfo.h"
/*!
@@ -403,7 +403,14 @@ template<> struct hash<mxnet::Context> {
return res;
}
};
+
+#if __cplusplus < 201402L && !defined(_MSC_VER)
+template<typename T, typename... Args>
+inline std::unique_ptr<T> make_unique(Args&&... args) {
+ return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
+#endif
+} // namespace std
#include "./tensor_blob.h"
//! \endcond
diff --git a/include/mxnet/c_api.h b/include/mxnet/c_api.h
index d6e13eb..e5e57c1 100644
--- a/include/mxnet/c_api.h
+++ b/include/mxnet/c_api.h
@@ -139,6 +139,12 @@ struct MXCallbackList {
void **contexts;
};
+struct LibFeature {
+ const char* name;
+ uint32_t index;
+ bool enabled;
+};
+
enum CustomOpCallbacks {
kCustomOpDelete,
kCustomOpForward,
@@ -210,12 +216,12 @@ MXNET_DLL const char *MXGetLastError();
//-------------------------------------
/*!
- * \brief
- * \param feature to check mxfeatures.h
- * \param out set to true if the feature is enabled, false otherwise
+ * \brief Get list of features supported on the runtime
+ * \param libFeature pointer to array of LibFeature
+ * \param size of the array
* \return 0 when success, -1 when failure happens.
*/
-MXNET_DLL int MXHasFeature(const mx_uint feature, bool* out);
+MXNET_DLL int MXLibInfoFeatures(const struct LibFeature **libFeature, size_t *size);
/*!
* \brief Seed all global random number generators in mxnet.
diff --git a/include/mxnet/mxfeatures.h b/include/mxnet/libinfo.h
similarity index 82%
rename from include/mxnet/mxfeatures.h
rename to include/mxnet/libinfo.h
index 10f9b36..f35d41a 100644
--- a/include/mxnet/mxfeatures.h
+++ b/include/mxnet/libinfo.h
@@ -18,21 +18,27 @@
*/
/*!
- * Copyright (c) 2018 by Contributors
- * \file mxfeatures.h
- * \brief check MXNet features including compile time support
+ * Copyright (c) 2018 by Contributors
+ * \file libinfo.h
+ * \author larroy
+ * \brief get features of the MXNet library at runtime
*/
#pragma once
+#include <string>
+#include <vector>
+#include <array>
+#include <memory>
#include "dmlc/base.h"
#include "mshadow/base.h"
+#include "c_api.h"
/*!
*\brief whether to use opencv support
*/
#ifndef MXNET_USE_OPENCV
-#define MXNET_USE_OPENCV 1
+#define MXNET_USE_OPENCV 0
#endif
/*!
@@ -124,7 +130,8 @@ namespace features {
// Check compile flags such as CMakeLists.txt
/// Compile time features
-enum : uint32_t {
+// ATTENTION: When changing this enum, match the strings in the implementation file!
+enum : unsigned {
// NVIDIA, CUDA
CUDA = 0,
CUDNN,
@@ -179,10 +186,25 @@ enum : uint32_t {
};
+struct EnumNames {
+ static const std::vector<std::string> names;
+};
+
+struct LibInfo {
+ LibInfo();
+ static LibInfo* getInstance();
+ const std::array<LibFeature, MAX_FEATURES>& getFeatures() {
+ return m_lib_features;
+ }
+ private:
+ std::array<LibFeature, MAX_FEATURES> m_lib_features;
+ static std::unique_ptr<LibInfo> m_inst;
+};
+
/*!
* \return true if the given feature is supported
*/
-bool is_enabled(uint32_t feat);
+bool is_enabled(unsigned feat);
} // namespace features
} // namespace mxnet
diff --git a/python/mxnet/mxfeatures.py b/python/mxnet/mxfeatures.py
deleted file mode 100644
index c546151..0000000
--- a/python/mxnet/mxfeatures.py
+++ /dev/null
@@ -1,103 +0,0 @@
-# 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/python/mxnet/runtime.py b/python/mxnet/runtime.py
new file mode 100644
index 0000000..afb3932
--- /dev/null
+++ b/python/mxnet/runtime.py
@@ -0,0 +1,48 @@
+# 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 querying of compile time features in the native library"""
+
+import ctypes
+from .base import _LIB, check_call
+
+class LibFeature(ctypes.Structure):
+ """
+ Compile time feature description
+ """
+ _fields_ = [
+ ("name", ctypes.c_char_p),
+ ("index", ctypes.c_uint32),
+ ("enabled", ctypes.c_bool)
+ ]
+
+def libinfo_features():
+ """
+ Check the library for compile-time features. The list of features are maintained in libinfo.h and libinfo.cc
+
+ Returns
+ -------
+ A list of class LibFeature indicating which features are available and enabled
+ """
+ lib_features = ctypes.POINTER(LibFeature)()
+ lib_features_size = ctypes.c_size_t()
+ check_call(_LIB.MXLibInfoFeatures(ctypes.byref(lib_features), ctypes.byref(lib_features_size)))
+ feature_list = [lib_features[i] for i in range(lib_features_size.value)]
+ return feature_list
diff --git a/src/c_api/c_api.cc b/src/c_api/c_api.cc
index b436e8c..7e03acc 100644
--- a/src/c_api/c_api.cc
+++ b/src/c_api/c_api.cc
@@ -43,7 +43,7 @@
#include "mxnet/kvstore.h"
#include "mxnet/rtc.h"
#include "mxnet/storage.h"
-#include "mxnet/mxfeatures.h"
+#include "mxnet/libinfo.h"
#include "./c_api_common.h"
#include "../operator/custom/custom-inl.h"
#include "../operator/tensor/matrix_op-inl.h"
@@ -87,9 +87,12 @@ inline int MXAPIGetFunctionRegInfo(const FunRegType *e,
// NOTE: return value is added in API_END
-int MXHasFeature(const mx_uint feature, bool* out) {
+int MXLibInfoFeatures(const struct LibFeature **lib_features, size_t *size) {
+ using namespace features;
API_BEGIN();
- *out = features::is_enabled(feature);
+ LibInfo* lib_info = LibInfo::getInstance();
+ *lib_features = lib_info->getFeatures().data();
+ *size = lib_info->getFeatures().size();
API_END();
}
diff --git a/src/c_api/c_api_profile.cc b/src/c_api/c_api_profile.cc
index dc1b781..0de7b48 100644
--- a/src/c_api/c_api_profile.cc
+++ b/src/c_api/c_api_profile.cc
@@ -52,11 +52,6 @@ struct APICallTimingData {
#endif // PROFILE_API_INCLUDE_AS_EVENT
};
-template<typename T, typename... Args>
-inline std::unique_ptr<T> make_unique(Args&&... args) {
- return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
-}
-
/*!
* \brief Per-thread profiling data
*/
@@ -78,7 +73,7 @@ class ProfilingThreadData {
auto iter = tasks_.find(name);
if (iter == tasks_.end()) {
iter = tasks_.emplace(std::make_pair(
- name, make_unique<profiler::ProfileTask>(name, domain))).first;
+ name, std::make_unique<profiler::ProfileTask>(name, domain))).first;
}
return iter->second.get();
}
@@ -93,7 +88,8 @@ class ProfilingThreadData {
// Per-thread so no lock necessary
auto iter = events_.find(name);
if (iter == events_.end()) {
- iter = events_.emplace(std::make_pair(name, make_unique<profiler::ProfileEvent>(name))).first;
+ iter = events_.emplace(std::make_pair(name,
+ std::make_unique<profiler::ProfileEvent>(name))).first;
}
return iter->second.get();
}
diff --git a/src/mxfeatures.cc b/src/libinfo.cc
similarity index 75%
rename from src/mxfeatures.cc
rename to src/libinfo.cc
index 7a435d7..44a834c 100644
--- a/src/mxfeatures.cc
+++ b/src/libinfo.cc
@@ -19,12 +19,14 @@
/*!
* Copyright (c) 2018 by Contributors
- * \file mxfeatures.cc
+ * \file libinfo.cc
+ * \author larroy
* \brief check MXNet features including compile time support
*/
-#include "mxnet/mxfeatures.h"
+#include "mxnet/libinfo.h"
#include <bitset>
+#include "mxnet/base.h"
namespace mxnet {
namespace features {
@@ -108,5 +110,54 @@ bool is_enabled(const unsigned feat) {
return featureSet.is_enabled(feat);
}
+LibInfo::LibInfo() {
+ for (size_t i = 0; i < MAX_FEATURES; ++i) {
+ m_lib_features[i].name = EnumNames::names[i].c_str();
+ m_lib_features[i].enabled = is_enabled(i);
+ m_lib_features[i].index = i;
+ }
+}
+
+LibInfo *LibInfo::getInstance() {
+ if (!m_inst)
+ m_inst = std::make_unique<LibInfo>();
+ return m_inst.get();
+}
+
+std::unique_ptr<LibInfo> LibInfo::m_inst = nullptr;
+
+const std::vector<std::string> EnumNames::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",
+};
+
} // namespace features
} // namespace mxnet
diff --git a/tests/cpp/misc/libinfo_test.cc b/tests/cpp/misc/libinfo_test.cc
new file mode 100644
index 0000000..57f8f8d
--- /dev/null
+++ b/tests/cpp/misc/libinfo_test.cc
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+#include <mxnet/libinfo.h>
+
+using namespace mxnet;
+using namespace std;
+using namespace mxnet::features;
+
+/*
+ * Test that enum and string values are in sync
+ */
+TEST(RuntimeTest, RuntimeTestAll) {
+ EXPECT_EQ(EnumNames::names.size(), MAX_FEATURES);
+ const auto& features = LibInfo::getInstance()->getFeatures();
+}
diff --git a/tests/python/unittest/test_features.py b/tests/python/unittest/test_features.py
deleted file mode 100644
index ff91181..0000000
--- a/tests/python/unittest/test_features.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# 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()
diff --git a/tests/python/unittest/test_libinfo.py b/tests/python/unittest/test_runtime.py
similarity index 71%
rename from tests/python/unittest/test_libinfo.py
rename to tests/python/unittest/test_runtime.py
index 66bf031..4333018 100644
--- a/tests/python/unittest/test_libinfo.py
+++ b/tests/python/unittest/test_runtime.py
@@ -15,16 +15,22 @@
# specific language governing permissions and limitations
# under the License.
-import os
import mxnet as mx
-from mxnet import libinfo
+import sys
+from mxnet.runtime import *
+from mxnet.base import MXNetError
+from nose.tools import *
-def test_include_path():
- incl_path = libinfo.find_include_path()
- assert os.path.exists(incl_path)
- assert os.path.isdir(incl_path)
+def test_libinfo_features():
+ features = libinfo_features()
+ print("Lib features: ")
+ for f in features:
+ print(f.name, f.enabled, f.index)
+ ok_(type(features) is list)
+ ok_(len(features) > 0)
-if __name__ == '__main__':
+
+if __name__ == "__main__":
import nose
nose.runmodule()