diff --git a/docs/api/python/index.md b/docs/api/python/index.md
index 6130078ee796..2e23b162ee77 100644
--- a/docs/api/python/index.md
+++ b/docs/api/python/index.md
@@ -174,6 +174,17 @@ Code examples are placed throughout the API documentation and these can be run a
rtc/rtc.md
```
+## Run-Time Feature detection / Library Info
+
+```eval_rst
+.. toctree::
+ :maxdepth: 1
+
+ libinfo/libinfo.md
+```
+
+
+
## Symbol API
```eval_rst
diff --git a/docs/api/python/libinfo/libinfo.md b/docs/api/python/libinfo/libinfo.md
new file mode 100644
index 000000000000..531e1ced3c99
--- /dev/null
+++ b/docs/api/python/libinfo/libinfo.md
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Run-Time Feature detection / Library info
+
+```eval_rst
+.. currentmodule:: mxnet.runtime
+```
+
+## Overview
+
+The libinfo functionality allows to check for compile-time features supported by the library.
+
+### Example usage
+
+```
+In [1]: import mxnet as mx
+ ...: import mxnet.runtime
+ ...: fs = mx.runtime.Features()
+
+In [2]: fs
+Out[2]: [✖ 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]
+
+In [3]: fs['CUDA'].enabled
+Out[3]: False
+
+In [4]: fs.is_enabled('CPU_SSE')
+Out[4]: True
+
+In [5]: fs.is_enabled('CUDA')
+Out[5]: False
+
+In [6]:
+```
+
+
+```eval_rst
+.. autosummary::
+ :nosignatures:
+
+ Features
+ Feature
+ feature_list
+```
+
+## API Reference
+
+
+
+```eval_rst
+.. automodule:: mxnet.runtime
+ :members:
+```
+
+
diff --git a/include/mxnet/c_api.h b/include/mxnet/c_api.h
index e5e57c10faaa..13ee903407b3 100644
--- a/include/mxnet/c_api.h
+++ b/include/mxnet/c_api.h
@@ -141,7 +141,6 @@ struct MXCallbackList {
struct LibFeature {
const char* name;
- uint32_t index;
bool enabled;
};
diff --git a/python/mxnet/runtime.py b/python/mxnet/runtime.py
index afb393281420..7ef5e1943072 100644
--- a/python/mxnet/runtime.py
+++ b/python/mxnet/runtime.py
@@ -1,3 +1,5 @@
+# coding: utf-8
+
# 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
@@ -15,34 +17,71 @@
# 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
+import collections
from .base import _LIB, check_call
-class LibFeature(ctypes.Structure):
+class Feature(ctypes.Structure):
"""
Compile time feature description
"""
_fields_ = [
- ("name", ctypes.c_char_p),
- ("index", ctypes.c_uint32),
+ ("_name", ctypes.c_char_p),
("enabled", ctypes.c_bool)
]
-def libinfo_features():
+ @property
+ def name(self):
+ return self._name.decode()
+
+ def __repr__(self):
+ if self.enabled:
+ return "✔ {}".format(self.name)
+ else:
+ return "✖ {}".format(self.name)
+
+def feature_list():
"""
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
+ :return: list of class LibFeature indicating which features are available and enabled
"""
- lib_features = ctypes.POINTER(LibFeature)()
+ lib_features_c_array = ctypes.POINTER(Feature)()
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
+ check_call(_LIB.MXLibInfoFeatures(ctypes.byref(lib_features_c_array), ctypes.byref(lib_features_size)))
+ features = [lib_features_c_array[i] for i in range(lib_features_size.value)]
+ return features
+
+class Features(collections.OrderedDict):
+ """
+ OrderedDict of name to Feature
+ """
+ def __init__(self):
+ super(Features, self).__init__([(f.name, f) for f in feature_list()])
+
+ def __repr__(self):
+ return str(list(self.values()))
+
+ def is_enabled(self, feature_name):
+ """
+ Check for a particular feature by name
+
+ Parameters
+ ----------
+ :param x: str The name of a valid feature as string for example 'CUDA'
+
+ Returns
+ -------
+ :return: bool True if it's enabled, False if it's disabled, RuntimeError if the feature is not known
+ """
+ feature_name = feature_name.upper()
+ if feature_name not in self:
+ raise RuntimeError("Feature '{}' is unknown, known features are: {}".format(
+ feature_name, list(self.keys())))
+ return self[feature_name].enabled
diff --git a/src/libinfo.cc b/src/libinfo.cc
index 44a834c85b16..2af61eac9eca 100644
--- a/src/libinfo.cc
+++ b/src/libinfo.cc
@@ -114,7 +114,6 @@ 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;
}
}
diff --git a/tests/python/unittest/test_runtime.py b/tests/python/unittest/test_runtime.py
index 433301819252..5b06d0c3c36c 100644
--- a/tests/python/unittest/test_runtime.py
+++ b/tests/python/unittest/test_runtime.py
@@ -21,14 +21,24 @@
from mxnet.base import MXNetError
from nose.tools import *
-def test_libinfo_features():
- features = libinfo_features()
- print("Lib features: ")
+def test_features():
+ features = Features()
+ print(features)
+ ok_('CUDA' in features)
+ ok_(len(features) >= 30)
+
+def test_is_enabled():
+ features = Features()
for f in features:
- print(f.name, f.enabled, f.index)
- ok_(type(features) is list)
- ok_(len(features) > 0)
+ if features[f].enabled:
+ ok_(features.is_enabled(f))
+ else:
+ ok_(not features.is_enabled(f))
+@raises(RuntimeError)
+def test_is_enabled_not_existing():
+ features = Features()
+ features.is_enabled('this girl is on fire')
if __name__ == "__main__":