Skip to content

Commit

Permalink
Refine runtime feature discovery python API and add documentation to … (
Browse files Browse the repository at this point in the history
apache#14130)

* Refine runtime feature discovery python API and add documentation to Python API docs

* Fix lint

* Provide is_enabled method to check if feature is present from string

* Refine docs, add is_enabled

* Fix encoding

* Fix doc

* Address CR suggestions

* remove index as per CR suggestion

* Fix lint

* runtime

* Fix doc

* Add license
  • Loading branch information
larroy authored and haohuw committed Jun 23, 2019
1 parent a118ef0 commit 3c69d08
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 18 deletions.
11 changes: 11 additions & 0 deletions docs/api/python/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
69 changes: 69 additions & 0 deletions docs/api/python/libinfo/libinfo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<!--- 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. -->

# 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

<script type="text/javascript" src='../../../_static/js/auto_module_index.js'></script>

```eval_rst
.. automodule:: mxnet.runtime
:members:
```

<script>auto_index("api-reference");</script>
1 change: 0 additions & 1 deletion include/mxnet/c_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ struct MXCallbackList {

struct LibFeature {
const char* name;
uint32_t index;
bool enabled;
};

Expand Down
59 changes: 49 additions & 10 deletions python/mxnet/runtime.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
1 change: 0 additions & 1 deletion src/libinfo.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

Expand Down
22 changes: 16 additions & 6 deletions tests/python/unittest/test_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__":
Expand Down

0 comments on commit 3c69d08

Please sign in to comment.