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()