From a48210e46afb9d50d17b5db0dbab724d9ce433f4 Mon Sep 17 00:00:00 2001 From: Manu Seth Date: Mon, 8 Jul 2019 16:19:22 -0700 Subject: [PATCH 01/38] Accelerator APIs header file --- include/mxnet/mxnet_acc.h | 119 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 include/mxnet/mxnet_acc.h diff --git a/include/mxnet/mxnet_acc.h b/include/mxnet/mxnet_acc.h new file mode 100644 index 000000000000..0e59043d0449 --- /dev/null +++ b/include/mxnet/mxnet_acc.h @@ -0,0 +1,119 @@ +/* + * 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) 2015 by Contributors + * \file mxnet_acc.h + * \brief Accelerator APIs to interact with accelerator libraries + */ +#ifndef MXNET_MXNET_ACC_H_ +#define MXNET_MXNET_ACC_H_ + +#include +#include "../dlpack/dlpack.h" + +extern "C" { + /* + Function: getAccName + Parameters: + - char* : short accelerator name given by acc library + Returns: + */ + void getAccName(char*); + + /* + Function: getNumAcc + Parameters: + Returns: Number of accelerators in the system + */ + int getNumAcc(); + + /* + Function: initialize + Parameters: + - int : MXNet version passed to the acc library + Returns: Success/Failure code + Failure code if library cannot be used with given MXNet version + */ + int initialize(int); + + /* + Function: supportedOps + Parameters: + - const char* : Graph json + - const char*[] : Data names + - const DLTensor* : Corresponding data + - const int : Number of data elements + - int* : Node/Operator IDs supported by acclerator + Returns: + */ + void supportedOps(const char*, const char*[], const DLTensor*, + const int, int*); + + /* + Function: loadModel + Parameters: + - const char* : Model ID assigned to subgraph + - const char* : Graph json + - const char*[] : Data names + - const DLTensor* : Corresponding data + - const int : Number of data elements + - const int : Accelerator ID in the system + Returns: Success/Failure code + */ + int loadModel(const char*, const char*, const char*[], + const DLTensor*, const int, const int); + + /* + Function: unloadModel + Parameters: + - const char* : Model ID assigned to subgraph + Returns: + */ + void unloadModel(const char*); + + /* + Function: infer + Parameters: + - const char* : Model ID assigned to subgraph + - const char*[] : Input data names + - const char*[] : Output data names + - const DLTensor* : Corresponding Input data + - DLTensor* : Output data given by accelerator + - const int : Number of input data elements + - const int : Number of output data elements + Returns: Success/Failure code + */ + int infer(const char*, const char*[], const char*[], + const DLTensor*, DLTensor*, const int, const int); + + /* + Function: configure + Parameters: + - const char*[] : Input keys + - const char*[] : Input values + - const int : Number of input pairs + - char*[] : Output keys + - char*[] : Output values + - int* : Number of output pairs + */ + int configure(const char*[], const char*[], const int, + char*[], char*[], int*); +} +#endif // MXNET_MXNET_ACC_H_ From 63958da9aded91c97122d701db5b0910239af738 Mon Sep 17 00:00:00 2001 From: Manu Seth Date: Wed, 17 Jul 2019 17:41:04 -0700 Subject: [PATCH 02/38] rebaseing with master --- CMakeLists.txt | 1 + Makefile | 2 +- include/mxnet/base.h | 75 ++++++++++++++++++++++++++++++++++++----- include/mxnet/library.h | 34 +++++++++++++++++++ python/mxnet/context.py | 28 +++++++++++++++ src/c_api/c_api.cc | 9 ++++- src/common/base.cc | 31 +++++++++++++++++ src/common/library.cc | 47 ++++++++++++++++++++++++++ 8 files changed, 216 insertions(+), 11 deletions(-) create mode 100644 include/mxnet/library.h create mode 100644 src/common/base.cc create mode 100644 src/common/library.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c479f756295..65fe54e13ec6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -757,6 +757,7 @@ if(USE_TVM_OP) endif() target_link_libraries(mxnet PUBLIC ${mxnet_LINKER_LIBS}) +target_link_libraries(mxnet PRIVATE ${CMAKE_DL_LIBS}) if(USE_PLUGINS_WARPCTC) target_link_libraries(mxnet PUBLIC debug ${WARPCTC_LIB_DEBUG}) diff --git a/Makefile b/Makefile index b54df174acde..f1e21d6fa945 100644 --- a/Makefile +++ b/Makefile @@ -107,7 +107,7 @@ else CFLAGS += -O3 -DNDEBUG=1 endif CFLAGS += -I$(TPARTYDIR)/mshadow/ -I$(TPARTYDIR)/dmlc-core/include -fPIC -I$(NNVM_PATH)/include -I$(DLPACK_PATH)/include -I$(TPARTYDIR)/tvm/include -Iinclude $(MSHADOW_CFLAGS) -LDFLAGS = -pthread $(MSHADOW_LDFLAGS) $(DMLC_LDFLAGS) +LDFLAGS = -pthread -ldl $(MSHADOW_LDFLAGS) $(DMLC_LDFLAGS) ifeq ($(ENABLE_TESTCOVERAGE), 1) CFLAGS += --coverage diff --git a/include/mxnet/base.h b/include/mxnet/base.h index c1e2da7a9db3..52f618760f6f 100644 --- a/include/mxnet/base.h +++ b/include/mxnet/base.h @@ -25,8 +25,9 @@ #ifndef MXNET_BASE_H_ #define MXNET_BASE_H_ -#include "dmlc/base.h" #include +#include +#include "dmlc/base.h" #include "dmlc/io.h" #include "dmlc/type_traits.h" #include "dmlc/parameter.h" @@ -36,7 +37,8 @@ #include "nnvm/symbolic.h" #include "libinfo.h" #include "tuple.h" - +#include "library.h" +#include "mxnet_acc.h" /*! * \brief define compatible keywords in g++ @@ -98,15 +100,30 @@ typedef mshadow::default_real_t real_t; /*! \brief operator structure from NNVM */ using Op = nnvm::Op; +struct AccContext { + int kAccType; + std::string accName; + + /*! \brief default constructor */ + AccContext() : kAccType(0), accName("Error") {} + /*! \brief constructor */ + AccContext(int type, std::string name) : kAccType(type), accName(name) {} +}; + /*! \brief Context information about the execution environment */ struct Context { /*! \brief Type of device */ - enum DeviceType { - kCPU = cpu::kDevMask, - kGPU = gpu::kDevMask, - kCPUPinned = 3, - kCPUShared = 5, - }; + static const int kCPU = 1; + static const int kGPU = 2; + static const int kCPUPinned = 3; + static const int kCPUShared = 5; + static const int kAccBase = 10; + + typedef int DeviceType; + + static std::map acc_map; + static std::map acc_names; + /*! \brief the device type we run the op on */ DeviceType dev_type; /*! \brief device id we are going to run it on */ @@ -126,6 +143,7 @@ struct Context { */ inline int real_dev_id() const { if (dev_type == kCPUPinned || dev_type == kGPU) return dev_id; + else if (dev_type >= kAccBase) return dev_id; return 0; } /*! @@ -169,7 +187,7 @@ struct Context { return true; } /*! \brief the maximal device type */ - static const int32_t kMaxDevType = 6; + static const int32_t kMaxDevType = 20; /*! \brief the maximal device index */ static const int32_t kMaxDevID = 16; /*! @@ -227,6 +245,12 @@ struct Context { * \return Context */ inline static Context FromString(const std::string& str); + /*! + * Load accelerator from given path and get its name + * \param path of .so file and name of the accelerator + * \return No return value + */ + inline static int LoadAcc(const std::string& path, char *name); private: #if MXNET_USE_CUDA @@ -517,6 +541,9 @@ inline Context Context::FromString(const std::string& str) { ret = CPUPinned(id); } else if (type == "cpu_shared") { ret = CPUShared(id); + } else if (Context::acc_names.find(type) != Context::acc_names.end()) { + DeviceType dev_type = Context::acc_names[type]; + ret = Create(dev_type, id); } else { LOG(FATAL) << "Invalid context string " << str; } @@ -526,6 +553,34 @@ inline Context Context::FromString(const std::string& str) { return ret; } +inline int Context::LoadAcc(const std::string& path, char *name) { + // load library + void *lib = load_lib(path.c_str()); + if (!lib) + LOG(FATAL) << "Unable to load library"; + + // get name function from library + void (*getAccName)(char*); + get_func(lib, reinterpret_cast(&getAccName), const_cast("getAccName")); + if (!getAccName) + LOG(FATAL) << "Unable to get accelerator name from library"; + + // call name function + char accname[100]; + getAccName(accname); + std::string name_str(accname); + snprintf(name, name_str.size(), "%s", name_str.c_str()); + + // create entry for accelerator + int id = Context::kAccBase + Context::acc_map.size(); + AccContext ctx(id, name_str); + + // add accelerator context to map + Context::acc_map[id] = ctx; + Context::acc_names[name_str] = id; + return id; +} + inline std::ostream& operator<<(std::ostream &out, const Context &ctx) { if (ctx.dev_type == Context::kCPU) { out << "cpu("; @@ -535,6 +590,8 @@ inline std::ostream& operator<<(std::ostream &out, const Context &ctx) { out << "cpu_pinned("; } else if (ctx.dev_type == Context::kCPUShared) { out << "cpu_shared("; + } else if (Context::acc_map.find(ctx.dev_type) != Context::acc_map.end()) { + out << Context::acc_map[ctx.dev_type].accName << "("; } else { out << "unknown("; } diff --git a/include/mxnet/library.h b/include/mxnet/library.h new file mode 100644 index 000000000000..a0cf94acf7b8 --- /dev/null +++ b/include/mxnet/library.h @@ -0,0 +1,34 @@ +/* + * 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) 2015 by Contributors + * \file library.h + * \brief Defining accelerator loading functions + */ +#ifndef MXNET_LIBRARY_H_ +#define MXNET_LIBRARY_H_ + +#include +#include + +void* load_lib(const char* path); +void get_func(void* handle, void** func, char* name); + +#endif // MXNET_LIBRARY_H_ diff --git a/python/mxnet/context.py b/python/mxnet/context.py index f284e00127b4..eac78fdea99d 100644 --- a/python/mxnet/context.py +++ b/python/mxnet/context.py @@ -21,6 +21,7 @@ import threading import warnings import ctypes +import os from .base import classproperty, with_metaclass, _MXClassPropertyMetaClass from .base import _LIB from .base import check_call @@ -71,6 +72,7 @@ class Context(with_metaclass(_MXClassPropertyMetaClass, object)): _default_ctx = threading.local() devtype2str = {1: 'cpu', 2: 'gpu', 3: 'cpu_pinned', 5: 'cpu_shared'} devstr2type = {'cpu': 1, 'gpu': 2, 'cpu_pinned': 3, 'cpu_shared': 5} + acc_map = {} def __init__(self, device_type, device_id=0): if isinstance(device_type, Context): self.device_typeid = device_type.device_typeid @@ -167,6 +169,32 @@ def empty_cache(self): Context._default_ctx.value = Context('cpu', 0) +def load_acc(path): + #check if path exists + if not os.path.exists(path): + print('load_acc path "%s" does NOT exist' % path) + return None + #check if path is to a file + if not os.path.isfile(path): + print('load_acc path "%s" is NOT a library file' % path) + return None + + byt_obj = path.encode('utf-8') + chararr = ctypes.c_char_p(byt_obj) + dev_id = ctypes.c_int() + name = ctypes.create_string_buffer(100) + + check_call(_LIB.MXLoadAccLib(chararr,ctypes.byref(dev_id),name)) + + dev_id = dev_id.value + name = name.value + Context.devtype2str[dev_id] = name + Context.devstr2type[name] = dev_id + Context.acc_map[dev_id] = (name,path) + + return Context(name, 0) + + def cpu(device_id=0): """Returns a CPU context. diff --git a/src/c_api/c_api.cc b/src/c_api/c_api.cc index 5207bdfa444b..5680835a82ea 100644 --- a/src/c_api/c_api.cc +++ b/src/c_api/c_api.cc @@ -87,9 +87,16 @@ inline int MXAPIGetFunctionRegInfo(const FunRegType *e, *arg_descriptions = dmlc::BeginPtr(ret->ret_vec_charp) + (e->arguments.size() * 2); API_END(); } - // NOTE: return value is added in API_END +int MXLoadAccLib(const char *path, int *id, char *name) { + API_BEGIN(); + std::string tmp(path); + int dev_id = mxnet::Context::LoadAcc(tmp, name); + *id = dev_id; + API_END(); +} + int MXLibInfoFeatures(const struct LibFeature **lib_features, size_t *size) { using namespace features; API_BEGIN(); diff --git a/src/common/base.cc b/src/common/base.cc new file mode 100644 index 000000000000..bcdce1cc71ab --- /dev/null +++ b/src/common/base.cc @@ -0,0 +1,31 @@ +/* + * 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) 2015 by Contributors + * \file base.cc + * \brief Defining map variables for the header file + */ +#include +#include + +#include "../../include/mxnet/base.h" + +std::map mxnet::Context::acc_map; +std::map mxnet::Context::acc_names; diff --git a/src/common/library.cc b/src/common/library.cc new file mode 100644 index 000000000000..a3fe47293059 --- /dev/null +++ b/src/common/library.cc @@ -0,0 +1,47 @@ +/* + * 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) 2015 by Contributors + * \file library.cc + * \brief Dynamically loading accelerator library + * and accessing its functions + */ + +#include "../../include/mxnet/library.h" + +void* load_lib(const char* path) { + void *handle; + handle = dlopen(path, RTLD_LAZY); + + if (!handle) { + std::cerr << "Error loading accelerator library: '" << path + << "'\n" << dlerror() << std::endl; + return 0; + } + return handle; +} + +void get_func(void* handle, void** func, char* name) { + *reinterpret_cast(func) = dlsym(handle, name); + if (!func) { + std::cerr << "Error getting function '" << name + << "' from accelerator library\n" << dlerror() << std::endl; + } +} From 5f9d6faadbeb9cc458d216fb711716b24127ea83 Mon Sep 17 00:00:00 2001 From: Manu Seth Date: Fri, 12 Jul 2019 16:17:05 -0700 Subject: [PATCH 03/38] adding example to test accelerator loading --- example/accel_api/Makefile | 5 +++++ example/accel_api/myacc.cpp | 8 ++++++++ example/accel_api/test.py | 4 ++++ 3 files changed, 17 insertions(+) create mode 100644 example/accel_api/Makefile create mode 100644 example/accel_api/myacc.cpp create mode 100644 example/accel_api/test.py diff --git a/example/accel_api/Makefile b/example/accel_api/Makefile new file mode 100644 index 000000000000..1a265f482f92 --- /dev/null +++ b/example/accel_api/Makefile @@ -0,0 +1,5 @@ +all: + g++ -shared -fPIC myacc.cpp -o libmyacc.so -I ../../include/mxnet + +clean: + rm -rf libmyacc.so diff --git a/example/accel_api/myacc.cpp b/example/accel_api/myacc.cpp new file mode 100644 index 000000000000..123bc45ad6a5 --- /dev/null +++ b/example/accel_api/myacc.cpp @@ -0,0 +1,8 @@ +#include "mxnet/mxnet_acc.h" +#include +#include + +extern "C" void getAccName(char* s) { + std::string name = "myacc"; + strcpy(s,name.c_str()); +} diff --git a/example/accel_api/test.py b/example/accel_api/test.py new file mode 100644 index 000000000000..6d26b030b19d --- /dev/null +++ b/example/accel_api/test.py @@ -0,0 +1,4 @@ +import mxnet as mx + +ctx = mx.context.load_acc('libmyacc.so') +print(ctx) From 4f9a021467e493bb9049d86df74ae7a6ca36d310 Mon Sep 17 00:00:00 2001 From: Manu Seth Date: Mon, 15 Jul 2019 02:37:33 -0700 Subject: [PATCH 04/38] adding c_api function header --- include/mxnet/base.h | 3 +-- include/mxnet/c_api.h | 9 +++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/mxnet/base.h b/include/mxnet/base.h index 52f618760f6f..f753ca4a3163 100644 --- a/include/mxnet/base.h +++ b/include/mxnet/base.h @@ -38,7 +38,6 @@ #include "libinfo.h" #include "tuple.h" #include "library.h" -#include "mxnet_acc.h" /*! * \brief define compatible keywords in g++ @@ -569,7 +568,7 @@ inline int Context::LoadAcc(const std::string& path, char *name) { char accname[100]; getAccName(accname); std::string name_str(accname); - snprintf(name, name_str.size(), "%s", name_str.c_str()); + snprintf(name, name_str.size()+1, "%s", name_str.c_str()); // create entry for accelerator int id = Context::kAccBase + Context::acc_map.size(); diff --git a/include/mxnet/c_api.h b/include/mxnet/c_api.h index 058f859ae7bc..30c6cbd39ef7 100644 --- a/include/mxnet/c_api.h +++ b/include/mxnet/c_api.h @@ -226,6 +226,15 @@ MXNET_DLL const char *MXGetLastError(); // Part 0: Global State setups //------------------------------------- +/*! + * \brief Get the context name and id for the accelerator library + * \param path to the library .so file + * \param id pointer to accelerator id + * \param name pointer to context name + * \return 0 when success, -1 when failure happens. + */ +MXNET_DLL int MXLoadAccLib(const char *path, int *id, char *name); + /*! * \brief Get list of features supported on the runtime * \param libFeature pointer to array of LibFeature From d5196955908ab41b8462291727f8590e6d8e0818 Mon Sep 17 00:00:00 2001 From: Manu Seth Date: Mon, 15 Jul 2019 03:04:20 -0700 Subject: [PATCH 05/38] modifying header file path --- example/accel_api/myacc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/accel_api/myacc.cpp b/example/accel_api/myacc.cpp index 123bc45ad6a5..d546f90d77d2 100644 --- a/example/accel_api/myacc.cpp +++ b/example/accel_api/myacc.cpp @@ -1,4 +1,4 @@ -#include "mxnet/mxnet_acc.h" +#include "mxnet_acc.h" #include #include From 602a37278ab3b0bfc451ab4891544c81dee49ffb Mon Sep 17 00:00:00 2001 From: Manu Seth Date: Mon, 15 Jul 2019 14:27:47 -0700 Subject: [PATCH 06/38] creating templates for call to lib fns --- example/accel_api/Makefile | 17 +++++++++++++++++ example/accel_api/my_accel.cc | 33 +++++++++++++++++++++++++++++++++ example/accel_api/myacc.cpp | 8 -------- example/accel_api/test.py | 20 ++++++++++++++++++++ include/mxnet/base.h | 6 ++---- include/mxnet/library.h | 12 +++++++++++- include/mxnet/mxnet_acc.h | 3 +++ python/mxnet/context.py | 14 ++++++++++++-- src/common/library.cc | 6 +++--- 9 files changed, 101 insertions(+), 18 deletions(-) create mode 100644 example/accel_api/my_accel.cc delete mode 100644 example/accel_api/myacc.cpp diff --git a/example/accel_api/Makefile b/example/accel_api/Makefile index 1a265f482f92..005fd21e0cb7 100644 --- a/example/accel_api/Makefile +++ b/example/accel_api/Makefile @@ -1,3 +1,20 @@ +# 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. + all: g++ -shared -fPIC myacc.cpp -o libmyacc.so -I ../../include/mxnet diff --git a/example/accel_api/my_accel.cc b/example/accel_api/my_accel.cc new file mode 100644 index 000000000000..285d063cfdfc --- /dev/null +++ b/example/accel_api/my_accel.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. + */ + +/*! + * Copyright (c) 2015 by Contributors + * \file my_accel.cc + * \brief Sample library functions + */ + +#include "mxnet_acc.h" +#include +#include + +void getAccName(char* s) { + std::string name = "myacc"; + strcpy(s,name.c_str()); +} diff --git a/example/accel_api/myacc.cpp b/example/accel_api/myacc.cpp deleted file mode 100644 index d546f90d77d2..000000000000 --- a/example/accel_api/myacc.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "mxnet_acc.h" -#include -#include - -extern "C" void getAccName(char* s) { - std::string name = "myacc"; - strcpy(s,name.c_str()); -} diff --git a/example/accel_api/test.py b/example/accel_api/test.py index 6d26b030b19d..78f7fec59737 100644 --- a/example/accel_api/test.py +++ b/example/accel_api/test.py @@ -1,3 +1,23 @@ +# 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=arguments-differ + import mxnet as mx ctx = mx.context.load_acc('libmyacc.so') diff --git a/include/mxnet/base.h b/include/mxnet/base.h index f753ca4a3163..25bf845cbaec 100644 --- a/include/mxnet/base.h +++ b/include/mxnet/base.h @@ -38,6 +38,7 @@ #include "libinfo.h" #include "tuple.h" #include "library.h" +#include "mxnet_acc.h" /*! * \brief define compatible keywords in g++ @@ -559,10 +560,7 @@ inline int Context::LoadAcc(const std::string& path, char *name) { LOG(FATAL) << "Unable to load library"; // get name function from library - void (*getAccName)(char*); - get_func(lib, reinterpret_cast(&getAccName), const_cast("getAccName")); - if (!getAccName) - LOG(FATAL) << "Unable to get accelerator name from library"; + getAccName_t getAccName = get_func(lib, const_cast(GETACCNAME_STR)); // call name function char accname[100]; diff --git a/include/mxnet/library.h b/include/mxnet/library.h index a0cf94acf7b8..e7d2ecf2771b 100644 --- a/include/mxnet/library.h +++ b/include/mxnet/library.h @@ -27,8 +27,18 @@ #include #include +#include "dmlc/io.h" void* load_lib(const char* path); -void get_func(void* handle, void** func, char* name); +void get_sym(void* handle, void** func, char* name); + +template +T get_func(void *lib, char *func_name) { + T func; + get_sym(lib, reinterpret_cast(&func), func_name); + if (!func) + LOG(FATAL) << "Unable to get function '" << func_name << "' from library"; + return func; +} #endif // MXNET_LIBRARY_H_ diff --git a/include/mxnet/mxnet_acc.h b/include/mxnet/mxnet_acc.h index 0e59043d0449..30648d648c44 100644 --- a/include/mxnet/mxnet_acc.h +++ b/include/mxnet/mxnet_acc.h @@ -28,6 +28,9 @@ #include #include "../dlpack/dlpack.h" +#define GETACCNAME_STR "getAccName" +typedef void (*getAccName_t)(char*); + extern "C" { /* Function: getAccName diff --git a/python/mxnet/context.py b/python/mxnet/context.py index eac78fdea99d..36ba8131f2ab 100644 --- a/python/mxnet/context.py +++ b/python/mxnet/context.py @@ -170,6 +170,16 @@ def empty_cache(self): def load_acc(path): + """Loads accelerator library and returns corresponding context. + + Parameters + ---------- + path : Path to accelerator library .so file + + Returns + ------- + context : Context + """ #check if path exists if not os.path.exists(path): print('load_acc path "%s" does NOT exist' % path) @@ -184,13 +194,13 @@ def load_acc(path): dev_id = ctypes.c_int() name = ctypes.create_string_buffer(100) - check_call(_LIB.MXLoadAccLib(chararr,ctypes.byref(dev_id),name)) + check_call(_LIB.MXLoadAccLib(chararr, ctypes.byref(dev_id), name)) dev_id = dev_id.value name = name.value Context.devtype2str[dev_id] = name Context.devstr2type[name] = dev_id - Context.acc_map[dev_id] = (name,path) + Context.acc_map[dev_id] = (name, path) return Context(name, 0) diff --git a/src/common/library.cc b/src/common/library.cc index a3fe47293059..af84970fe5e0 100644 --- a/src/common/library.cc +++ b/src/common/library.cc @@ -38,9 +38,9 @@ void* load_lib(const char* path) { return handle; } -void get_func(void* handle, void** func, char* name) { - *reinterpret_cast(func) = dlsym(handle, name); - if (!func) { +void get_sym(void* handle, void** func, char* name) { + *func = dlsym(handle, name); + if (!(*func)) { std::cerr << "Error getting function '" << name << "' from accelerator library\n" << dlerror() << std::endl; } From 565dbd26e3251f35960f0b33d95f08442d58522b Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Thu, 18 Jul 2019 00:29:13 +0000 Subject: [PATCH 07/38] modifying target to mxnet_static for libdl --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 65fe54e13ec6..a86435f9900f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -701,6 +701,7 @@ if(UNIX) add_library(mxnet SHARED ${DUMMY_SOURCE}) target_link_libraries(mxnet PRIVATE ${BEGIN_WHOLE_ARCHIVE} $ ${END_WHOLE_ARCHIVE}) target_link_libraries(mxnet PRIVATE mxnet_static) + target_link_libraries(mxnet_static PUBLIC ${CMAKE_DL_LIBS}) set_target_properties(mxnet_static PROPERTIES OUTPUT_NAME mxnet) else() add_library(mxnet SHARED ${SOURCE}) @@ -757,7 +758,6 @@ if(USE_TVM_OP) endif() target_link_libraries(mxnet PUBLIC ${mxnet_LINKER_LIBS}) -target_link_libraries(mxnet PRIVATE ${CMAKE_DL_LIBS}) if(USE_PLUGINS_WARPCTC) target_link_libraries(mxnet PUBLIC debug ${WARPCTC_LIB_DEBUG}) From 3dc78325f58e102466fe7471a98ff91dd900f69d Mon Sep 17 00:00:00 2001 From: Manu Seth Date: Fri, 19 Jul 2019 14:07:13 -0700 Subject: [PATCH 08/38] returning nullptr handle if library not loaded --- src/common/library.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/library.cc b/src/common/library.cc index af84970fe5e0..edfe50658391 100644 --- a/src/common/library.cc +++ b/src/common/library.cc @@ -33,7 +33,7 @@ void* load_lib(const char* path) { if (!handle) { std::cerr << "Error loading accelerator library: '" << path << "'\n" << dlerror() << std::endl; - return 0; + return nullptr; } return handle; } From 001bbb155e418c3271e7b798ba62c0d742131ea8 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 23 Jul 2019 00:53:16 +0000 Subject: [PATCH 09/38] refactoring code to load libraries dynamically --- example/{accel_api => lib_api}/Makefile | 4 +- .../my_accel.cc => lib_api/mylib.cc} | 16 ++- example/{accel_api => lib_api}/test.py | 3 +- include/mxnet/base.h | 72 ++--------- include/mxnet/c_api.h | 6 +- src/common/base.cc => include/mxnet/lib_api.h | 29 +++-- include/mxnet/mxnet_acc.h | 122 ------------------ python/mxnet/__init__.py | 1 + python/mxnet/context.py | 38 ------ python/mxnet/library.py | 51 ++++++++ src/c_api/c_api.cc | 17 ++- 11 files changed, 110 insertions(+), 249 deletions(-) rename example/{accel_api => lib_api}/Makefile (90%) rename example/{accel_api/my_accel.cc => lib_api/mylib.cc} (75%) rename example/{accel_api => lib_api}/test.py (94%) rename src/common/base.cc => include/mxnet/lib_api.h (59%) delete mode 100644 include/mxnet/mxnet_acc.h create mode 100644 python/mxnet/library.py diff --git a/example/accel_api/Makefile b/example/lib_api/Makefile similarity index 90% rename from example/accel_api/Makefile rename to example/lib_api/Makefile index 005fd21e0cb7..4e27857a7e1d 100644 --- a/example/accel_api/Makefile +++ b/example/lib_api/Makefile @@ -16,7 +16,7 @@ # under the License. all: - g++ -shared -fPIC myacc.cpp -o libmyacc.so -I ../../include/mxnet + g++ -shared -fPIC mylib.cc -o mylib.so -I ../../include/mxnet clean: - rm -rf libmyacc.so + rm -rf mylib.so diff --git a/example/accel_api/my_accel.cc b/example/lib_api/mylib.cc similarity index 75% rename from example/accel_api/my_accel.cc rename to example/lib_api/mylib.cc index 285d063cfdfc..df6f705b0ffd 100644 --- a/example/accel_api/my_accel.cc +++ b/example/lib_api/mylib.cc @@ -23,11 +23,15 @@ * \brief Sample library functions */ -#include "mxnet_acc.h" -#include -#include +#include +#include "lib_api.h" -void getAccName(char* s) { - std::string name = "myacc"; - strcpy(s,name.c_str()); +int initialize(int version) { + if (version >= 10400) { + std::cout << "MXNet version " << version << " supported" << std::endl; + return 1; + } else { + std::cout << "MXNet version " << version << " not supported" << std::endl; + return 0; + } } diff --git a/example/accel_api/test.py b/example/lib_api/test.py similarity index 94% rename from example/accel_api/test.py rename to example/lib_api/test.py index 78f7fec59737..0ad55f027ad6 100644 --- a/example/accel_api/test.py +++ b/example/lib_api/test.py @@ -20,5 +20,4 @@ import mxnet as mx -ctx = mx.context.load_acc('libmyacc.so') -print(ctx) +mx.library.load_lib('mylib.so') diff --git a/include/mxnet/base.h b/include/mxnet/base.h index 25bf845cbaec..c1e2da7a9db3 100644 --- a/include/mxnet/base.h +++ b/include/mxnet/base.h @@ -25,9 +25,8 @@ #ifndef MXNET_BASE_H_ #define MXNET_BASE_H_ -#include -#include #include "dmlc/base.h" +#include #include "dmlc/io.h" #include "dmlc/type_traits.h" #include "dmlc/parameter.h" @@ -37,8 +36,7 @@ #include "nnvm/symbolic.h" #include "libinfo.h" #include "tuple.h" -#include "library.h" -#include "mxnet_acc.h" + /*! * \brief define compatible keywords in g++ @@ -100,30 +98,15 @@ typedef mshadow::default_real_t real_t; /*! \brief operator structure from NNVM */ using Op = nnvm::Op; -struct AccContext { - int kAccType; - std::string accName; - - /*! \brief default constructor */ - AccContext() : kAccType(0), accName("Error") {} - /*! \brief constructor */ - AccContext(int type, std::string name) : kAccType(type), accName(name) {} -}; - /*! \brief Context information about the execution environment */ struct Context { /*! \brief Type of device */ - static const int kCPU = 1; - static const int kGPU = 2; - static const int kCPUPinned = 3; - static const int kCPUShared = 5; - static const int kAccBase = 10; - - typedef int DeviceType; - - static std::map acc_map; - static std::map acc_names; - + enum DeviceType { + kCPU = cpu::kDevMask, + kGPU = gpu::kDevMask, + kCPUPinned = 3, + kCPUShared = 5, + }; /*! \brief the device type we run the op on */ DeviceType dev_type; /*! \brief device id we are going to run it on */ @@ -143,7 +126,6 @@ struct Context { */ inline int real_dev_id() const { if (dev_type == kCPUPinned || dev_type == kGPU) return dev_id; - else if (dev_type >= kAccBase) return dev_id; return 0; } /*! @@ -187,7 +169,7 @@ struct Context { return true; } /*! \brief the maximal device type */ - static const int32_t kMaxDevType = 20; + static const int32_t kMaxDevType = 6; /*! \brief the maximal device index */ static const int32_t kMaxDevID = 16; /*! @@ -245,12 +227,6 @@ struct Context { * \return Context */ inline static Context FromString(const std::string& str); - /*! - * Load accelerator from given path and get its name - * \param path of .so file and name of the accelerator - * \return No return value - */ - inline static int LoadAcc(const std::string& path, char *name); private: #if MXNET_USE_CUDA @@ -541,9 +517,6 @@ inline Context Context::FromString(const std::string& str) { ret = CPUPinned(id); } else if (type == "cpu_shared") { ret = CPUShared(id); - } else if (Context::acc_names.find(type) != Context::acc_names.end()) { - DeviceType dev_type = Context::acc_names[type]; - ret = Create(dev_type, id); } else { LOG(FATAL) << "Invalid context string " << str; } @@ -553,31 +526,6 @@ inline Context Context::FromString(const std::string& str) { return ret; } -inline int Context::LoadAcc(const std::string& path, char *name) { - // load library - void *lib = load_lib(path.c_str()); - if (!lib) - LOG(FATAL) << "Unable to load library"; - - // get name function from library - getAccName_t getAccName = get_func(lib, const_cast(GETACCNAME_STR)); - - // call name function - char accname[100]; - getAccName(accname); - std::string name_str(accname); - snprintf(name, name_str.size()+1, "%s", name_str.c_str()); - - // create entry for accelerator - int id = Context::kAccBase + Context::acc_map.size(); - AccContext ctx(id, name_str); - - // add accelerator context to map - Context::acc_map[id] = ctx; - Context::acc_names[name_str] = id; - return id; -} - inline std::ostream& operator<<(std::ostream &out, const Context &ctx) { if (ctx.dev_type == Context::kCPU) { out << "cpu("; @@ -587,8 +535,6 @@ inline std::ostream& operator<<(std::ostream &out, const Context &ctx) { out << "cpu_pinned("; } else if (ctx.dev_type == Context::kCPUShared) { out << "cpu_shared("; - } else if (Context::acc_map.find(ctx.dev_type) != Context::acc_map.end()) { - out << Context::acc_map[ctx.dev_type].accName << "("; } else { out << "unknown("; } diff --git a/include/mxnet/c_api.h b/include/mxnet/c_api.h index 30c6cbd39ef7..376c7e9d1063 100644 --- a/include/mxnet/c_api.h +++ b/include/mxnet/c_api.h @@ -227,13 +227,11 @@ MXNET_DLL const char *MXGetLastError(); //------------------------------------- /*! - * \brief Get the context name and id for the accelerator library + * \brief Load library dynamically * \param path to the library .so file - * \param id pointer to accelerator id - * \param name pointer to context name * \return 0 when success, -1 when failure happens. */ -MXNET_DLL int MXLoadAccLib(const char *path, int *id, char *name); +MXNET_DLL int MXLoadLib(const char *path); /*! * \brief Get list of features supported on the runtime diff --git a/src/common/base.cc b/include/mxnet/lib_api.h similarity index 59% rename from src/common/base.cc rename to include/mxnet/lib_api.h index bcdce1cc71ab..5f549a290262 100644 --- a/src/common/base.cc +++ b/include/mxnet/lib_api.h @@ -18,14 +18,27 @@ */ /*! - * Copyright (c) 2015 by Contributors - * \file base.cc - * \brief Defining map variables for the header file + * Copyright (c) 2015 by Contributors + * \file lib_api.h + * \brief APIs to interact with libraries */ -#include -#include +#ifndef MXNET_LIB_API_H_ +#define MXNET_LIB_API_H_ -#include "../../include/mxnet/base.h" +#include +#include "../dlpack/dlpack.h" -std::map mxnet::Context::acc_map; -std::map mxnet::Context::acc_names; +#define INITIALIZE_STR "initialize" +typedef int (*initialize_t)(int); + +extern "C" { + /* + Function: initialize + Parameters: + - int : MXNet version passed to library + Returns: Success/Failure code + Failure code if library cannot be used with passed MXNet version + */ + int initialize(int); +} +#endif // MXNET_LIB_API_H_ diff --git a/include/mxnet/mxnet_acc.h b/include/mxnet/mxnet_acc.h deleted file mode 100644 index 30648d648c44..000000000000 --- a/include/mxnet/mxnet_acc.h +++ /dev/null @@ -1,122 +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. - */ - -/*! - * Copyright (c) 2015 by Contributors - * \file mxnet_acc.h - * \brief Accelerator APIs to interact with accelerator libraries - */ -#ifndef MXNET_MXNET_ACC_H_ -#define MXNET_MXNET_ACC_H_ - -#include -#include "../dlpack/dlpack.h" - -#define GETACCNAME_STR "getAccName" -typedef void (*getAccName_t)(char*); - -extern "C" { - /* - Function: getAccName - Parameters: - - char* : short accelerator name given by acc library - Returns: - */ - void getAccName(char*); - - /* - Function: getNumAcc - Parameters: - Returns: Number of accelerators in the system - */ - int getNumAcc(); - - /* - Function: initialize - Parameters: - - int : MXNet version passed to the acc library - Returns: Success/Failure code - Failure code if library cannot be used with given MXNet version - */ - int initialize(int); - - /* - Function: supportedOps - Parameters: - - const char* : Graph json - - const char*[] : Data names - - const DLTensor* : Corresponding data - - const int : Number of data elements - - int* : Node/Operator IDs supported by acclerator - Returns: - */ - void supportedOps(const char*, const char*[], const DLTensor*, - const int, int*); - - /* - Function: loadModel - Parameters: - - const char* : Model ID assigned to subgraph - - const char* : Graph json - - const char*[] : Data names - - const DLTensor* : Corresponding data - - const int : Number of data elements - - const int : Accelerator ID in the system - Returns: Success/Failure code - */ - int loadModel(const char*, const char*, const char*[], - const DLTensor*, const int, const int); - - /* - Function: unloadModel - Parameters: - - const char* : Model ID assigned to subgraph - Returns: - */ - void unloadModel(const char*); - - /* - Function: infer - Parameters: - - const char* : Model ID assigned to subgraph - - const char*[] : Input data names - - const char*[] : Output data names - - const DLTensor* : Corresponding Input data - - DLTensor* : Output data given by accelerator - - const int : Number of input data elements - - const int : Number of output data elements - Returns: Success/Failure code - */ - int infer(const char*, const char*[], const char*[], - const DLTensor*, DLTensor*, const int, const int); - - /* - Function: configure - Parameters: - - const char*[] : Input keys - - const char*[] : Input values - - const int : Number of input pairs - - char*[] : Output keys - - char*[] : Output values - - int* : Number of output pairs - */ - int configure(const char*[], const char*[], const int, - char*[], char*[], int*); -} -#endif // MXNET_MXNET_ACC_H_ diff --git a/python/mxnet/__init__.py b/python/mxnet/__init__.py index ab4bffde28a9..233bb2a1f57e 100644 --- a/python/mxnet/__init__.py +++ b/python/mxnet/__init__.py @@ -26,6 +26,7 @@ from .base import MXNetError from .util import is_np_shape, set_np_shape, np_shape, use_np_shape from . import base +from . import library from . import contrib from . import ndarray from . import ndarray as nd diff --git a/python/mxnet/context.py b/python/mxnet/context.py index 36ba8131f2ab..f284e00127b4 100644 --- a/python/mxnet/context.py +++ b/python/mxnet/context.py @@ -21,7 +21,6 @@ import threading import warnings import ctypes -import os from .base import classproperty, with_metaclass, _MXClassPropertyMetaClass from .base import _LIB from .base import check_call @@ -72,7 +71,6 @@ class Context(with_metaclass(_MXClassPropertyMetaClass, object)): _default_ctx = threading.local() devtype2str = {1: 'cpu', 2: 'gpu', 3: 'cpu_pinned', 5: 'cpu_shared'} devstr2type = {'cpu': 1, 'gpu': 2, 'cpu_pinned': 3, 'cpu_shared': 5} - acc_map = {} def __init__(self, device_type, device_id=0): if isinstance(device_type, Context): self.device_typeid = device_type.device_typeid @@ -169,42 +167,6 @@ def empty_cache(self): Context._default_ctx.value = Context('cpu', 0) -def load_acc(path): - """Loads accelerator library and returns corresponding context. - - Parameters - ---------- - path : Path to accelerator library .so file - - Returns - ------- - context : Context - """ - #check if path exists - if not os.path.exists(path): - print('load_acc path "%s" does NOT exist' % path) - return None - #check if path is to a file - if not os.path.isfile(path): - print('load_acc path "%s" is NOT a library file' % path) - return None - - byt_obj = path.encode('utf-8') - chararr = ctypes.c_char_p(byt_obj) - dev_id = ctypes.c_int() - name = ctypes.create_string_buffer(100) - - check_call(_LIB.MXLoadAccLib(chararr, ctypes.byref(dev_id), name)) - - dev_id = dev_id.value - name = name.value - Context.devtype2str[dev_id] = name - Context.devstr2type[name] = dev_id - Context.acc_map[dev_id] = (name, path) - - return Context(name, 0) - - def cpu(device_id=0): """Returns a CPU context. diff --git a/python/mxnet/library.py b/python/mxnet/library.py new file mode 100644 index 000000000000..4d9863b4ef68 --- /dev/null +++ b/python/mxnet/library.py @@ -0,0 +1,51 @@ +# 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 +"""Library management API of mxnet.""" +from __future__ import absolute_import +import ctypes +import os +from .base import _LIB +from .base import check_call + +def load_lib(path): + """Loads library dynamically. + + Parameters + --------- + path : Path to library .so file + + Returns + --------- + void + """ + #check if path exists + if not os.path.exists(path): + print('load_lib path "%s" does NOT exist' % path) + return None + #check if path is to a file + if not os.path.isfile(path): + print('load_lib path "%s" is NOT a library file' % path) + return None + + byt_obj = path.encode('utf-8') + chararr = ctypes.c_char_p(byt_obj) + check_call(_LIB.MXLoadLib(chararr)) + + return + diff --git a/src/c_api/c_api.cc b/src/c_api/c_api.cc index 5680835a82ea..02ccb226dd54 100644 --- a/src/c_api/c_api.cc +++ b/src/c_api/c_api.cc @@ -45,6 +45,8 @@ #include "mxnet/storage.h" #include "mxnet/libinfo.h" #include "mxnet/imperative.h" +#include "mxnet/library.h" +#include "mxnet/lib_api.h" #include "./c_api_common.h" #include "../operator/custom/custom-inl.h" #include "../operator/tensor/matrix_op-inl.h" @@ -87,13 +89,20 @@ inline int MXAPIGetFunctionRegInfo(const FunRegType *e, *arg_descriptions = dmlc::BeginPtr(ret->ret_vec_charp) + (e->arguments.size() * 2); API_END(); } + // NOTE: return value is added in API_END -int MXLoadAccLib(const char *path, int *id, char *name) { +int MXLoadLib(const char *path) { API_BEGIN(); - std::string tmp(path); - int dev_id = mxnet::Context::LoadAcc(tmp, name); - *id = dev_id; + void *lib = load_lib(path); + if(!lib) + LOG(FATAL) << "Unable to load library"; + + initialize_t initialize = get_func(lib, const_cast(INITIALIZE_STR)); + int version = MXNET_VERSION; + int flag = initialize(version); + if (!flag) + LOG(FATAL) << "Library failed to initialize"; API_END(); } From 3e93d81e8d2e67f943fdf9de0f44499c4f4ec795 Mon Sep 17 00:00:00 2001 From: mseth10 Date: Tue, 23 Jul 2019 19:15:46 +0000 Subject: [PATCH 10/38] addressing review comments --- example/lib_api/mylib.cc | 2 +- example/lib_api/test.py | 2 +- include/mxnet/lib_api.h | 4 ++-- include/mxnet/library.h | 12 ++++++++++++ python/mxnet/library.py | 11 ++++++----- src/c_api/c_api.cc | 7 +++---- src/common/library.cc | 20 ++++++++++++++++---- 7 files changed, 41 insertions(+), 17 deletions(-) diff --git a/example/lib_api/mylib.cc b/example/lib_api/mylib.cc index df6f705b0ffd..c6096f6a4f80 100644 --- a/example/lib_api/mylib.cc +++ b/example/lib_api/mylib.cc @@ -19,7 +19,7 @@ /*! * Copyright (c) 2015 by Contributors - * \file my_accel.cc + * \file mylib.cc * \brief Sample library functions */ diff --git a/example/lib_api/test.py b/example/lib_api/test.py index 0ad55f027ad6..6d19030f1e39 100644 --- a/example/lib_api/test.py +++ b/example/lib_api/test.py @@ -20,4 +20,4 @@ import mxnet as mx -mx.library.load_lib('mylib.so') +mx.library.load('mylib.so') diff --git a/include/mxnet/lib_api.h b/include/mxnet/lib_api.h index 5f549a290262..456f23d94e66 100644 --- a/include/mxnet/lib_api.h +++ b/include/mxnet/lib_api.h @@ -36,8 +36,8 @@ extern "C" { Function: initialize Parameters: - int : MXNet version passed to library - Returns: Success/Failure code - Failure code if library cannot be used with passed MXNet version + Returns: + - int : Non-zero value on error i.e. library incompatible with passed MXNet version */ int initialize(int); } diff --git a/include/mxnet/library.h b/include/mxnet/library.h index e7d2ecf2771b..e07156c8a9c2 100644 --- a/include/mxnet/library.h +++ b/include/mxnet/library.h @@ -32,6 +32,18 @@ void* load_lib(const char* path); void get_sym(void* handle, void** func, char* name); +/* +get_func - a templated function that fetches from the library +a function pointer of any given datatype and name + +Template parameter +- T : data type of function pointer +Input parameter +- lib : library handle +- func_name : function name to search for in the library +Returns +- func : function pointer +*/ template T get_func(void *lib, char *func_name) { T func; diff --git a/python/mxnet/library.py b/python/mxnet/library.py index 4d9863b4ef68..1e4f708eb405 100644 --- a/python/mxnet/library.py +++ b/python/mxnet/library.py @@ -23,7 +23,7 @@ from .base import _LIB from .base import check_call -def load_lib(path): +def load(path): """Loads library dynamically. Parameters @@ -36,11 +36,12 @@ def load_lib(path): """ #check if path exists if not os.path.exists(path): - print('load_lib path "%s" does NOT exist' % path) + print('load path "%s" does NOT exist' % path) return None - #check if path is to a file - if not os.path.isfile(path): - print('load_lib path "%s" is NOT a library file' % path) + #check if path is to a library file + _, file_ext = os.path.splitext(path) + if not file_ext in ['.so', '.dll']: + print('load path "%s" is NOT a library file' % path) return None byt_obj = path.encode('utf-8') diff --git a/src/c_api/c_api.cc b/src/c_api/c_api.cc index 02ccb226dd54..e5bddd025863 100644 --- a/src/c_api/c_api.cc +++ b/src/c_api/c_api.cc @@ -92,16 +92,15 @@ inline int MXAPIGetFunctionRegInfo(const FunRegType *e, // NOTE: return value is added in API_END +// Loads library and initializes it int MXLoadLib(const char *path) { API_BEGIN(); void *lib = load_lib(path); - if(!lib) + if (!lib) LOG(FATAL) << "Unable to load library"; initialize_t initialize = get_func(lib, const_cast(INITIALIZE_STR)); - int version = MXNET_VERSION; - int flag = initialize(version); - if (!flag) + if (!initialize(int(MXNET_VERSION))) LOG(FATAL) << "Library failed to initialize"; API_END(); } diff --git a/src/common/library.cc b/src/common/library.cc index edfe50658391..2b444b3e8d41 100644 --- a/src/common/library.cc +++ b/src/common/library.cc @@ -26,22 +26,34 @@ #include "../../include/mxnet/library.h" +/* +Loads the dynamic shared library file +Parameter: Library file location +Returns: handle for the loaded library, NULL if loading unsuccessful +*/ void* load_lib(const char* path) { void *handle; handle = dlopen(path, RTLD_LAZY); if (!handle) { - std::cerr << "Error loading accelerator library: '" << path - << "'\n" << dlerror() << std::endl; + LOG(FATAL) << "Error loading accelerator library: '" << path + << "'\n" << dlerror(); return nullptr; } return handle; } +/* +Obtains address of given function in the loaded library +Parameters +- handle: handle for the loaded library +- func: function pointer that gets output address +- name: function name to be fetched +*/ void get_sym(void* handle, void** func, char* name) { *func = dlsym(handle, name); if (!(*func)) { - std::cerr << "Error getting function '" << name - << "' from accelerator library\n" << dlerror() << std::endl; + LOG(FATAL) << "Error getting function '" << name + << "' from accelerator library\n" << dlerror(); } } From 35913dab6bf110a1abad176eaae3094edd758098 Mon Sep 17 00:00:00 2001 From: mseth10 Date: Tue, 23 Jul 2019 19:33:46 +0000 Subject: [PATCH 11/38] using static cast --- src/c_api/c_api.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/c_api/c_api.cc b/src/c_api/c_api.cc index e5bddd025863..c876c90b4808 100644 --- a/src/c_api/c_api.cc +++ b/src/c_api/c_api.cc @@ -100,7 +100,7 @@ int MXLoadLib(const char *path) { LOG(FATAL) << "Unable to load library"; initialize_t initialize = get_func(lib, const_cast(INITIALIZE_STR)); - if (!initialize(int(MXNET_VERSION))) + if (!initialize(static_cast(MXNET_VERSION))) LOG(FATAL) << "Library failed to initialize"; API_END(); } From 87fa3cf1e380f810cea3cfa379439e31219f2282 Mon Sep 17 00:00:00 2001 From: mseth10 Date: Tue, 23 Jul 2019 20:42:26 +0000 Subject: [PATCH 12/38] pylint fix --- python/mxnet/library.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/python/mxnet/library.py b/python/mxnet/library.py index 1e4f708eb405..db648c9fac89 100644 --- a/python/mxnet/library.py +++ b/python/mxnet/library.py @@ -37,16 +37,15 @@ def load(path): #check if path exists if not os.path.exists(path): print('load path "%s" does NOT exist' % path) - return None + return #check if path is to a library file _, file_ext = os.path.splitext(path) if not file_ext in ['.so', '.dll']: print('load path "%s" is NOT a library file' % path) - return None + return byt_obj = path.encode('utf-8') chararr = ctypes.c_char_p(byt_obj) check_call(_LIB.MXLoadLib(chararr)) return - From 0dad266595f2f960667c2998d55819ccabb6e351 Mon Sep 17 00:00:00 2001 From: mseth10 Date: Tue, 23 Jul 2019 22:26:01 +0000 Subject: [PATCH 13/38] moving library.h file to src/common/ --- src/c_api/c_api.cc | 2 +- {include/mxnet => src/common}/library.h | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename {include/mxnet => src/common}/library.h (100%) diff --git a/src/c_api/c_api.cc b/src/c_api/c_api.cc index c876c90b4808..042d638aae85 100644 --- a/src/c_api/c_api.cc +++ b/src/c_api/c_api.cc @@ -45,13 +45,13 @@ #include "mxnet/storage.h" #include "mxnet/libinfo.h" #include "mxnet/imperative.h" -#include "mxnet/library.h" #include "mxnet/lib_api.h" #include "./c_api_common.h" #include "../operator/custom/custom-inl.h" #include "../operator/tensor/matrix_op-inl.h" #include "../operator/tvmop/op_module.h" #include "../common/utils.h" +#include "../common/library.h" using namespace mxnet; diff --git a/include/mxnet/library.h b/src/common/library.h similarity index 100% rename from include/mxnet/library.h rename to src/common/library.h From 16afd9644f11d7b952c765d8cb8415f89186a8f2 Mon Sep 17 00:00:00 2001 From: mseth10 Date: Tue, 23 Jul 2019 22:27:04 +0000 Subject: [PATCH 14/38] adding dynamic loading support for windows --- src/common/library.cc | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/common/library.cc b/src/common/library.cc index 2b444b3e8d41..275b4058166c 100644 --- a/src/common/library.cc +++ b/src/common/library.cc @@ -24,7 +24,13 @@ * and accessing its functions */ -#include "../../include/mxnet/library.h" +#if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) +#include +#include +#endif + +#include "library.h" + /* Loads the dynamic shared library file @@ -33,11 +39,14 @@ Returns: handle for the loaded library, NULL if loading unsuccessful */ void* load_lib(const char* path) { void *handle; +#if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) + handle = LoadLibrary(path); +#else handle = dlopen(path, RTLD_LAZY); +#endif // _WIN32 or _WIN64 or __WINDOWS__ if (!handle) { - LOG(FATAL) << "Error loading accelerator library: '" << path - << "'\n" << dlerror(); + LOG(FATAL) << "Error loading accelerator library: '" << path << "'"; return nullptr; } return handle; @@ -51,9 +60,14 @@ Parameters - name: function name to be fetched */ void get_sym(void* handle, void** func, char* name) { +#if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) + *func = GetProcAddress(handle, name); + FreeLibrary(hinstLib); +#else *func = dlsym(handle, name); +#endif // _WIN32 or _WIN64 or __WINDOWS__ + if (!(*func)) { - LOG(FATAL) << "Error getting function '" << name - << "' from accelerator library\n" << dlerror(); + LOG(FATAL) << "Error getting function '" << name << "' from accelerator library"; } } From f265d0420d6903df4e8988a95f4e3742986f5020 Mon Sep 17 00:00:00 2001 From: mseth10 Date: Tue, 23 Jul 2019 22:48:15 +0000 Subject: [PATCH 15/38] updating header guard --- src/common/library.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/library.h b/src/common/library.h index e07156c8a9c2..086f386d5c15 100644 --- a/src/common/library.h +++ b/src/common/library.h @@ -22,8 +22,8 @@ * \file library.h * \brief Defining accelerator loading functions */ -#ifndef MXNET_LIBRARY_H_ -#define MXNET_LIBRARY_H_ +#ifndef MXNET_COMMON_LIBRARY_H_ +#define MXNET_COMMON_LIBRARY_H_ #include #include @@ -53,4 +53,4 @@ T get_func(void *lib, char *func_name) { return func; } -#endif // MXNET_LIBRARY_H_ +#endif // MXNET_COMMON_LIBRARY_H_ From 955cf988ef11ed00e5ef32a37b298c2ca6c5220f Mon Sep 17 00:00:00 2001 From: mseth10 Date: Tue, 23 Jul 2019 23:11:59 +0000 Subject: [PATCH 16/38] fixing headers --- include/mxnet/lib_api.h | 1 - src/common/library.cc | 3 ++- src/common/library.h | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/include/mxnet/lib_api.h b/include/mxnet/lib_api.h index 456f23d94e66..4af899371fa5 100644 --- a/include/mxnet/lib_api.h +++ b/include/mxnet/lib_api.h @@ -26,7 +26,6 @@ #define MXNET_LIB_API_H_ #include -#include "../dlpack/dlpack.h" #define INITIALIZE_STR "initialize" typedef int (*initialize_t)(int); diff --git a/src/common/library.cc b/src/common/library.cc index 275b4058166c..d4854060c480 100644 --- a/src/common/library.cc +++ b/src/common/library.cc @@ -26,7 +26,8 @@ #if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) #include -#include +#else +#include #endif #include "library.h" diff --git a/src/common/library.h b/src/common/library.h index 086f386d5c15..24165e249bcf 100644 --- a/src/common/library.h +++ b/src/common/library.h @@ -25,7 +25,6 @@ #ifndef MXNET_COMMON_LIBRARY_H_ #define MXNET_COMMON_LIBRARY_H_ -#include #include #include "dmlc/io.h" From 7d3d53063bc38e1e0466b0b32f7a86a298fcbc0e Mon Sep 17 00:00:00 2001 From: mseth10 Date: Tue, 23 Jul 2019 23:20:13 +0000 Subject: [PATCH 17/38] fixing windows casting error --- src/common/library.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/common/library.cc b/src/common/library.cc index d4854060c480..202b9c6974b5 100644 --- a/src/common/library.cc +++ b/src/common/library.cc @@ -62,8 +62,7 @@ Parameters */ void get_sym(void* handle, void** func, char* name) { #if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) - *func = GetProcAddress(handle, name); - FreeLibrary(hinstLib); + *func = GetProcAddress((HMODULE)handle, name); #else *func = dlsym(handle, name); #endif // _WIN32 or _WIN64 or __WINDOWS__ From 3e846c4d95712201433370e064847d4abecbe6d8 Mon Sep 17 00:00:00 2001 From: mseth10 Date: Wed, 24 Jul 2019 23:58:47 +0000 Subject: [PATCH 18/38] declaring library functions for windows --- include/mxnet/lib_api.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/mxnet/lib_api.h b/include/mxnet/lib_api.h index 4af899371fa5..f90b2ef8526d 100644 --- a/include/mxnet/lib_api.h +++ b/include/mxnet/lib_api.h @@ -38,6 +38,10 @@ extern "C" { Returns: - int : Non-zero value on error i.e. library incompatible with passed MXNet version */ +#if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) + __declspec(dllexport) int __cdecl initialize(int); +#else int initialize(int); +#endif } #endif // MXNET_LIB_API_H_ From bc4cbd2faeb76a4261f84fd41ee62e59bd910a4c Mon Sep 17 00:00:00 2001 From: mseth10 Date: Thu, 25 Jul 2019 00:02:12 +0000 Subject: [PATCH 19/38] adding library testing module in examples --- example/lib_api/Makefile | 11 +++++- example/lib_api/libtest.cc | 77 ++++++++++++++++++++++++++++++++++++++ example/lib_api/mylib.cc | 4 +- example/lib_api/test.py | 6 ++- 4 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 example/lib_api/libtest.cc diff --git a/example/lib_api/Makefile b/example/lib_api/Makefile index 4e27857a7e1d..e5893c8065c4 100644 --- a/example/lib_api/Makefile +++ b/example/lib_api/Makefile @@ -18,5 +18,14 @@ all: g++ -shared -fPIC mylib.cc -o mylib.so -I ../../include/mxnet +test: + g++ -std=c++11 -O3 -o libtest libtest.cc -ldl -I ../../include/mxnet + +windows: + cl /LD mylib.cc + +win_test: + cl libtest.cc + clean: - rm -rf mylib.so + rm -rf mylib.so libtest diff --git a/example/lib_api/libtest.cc b/example/lib_api/libtest.cc new file mode 100644 index 000000000000..4f90b53225e3 --- /dev/null +++ b/example/lib_api/libtest.cc @@ -0,0 +1,77 @@ +/* + * 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) 2015 by Contributors + * \file libtest.cc + * \brief Tests if the library is implemented correctly + */ + +#if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) +#include +#else +#include +#endif + +#include +#include "../../include/mxnet/lib_api.h" + +#define MXNET_VERSION 10500 + +int main(void) { + // Get a handle to the library. +#if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) + HINSTANCE handle; + handle = LoadLibrary(TEXT("lib.dll")); +#else + void *handle; + handle = dlopen("mylib.so", RTLD_LAZY); +#endif + + // If the handle is valid, try to get the function address. + if (!handle) { + printf("Unable to load library\n"); + return 1; + } + + initialize_t func; +#if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) + func = (initialize_t) GetProcAddress(handle, INITIALIZE_STR); +#else + func = (initialize_t) dlsym(handle, INITIALIZE_STR); +#endif + + // If the function address is valid, call the function. + if (!func) { + printf("Unable to get function 'intialize' from library\n"); + return 1; + } + + // Call the function. + (func)(MXNET_VERSION); + + // Deallocate memory. +#if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) + FreeLibrary(handle); +#else + dlclose(handle); +#endif + + return 0; +} diff --git a/example/lib_api/mylib.cc b/example/lib_api/mylib.cc index c6096f6a4f80..e67560a87f3d 100644 --- a/example/lib_api/mylib.cc +++ b/example/lib_api/mylib.cc @@ -20,7 +20,7 @@ /*! * Copyright (c) 2015 by Contributors * \file mylib.cc - * \brief Sample library functions + * \brief Sample library file */ #include @@ -33,5 +33,5 @@ int initialize(int version) { } else { std::cout << "MXNet version " << version << " not supported" << std::endl; return 0; - } + } } diff --git a/example/lib_api/test.py b/example/lib_api/test.py index 6d19030f1e39..4780233f1c71 100644 --- a/example/lib_api/test.py +++ b/example/lib_api/test.py @@ -19,5 +19,9 @@ # pylint: disable=arguments-differ import mxnet as mx +import os -mx.library.load('mylib.so') +if (os.name=='posix'): + mx.library.load('mylib.so') +elif (os.name=='nt'): + mx.library.load('mylib.dll') From 53e71df342872aae4028debd57939436117d34a8 Mon Sep 17 00:00:00 2001 From: mseth10 Date: Thu, 25 Jul 2019 00:05:04 +0000 Subject: [PATCH 20/38] adding unit test to test library loading --- tests/python/unittest/test_library_loading.py | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 tests/python/unittest/test_library_loading.py diff --git a/tests/python/unittest/test_library_loading.py b/tests/python/unittest/test_library_loading.py new file mode 100644 index 000000000000..5aa9c24341c1 --- /dev/null +++ b/tests/python/unittest/test_library_loading.py @@ -0,0 +1,29 @@ +# 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 os +from mxnet.test_utils import download + +def test_library_loading(): + if (os.name=='posix'): + lib = 'mylib.so' + elif (os.name=='nt'): + lib = 'mylib.dll' + + fname = mx.test_utils.download('https://mxnet-demo-models.s3.amazonaws.com/lib_binary/'+lib) + mx.library.load(fname) From db840090bf33a8984f63272bc9abdb4428bb57b1 Mon Sep 17 00:00:00 2001 From: mseth10 Date: Thu, 25 Jul 2019 17:10:19 +0000 Subject: [PATCH 21/38] correcting file names --- example/lib_api/libtest.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/lib_api/libtest.cc b/example/lib_api/libtest.cc index 4f90b53225e3..f8bc18dc0e40 100644 --- a/example/lib_api/libtest.cc +++ b/example/lib_api/libtest.cc @@ -30,7 +30,7 @@ #endif #include -#include "../../include/mxnet/lib_api.h" +#include "lib_api.h" #define MXNET_VERSION 10500 @@ -38,7 +38,7 @@ int main(void) { // Get a handle to the library. #if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) HINSTANCE handle; - handle = LoadLibrary(TEXT("lib.dll")); + handle = LoadLibrary(TEXT("mylib.dll")); #else void *handle; handle = dlopen("mylib.so", RTLD_LAZY); From 25a9ccbca1bd7f42ecab6ee8a3e1e2f66c2e9c31 Mon Sep 17 00:00:00 2001 From: mseth10 Date: Thu, 25 Jul 2019 20:26:54 +0000 Subject: [PATCH 22/38] updating error messages --- src/common/library.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/library.cc b/src/common/library.cc index 202b9c6974b5..e472010142e1 100644 --- a/src/common/library.cc +++ b/src/common/library.cc @@ -47,7 +47,7 @@ void* load_lib(const char* path) { #endif // _WIN32 or _WIN64 or __WINDOWS__ if (!handle) { - LOG(FATAL) << "Error loading accelerator library: '" << path << "'"; + LOG(FATAL) << "Error loading library: '" << path << "'"; return nullptr; } return handle; @@ -68,6 +68,6 @@ void get_sym(void* handle, void** func, char* name) { #endif // _WIN32 or _WIN64 or __WINDOWS__ if (!(*func)) { - LOG(FATAL) << "Error getting function '" << name << "' from accelerator library"; + LOG(FATAL) << "Error getting function '" << name << "' from library"; } } From 1682af3e5929f05a25aa5311f376065a873758fd Mon Sep 17 00:00:00 2001 From: mseth10 Date: Thu, 25 Jul 2019 21:07:35 +0000 Subject: [PATCH 23/38] getting error message from DL library --- src/common/library.cc | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/common/library.cc b/src/common/library.cc index e472010142e1..bcadca1678a6 100644 --- a/src/common/library.cc +++ b/src/common/library.cc @@ -42,14 +42,30 @@ void* load_lib(const char* path) { void *handle; #if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) handle = LoadLibrary(path); + if (!handle) { + char *lpMsgBuf; + unsigned long dw = GetLastError(); + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + dw, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + &lpMsgBuf, + 0, NULL ); + LOG(FATAL) << "Error loading library: '" << path << "'\n" << lpMsgBuf; + LocalFree(lpMsgBuf); + return nullptr; + } #else handle = dlopen(path, RTLD_LAZY); -#endif // _WIN32 or _WIN64 or __WINDOWS__ - if (!handle) { - LOG(FATAL) << "Error loading library: '" << path << "'"; + LOG(FATAL) << "Error loading library: '" << path << "'\n" << dlerror(); return nullptr; } +#endif // _WIN32 or _WIN64 or __WINDOWS__ + return handle; } From 7551313e815e6b7826945847c39e5c0000b0f150 Mon Sep 17 00:00:00 2001 From: mseth10 Date: Thu, 25 Jul 2019 21:08:55 +0000 Subject: [PATCH 24/38] adding unit test to gpu suite --- tests/python/gpu/test_operator_gpu.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/python/gpu/test_operator_gpu.py b/tests/python/gpu/test_operator_gpu.py index 91ba9fb68750..a8aa1ff853f7 100644 --- a/tests/python/gpu/test_operator_gpu.py +++ b/tests/python/gpu/test_operator_gpu.py @@ -45,6 +45,7 @@ from test_subgraph_op import * from test_contrib_operator import test_multibox_target_op from test_tvm_op import * +from test_library_loading import * set_default_context(mx.gpu(0)) del test_support_vector_machine_l1_svm # noqa From 68a4e6cd1f88e40ed6bc7a930c679f79fa9fe602 Mon Sep 17 00:00:00 2001 From: mseth10 Date: Thu, 25 Jul 2019 21:28:32 +0000 Subject: [PATCH 25/38] correcting windows pointer --- src/common/library.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/library.cc b/src/common/library.cc index bcadca1678a6..2d23491a5650 100644 --- a/src/common/library.cc +++ b/src/common/library.cc @@ -52,7 +52,7 @@ void* load_lib(const char* path) { NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - &lpMsgBuf, + lpMsgBuf, 0, NULL ); LOG(FATAL) << "Error loading library: '" << path << "'\n" << lpMsgBuf; LocalFree(lpMsgBuf); From e8c8d2fc13f3b9846b4fd64c98737691985850a4 Mon Sep 17 00:00:00 2001 From: mseth10 Date: Fri, 26 Jul 2019 01:40:05 +0000 Subject: [PATCH 26/38] requiring absolute path to library --- python/mxnet/library.py | 4 ++++ src/common/library.cc | 9 +++++---- tests/python/unittest/test_library_loading.py | 1 + 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/python/mxnet/library.py b/python/mxnet/library.py index db648c9fac89..758223294e98 100644 --- a/python/mxnet/library.py +++ b/python/mxnet/library.py @@ -38,6 +38,10 @@ def load(path): if not os.path.exists(path): print('load path "%s" does NOT exist' % path) return + #check if path is an absolute path + if not os.path.isabs(path): + print('load path "%s" is not an absolute path' % path) + return #check if path is to a library file _, file_ext = os.path.splitext(path) if not file_ext in ['.so', '.dll']: diff --git a/src/common/library.cc b/src/common/library.cc index 2d23491a5650..7d74e7fb1e95 100644 --- a/src/common/library.cc +++ b/src/common/library.cc @@ -43,17 +43,18 @@ void* load_lib(const char* path) { #if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) handle = LoadLibrary(path); if (!handle) { + // Retrieve the system error message for the last-error code char *lpMsgBuf; - unsigned long dw = GetLastError(); + uint32_t dw = GetLastError(); FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - lpMsgBuf, - 0, NULL ); + reinterpret_cast(&lpMsgBuf), + 0, NULL); LOG(FATAL) << "Error loading library: '" << path << "'\n" << lpMsgBuf; LocalFree(lpMsgBuf); return nullptr; diff --git a/tests/python/unittest/test_library_loading.py b/tests/python/unittest/test_library_loading.py index 5aa9c24341c1..9eae0e19bcbe 100644 --- a/tests/python/unittest/test_library_loading.py +++ b/tests/python/unittest/test_library_loading.py @@ -26,4 +26,5 @@ def test_library_loading(): lib = 'mylib.dll' fname = mx.test_utils.download('https://mxnet-demo-models.s3.amazonaws.com/lib_binary/'+lib) + fname = os.path.abspath(fname) mx.library.load(fname) From 71ac9372292aedeaf10afbdfa455666045ef3c6f Mon Sep 17 00:00:00 2001 From: mseth10 Date: Fri, 26 Jul 2019 16:28:57 +0000 Subject: [PATCH 27/38] changing file description --- src/common/library.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/library.h b/src/common/library.h index 24165e249bcf..cdfb53c2398c 100644 --- a/src/common/library.h +++ b/src/common/library.h @@ -20,7 +20,7 @@ /*! * Copyright (c) 2015 by Contributors * \file library.h - * \brief Defining accelerator loading functions + * \brief Defining library loading functions */ #ifndef MXNET_COMMON_LIBRARY_H_ #define MXNET_COMMON_LIBRARY_H_ From 4cb4caf9c1ef6fb83c1c92f9bfec92b03b448d1a Mon Sep 17 00:00:00 2001 From: mseth10 Date: Tue, 30 Jul 2019 00:17:49 +0000 Subject: [PATCH 28/38] addressing review comments - adding more docs, windows error msg --- example/lib_api/libtest.cc | 7 ++- example/lib_api/test.py | 2 + include/mxnet/lib_api.h | 14 ++--- python/mxnet/base.py | 2 +- python/mxnet/library.py | 16 ++--- src/common/library.cc | 62 ++++++++++++------- src/common/library.h | 20 +++--- tests/python/unittest/test_library_loading.py | 2 + 8 files changed, 67 insertions(+), 58 deletions(-) diff --git a/example/lib_api/libtest.cc b/example/lib_api/libtest.cc index f8bc18dc0e40..69a1a884cc0c 100644 --- a/example/lib_api/libtest.cc +++ b/example/lib_api/libtest.cc @@ -20,7 +20,9 @@ /*! * Copyright (c) 2015 by Contributors * \file libtest.cc - * \brief Tests if the library is implemented correctly + * \brief This test checks if the library is implemented correctly + * and does not involve dynamic loading of library into MXNet + * This test is supposed to be run before test.py */ #if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) @@ -44,12 +46,12 @@ int main(void) { handle = dlopen("mylib.so", RTLD_LAZY); #endif - // If the handle is valid, try to get the function address. if (!handle) { printf("Unable to load library\n"); return 1; } + // get initialize function address from the library initialize_t func; #if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) func = (initialize_t) GetProcAddress(handle, INITIALIZE_STR); @@ -57,7 +59,6 @@ int main(void) { func = (initialize_t) dlsym(handle, INITIALIZE_STR); #endif - // If the function address is valid, call the function. if (!func) { printf("Unable to get function 'intialize' from library\n"); return 1; diff --git a/example/lib_api/test.py b/example/lib_api/test.py index 4780233f1c71..abb9d5b13fdb 100644 --- a/example/lib_api/test.py +++ b/example/lib_api/test.py @@ -18,6 +18,8 @@ # coding: utf-8 # pylint: disable=arguments-differ +# This test checks if dynamic loading of library into MXNet is successful + import mxnet as mx import os diff --git a/include/mxnet/lib_api.h b/include/mxnet/lib_api.h index f90b2ef8526d..3673d8d67dde 100644 --- a/include/mxnet/lib_api.h +++ b/include/mxnet/lib_api.h @@ -31,13 +31,13 @@ typedef int (*initialize_t)(int); extern "C" { - /* - Function: initialize - Parameters: - - int : MXNet version passed to library - Returns: - - int : Non-zero value on error i.e. library incompatible with passed MXNet version - */ + /*! + * \brief Checks if the MXNet version is supported by the library. + * If supported, initializes the library. + * \param version MXNet version number passed to library and defined as: + * MXNET_VERSION = (MXNET_MAJOR*10000 + MXNET_MINOR*100 + MXNET_PATCH) + * \return Non-zero value on error i.e. library incompatible with passed MXNet version + */ #if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) __declspec(dllexport) int __cdecl initialize(int); #else diff --git a/python/mxnet/base.py b/python/mxnet/base.py index bf8026359d02..17819bde28b2 100644 --- a/python/mxnet/base.py +++ b/python/mxnet/base.py @@ -86,7 +86,7 @@ def __repr__(self): class MXNetError(Exception): - """Error that will be throwed by all mxnet functions.""" + """Error that will be thrown by all mxnet functions.""" pass diff --git a/python/mxnet/library.py b/python/mxnet/library.py index 758223294e98..9ebf2c2bc580 100644 --- a/python/mxnet/library.py +++ b/python/mxnet/library.py @@ -20,15 +20,14 @@ from __future__ import absolute_import import ctypes import os -from .base import _LIB -from .base import check_call +from .base import _LIB, check_call, MXNetError def load(path): """Loads library dynamically. Parameters --------- - path : Path to library .so file + path : Path to library .so/.dll file Returns --------- @@ -36,20 +35,15 @@ def load(path): """ #check if path exists if not os.path.exists(path): - print('load path "%s" does NOT exist' % path) - return + raise MXNetError("load path %s does NOT exist" % path) #check if path is an absolute path if not os.path.isabs(path): - print('load path "%s" is not an absolute path' % path) - return + raise MXNetError("load path %s is not an absolute path" % path) #check if path is to a library file _, file_ext = os.path.splitext(path) if not file_ext in ['.so', '.dll']: - print('load path "%s" is NOT a library file' % path) - return + raise MXNetError("load path %s is NOT a library file" % path) byt_obj = path.encode('utf-8') chararr = ctypes.c_char_p(byt_obj) check_call(_LIB.MXLoadLib(chararr)) - - return diff --git a/src/common/library.cc b/src/common/library.cc index 7d74e7fb1e95..af526adfd77e 100644 --- a/src/common/library.cc +++ b/src/common/library.cc @@ -33,28 +33,38 @@ #include "library.h" -/* -Loads the dynamic shared library file -Parameter: Library file location -Returns: handle for the loaded library, NULL if loading unsuccessful -*/ -void* load_lib(const char* path) { - void *handle; #if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) - handle = LoadLibrary(path); - if (!handle) { - // Retrieve the system error message for the last-error code - char *lpMsgBuf; - uint32_t dw = GetLastError(); - FormatMessage( +/*! + * \brief Retrieve the system error message for the last-error code + * \param err string that gets the error message + */ +void win_err(char **err) { + uint32_t dw = GetLastError(); + FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - reinterpret_cast(&lpMsgBuf), + reinterpret_cast(err), 0, NULL); +} +#endif + + +/*! + * \brief Loads the dynamic shared library file + * \param path library file location + * \return handle a pointer for the loaded library, nullptr if loading unsuccessful + */ +void* load_lib(const char* path) { + void *handle; +#if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) + handle = LoadLibrary(path); + if (!handle) { + char *lpMsgBuf; + win_err(&lpMsgBuf); LOG(FATAL) << "Error loading library: '" << path << "'\n" << lpMsgBuf; LocalFree(lpMsgBuf); return nullptr; @@ -70,21 +80,25 @@ void* load_lib(const char* path) { return handle; } -/* -Obtains address of given function in the loaded library -Parameters -- handle: handle for the loaded library -- func: function pointer that gets output address -- name: function name to be fetched -*/ +/*! + * \brief Obtains address of given function in the loaded library + * \param handle pointer for the loaded library + * \param func function pointer that gets output address + * \param name function name to be fetched + */ void get_sym(void* handle, void** func, char* name) { #if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) *func = GetProcAddress((HMODULE)handle, name); + if (!(*func)) { + char *lpMsgBuf; + win_err(&lpMsgBuf); + LOG(FATAL) << "Error getting function '" << name << "' from library\n" << lpMsgBuf; + LocalFree(lpMsgBuf); + } #else *func = dlsym(handle, name); -#endif // _WIN32 or _WIN64 or __WINDOWS__ - if (!(*func)) { - LOG(FATAL) << "Error getting function '" << name << "' from library"; + LOG(FATAL) << "Error getting function '" << name << "' from library\n" << dlerror(); } +#endif // _WIN32 or _WIN64 or __WINDOWS__ } diff --git a/src/common/library.h b/src/common/library.h index cdfb53c2398c..4656c16097fa 100644 --- a/src/common/library.h +++ b/src/common/library.h @@ -31,18 +31,14 @@ void* load_lib(const char* path); void get_sym(void* handle, void** func, char* name); -/* -get_func - a templated function that fetches from the library -a function pointer of any given datatype and name - -Template parameter -- T : data type of function pointer -Input parameter -- lib : library handle -- func_name : function name to search for in the library -Returns -- func : function pointer -*/ +/*! + * \brief a templated function that fetches from the library + * a function pointer of any given datatype and name + * \param T a template parameter for data type of function pointer + * \param lib library handle + * \param func_name function name to search for in the library + * \return func a function pointer + */ template T get_func(void *lib, char *func_name) { T func; diff --git a/tests/python/unittest/test_library_loading.py b/tests/python/unittest/test_library_loading.py index 9eae0e19bcbe..5d2717952039 100644 --- a/tests/python/unittest/test_library_loading.py +++ b/tests/python/unittest/test_library_loading.py @@ -15,6 +15,8 @@ # specific language governing permissions and limitations # under the License. +# This test checks if dynamic loading of library into MXNet is successful + import mxnet as mx import os from mxnet.test_utils import download From 4e2dba8eec44596e67ca6d4a79c733a2ef9fd90b Mon Sep 17 00:00:00 2001 From: mseth10 Date: Tue, 30 Jul 2019 22:28:56 +0000 Subject: [PATCH 29/38] addressing PR comments --- example/lib_api/libtest.cc | 16 ++++++++-------- example/lib_api/test.py | 2 ++ include/mxnet/lib_api.h | 9 ++++++--- src/c_api/c_api.cc | 2 +- src/common/library.cc | 18 +++++++++--------- 5 files changed, 26 insertions(+), 21 deletions(-) diff --git a/example/lib_api/libtest.cc b/example/lib_api/libtest.cc index 69a1a884cc0c..8bdf36c05d37 100644 --- a/example/lib_api/libtest.cc +++ b/example/lib_api/libtest.cc @@ -31,7 +31,7 @@ #include #endif -#include +#include #include "lib_api.h" #define MXNET_VERSION 10500 @@ -47,25 +47,25 @@ int main(void) { #endif if (!handle) { - printf("Unable to load library\n"); + std::cerr << "Unable to load library" << std::endl; return 1; } // get initialize function address from the library - initialize_t func; + initialize_t init_lib; #if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) - func = (initialize_t) GetProcAddress(handle, INITIALIZE_STR); + init_lib = (initialize_t) GetProcAddress(handle, MXLIB_INITIALIZE_STR); #else - func = (initialize_t) dlsym(handle, INITIALIZE_STR); + init_lib = (initialize_t) dlsym(handle, MXLIB_INITIALIZE_STR); #endif - if (!func) { - printf("Unable to get function 'intialize' from library\n"); + if (!init_lib) { + std::cerr << "Unable to get function 'intialize' from library" << std::endl; return 1; } // Call the function. - (func)(MXNET_VERSION); + (init_lib)(MXNET_VERSION); // Deallocate memory. #if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) diff --git a/example/lib_api/test.py b/example/lib_api/test.py index abb9d5b13fdb..d73d85c02ced 100644 --- a/example/lib_api/test.py +++ b/example/lib_api/test.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python3 + # 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 diff --git a/include/mxnet/lib_api.h b/include/mxnet/lib_api.h index 3673d8d67dde..ca3b2952eafa 100644 --- a/include/mxnet/lib_api.h +++ b/include/mxnet/lib_api.h @@ -25,9 +25,12 @@ #ifndef MXNET_LIB_API_H_ #define MXNET_LIB_API_H_ -#include - -#define INITIALIZE_STR "initialize" +/*! + * \brief Following are the APIs implemented in the external library + * Each API has a #define string that is used to lookup the function in the library + * Followed by the function declaration + */ +#define MXLIB_INITIALIZE_STR "initialize" typedef int (*initialize_t)(int); extern "C" { diff --git a/src/c_api/c_api.cc b/src/c_api/c_api.cc index 042d638aae85..5b23a8c694f6 100644 --- a/src/c_api/c_api.cc +++ b/src/c_api/c_api.cc @@ -99,7 +99,7 @@ int MXLoadLib(const char *path) { if (!lib) LOG(FATAL) << "Unable to load library"; - initialize_t initialize = get_func(lib, const_cast(INITIALIZE_STR)); + initialize_t initialize = get_func(lib, const_cast(MXLIB_INITIALIZE_STR)); if (!initialize(static_cast(MXNET_VERSION))) LOG(FATAL) << "Library failed to initialize"; API_END(); diff --git a/src/common/library.cc b/src/common/library.cc index af526adfd77e..fff69565a6b1 100644 --- a/src/common/library.cc +++ b/src/common/library.cc @@ -59,14 +59,14 @@ void win_err(char **err) { * \return handle a pointer for the loaded library, nullptr if loading unsuccessful */ void* load_lib(const char* path) { - void *handle; + void *handle = nullptr; #if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) handle = LoadLibrary(path); if (!handle) { - char *lpMsgBuf; - win_err(&lpMsgBuf); - LOG(FATAL) << "Error loading library: '" << path << "'\n" << lpMsgBuf; - LocalFree(lpMsgBuf); + char *err_msg = nullptr; + win_err(&err_msg); + LOG(FATAL) << "Error loading library: '" << path << "'\n" << err_msg; + LocalFree(err_msg); return nullptr; } #else @@ -90,10 +90,10 @@ void get_sym(void* handle, void** func, char* name) { #if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) *func = GetProcAddress((HMODULE)handle, name); if (!(*func)) { - char *lpMsgBuf; - win_err(&lpMsgBuf); - LOG(FATAL) << "Error getting function '" << name << "' from library\n" << lpMsgBuf; - LocalFree(lpMsgBuf); + char *err_msg = nullptr; + win_err(&err_msg); + LOG(FATAL) << "Error getting function '" << name << "' from library\n" << err_msg; + LocalFree(err_msg); } #else *func = dlsym(handle, name); From 7f8a9fb3521bccba1fa4700741d3f31c3d890aea Mon Sep 17 00:00:00 2001 From: mseth10 Date: Wed, 31 Jul 2019 21:20:41 +0000 Subject: [PATCH 30/38] checking machine type for unit test --- tests/python/unittest/test_library_loading.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/python/unittest/test_library_loading.py b/tests/python/unittest/test_library_loading.py index 5d2717952039..3d56d0c750a6 100644 --- a/tests/python/unittest/test_library_loading.py +++ b/tests/python/unittest/test_library_loading.py @@ -17,10 +17,16 @@ # This test checks if dynamic loading of library into MXNet is successful -import mxnet as mx import os +import platform +import unittest +import mxnet as mx from mxnet.test_utils import download +def check_platform(): + return platform.machine() not in ['x86_64', 'AMD64'] + +@unittest.skipIf(check_platform(), "not all machine types supported") def test_library_loading(): if (os.name=='posix'): lib = 'mylib.so' From 672b2b9e7c6a808bfd685bebaf5def84e7fcbc37 Mon Sep 17 00:00:00 2001 From: mseth10 Date: Thu, 1 Aug 2019 18:39:55 +0000 Subject: [PATCH 31/38] =?UTF-8?q?=E2=80=9Cre-trigger=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From 2257ff3203f44dc23801070b5a0e1dc85eeb63a7 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Fri, 2 Aug 2019 06:26:35 +0000 Subject: [PATCH 32/38] added map to store loaded libraries --- src/common/library.cc | 40 ++++++++++++++++++++++++++-------------- src/common/library.h | 2 ++ 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/common/library.cc b/src/common/library.cc index fff69565a6b1..119ad9cdd975 100644 --- a/src/common/library.cc +++ b/src/common/library.cc @@ -30,8 +30,11 @@ #include #endif +#include +#include #include "library.h" +std::map loaded_libs; #if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) /*! @@ -60,23 +63,32 @@ void win_err(char **err) { */ void* load_lib(const char* path) { void *handle = nullptr; + std::string path_str(path); + //check if library was already loaded + if(loaded_libs.find(path_str) == loaded_libs.end()) { + //if not, load it #if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) - handle = LoadLibrary(path); - if (!handle) { - char *err_msg = nullptr; - win_err(&err_msg); - LOG(FATAL) << "Error loading library: '" << path << "'\n" << err_msg; - LocalFree(err_msg); - return nullptr; - } + handle = LoadLibrary(path); + if (!handle) { + char *err_msg = nullptr; + win_err(&err_msg); + LOG(FATAL) << "Error loading library: '" << path << "'\n" << err_msg; + LocalFree(err_msg); + return nullptr; + } #else - handle = dlopen(path, RTLD_LAZY); - if (!handle) { - LOG(FATAL) << "Error loading library: '" << path << "'\n" << dlerror(); - return nullptr; - } + handle = dlopen(path, RTLD_LAZY); + if (!handle) { + LOG(FATAL) << "Error loading library: '" << path << "'\n" << dlerror(); + return nullptr; + } #endif // _WIN32 or _WIN64 or __WINDOWS__ - + //then store the pointer to the library + loaded_libs[path_str] = handle; + } else { + //otherwise just look up the pointer + handle = loaded_libs[path_str]; + } return handle; } diff --git a/src/common/library.h b/src/common/library.h index 4656c16097fa..a11148c60d87 100644 --- a/src/common/library.h +++ b/src/common/library.h @@ -28,6 +28,8 @@ #include #include "dmlc/io.h" +static std::map loaded_libs; + void* load_lib(const char* path); void get_sym(void* handle, void** func, char* name); From 0d05d1c8631afb40189b0d98f33ef3abf4d6c1bf Mon Sep 17 00:00:00 2001 From: samskalicky Date: Fri, 2 Aug 2019 06:46:40 +0000 Subject: [PATCH 33/38] added dlclose calls in naive & threaded engines --- src/engine/naive_engine.cc | 6 ++++++ src/engine/threaded_engine.h | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/engine/naive_engine.cc b/src/engine/naive_engine.cc index 92b38a8ea368..e3f659bdf85e 100644 --- a/src/engine/naive_engine.cc +++ b/src/engine/naive_engine.cc @@ -30,6 +30,7 @@ #include "./openmp.h" #include "../common/object_pool.h" #include "../profiler/custom_op_profiler.h" +#include "../../src/common/library.h" namespace mxnet { namespace engine { @@ -84,6 +85,11 @@ class NaiveEngine final : public Engine { } } #endif + //close opened libraries + for(std::string path : loaded_libs) { + void* handle = loaded_libs[path]; + dlclose(handle); + } } void Stop() override { diff --git a/src/engine/threaded_engine.h b/src/engine/threaded_engine.h index bf74485ba442..5011f23ba13d 100644 --- a/src/engine/threaded_engine.h +++ b/src/engine/threaded_engine.h @@ -44,6 +44,7 @@ #include "./openmp.h" #include "../common/object_pool.h" #include "../profiler/custom_op_profiler.h" +#include "../../src/common/library.h" namespace mxnet { namespace engine { @@ -331,6 +332,11 @@ class ThreadedEngine : public Engine { kill_.store(true); } finished_cv_.notify_all(); + //close opened libraries + for(std::string path : loaded_libs) { + void* handle = loaded_libs[path]; + dlclose(handle); + } } protected: From 3879f61f987d89c5f3d2550e097154c416469f82 Mon Sep 17 00:00:00 2001 From: samskalicky Date: Fri, 2 Aug 2019 07:07:42 +0000 Subject: [PATCH 34/38] removed library map declaration in cc file --- src/common/library.cc | 12 ++++++++---- src/common/library.h | 2 ++ src/engine/naive_engine.cc | 5 ++--- src/engine/threaded_engine.h | 5 ++--- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/common/library.cc b/src/common/library.cc index 119ad9cdd975..0b4d4d43e8c0 100644 --- a/src/common/library.cc +++ b/src/common/library.cc @@ -30,12 +30,8 @@ #include #endif -#include -#include #include "library.h" -std::map loaded_libs; - #if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) /*! * \brief Retrieve the system error message for the last-error code @@ -92,6 +88,14 @@ void* load_lib(const char* path) { return handle; } +/*! + * \brief Closes the loaded dynamic shared library file + * \param handle library file handle + */ +void close_lib(void* handle) { + dlclose(handle); +} + /*! * \brief Obtains address of given function in the loaded library * \param handle pointer for the loaded library diff --git a/src/common/library.h b/src/common/library.h index a11148c60d87..2ffbaa93605b 100644 --- a/src/common/library.h +++ b/src/common/library.h @@ -28,9 +28,11 @@ #include #include "dmlc/io.h" +//map of libraries loaded static std::map loaded_libs; void* load_lib(const char* path); +void close_lib(void* handle); void get_sym(void* handle, void** func, char* name); /*! diff --git a/src/engine/naive_engine.cc b/src/engine/naive_engine.cc index e3f659bdf85e..ea0464926674 100644 --- a/src/engine/naive_engine.cc +++ b/src/engine/naive_engine.cc @@ -86,9 +86,8 @@ class NaiveEngine final : public Engine { } #endif //close opened libraries - for(std::string path : loaded_libs) { - void* handle = loaded_libs[path]; - dlclose(handle); + for(auto const& lib : loaded_libs) { + close_lib(lib.second); } } diff --git a/src/engine/threaded_engine.h b/src/engine/threaded_engine.h index 5011f23ba13d..b0246d287640 100644 --- a/src/engine/threaded_engine.h +++ b/src/engine/threaded_engine.h @@ -333,9 +333,8 @@ class ThreadedEngine : public Engine { } finished_cv_.notify_all(); //close opened libraries - for(std::string path : loaded_libs) { - void* handle = loaded_libs[path]; - dlclose(handle); + for(auto const& lib : loaded_libs) { + close_lib(lib.second); } } From 289c3a5ed1355648855b25a26ed4e445fd8170be Mon Sep 17 00:00:00 2001 From: samskalicky Date: Fri, 2 Aug 2019 07:14:55 +0000 Subject: [PATCH 35/38] added windows free --- src/common/library.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/common/library.cc b/src/common/library.cc index 0b4d4d43e8c0..3b66389d9903 100644 --- a/src/common/library.cc +++ b/src/common/library.cc @@ -93,7 +93,11 @@ void* load_lib(const char* path) { * \param handle library file handle */ void close_lib(void* handle) { +#if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) + FreeLibrary(handle); +#else dlclose(handle); +#endif // _WIN32 or _WIN64 or __WINDOWS__ } /*! From a3b545da9fe2394faba76a9062c1b74cc7b22334 Mon Sep 17 00:00:00 2001 From: samskalicky Date: Fri, 2 Aug 2019 18:29:39 +0000 Subject: [PATCH 36/38] fixed formatting --- src/common/library.cc | 11 ++++++----- src/common/library.h | 6 ++++-- src/engine/naive_engine.cc | 4 ++-- src/engine/threaded_engine.h | 4 ++-- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/common/library.cc b/src/common/library.cc index 3b66389d9903..7fdd70d07db6 100644 --- a/src/common/library.cc +++ b/src/common/library.cc @@ -30,6 +30,7 @@ #include #endif +#include #include "library.h" #if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) @@ -60,9 +61,9 @@ void win_err(char **err) { void* load_lib(const char* path) { void *handle = nullptr; std::string path_str(path); - //check if library was already loaded - if(loaded_libs.find(path_str) == loaded_libs.end()) { - //if not, load it + // check if library was already loaded + if (loaded_libs.find(path_str) == loaded_libs.end()) { + // if not, load it #if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) handle = LoadLibrary(path); if (!handle) { @@ -79,10 +80,10 @@ void* load_lib(const char* path) { return nullptr; } #endif // _WIN32 or _WIN64 or __WINDOWS__ - //then store the pointer to the library + // then store the pointer to the library loaded_libs[path_str] = handle; } else { - //otherwise just look up the pointer + // otherwise just look up the pointer handle = loaded_libs[path_str]; } return handle; diff --git a/src/common/library.h b/src/common/library.h index 2ffbaa93605b..d6eff4184191 100644 --- a/src/common/library.h +++ b/src/common/library.h @@ -26,10 +26,12 @@ #define MXNET_COMMON_LIBRARY_H_ #include +#include +#include #include "dmlc/io.h" -//map of libraries loaded -static std::map loaded_libs; +// map of libraries loaded +static std::map loaded_libs; void* load_lib(const char* path); void close_lib(void* handle); diff --git a/src/engine/naive_engine.cc b/src/engine/naive_engine.cc index ea0464926674..371a6eb96303 100644 --- a/src/engine/naive_engine.cc +++ b/src/engine/naive_engine.cc @@ -85,8 +85,8 @@ class NaiveEngine final : public Engine { } } #endif - //close opened libraries - for(auto const& lib : loaded_libs) { + // close opened libraries + for (auto const& lib : loaded_libs) { close_lib(lib.second); } } diff --git a/src/engine/threaded_engine.h b/src/engine/threaded_engine.h index b0246d287640..e9ced8898305 100644 --- a/src/engine/threaded_engine.h +++ b/src/engine/threaded_engine.h @@ -332,8 +332,8 @@ class ThreadedEngine : public Engine { kill_.store(true); } finished_cv_.notify_all(); - //close opened libraries - for(auto const& lib : loaded_libs) { + // close opened libraries + for (auto const& lib : loaded_libs) { close_lib(lib.second); } } From e512d64e9901b78324d47bdca421024038069dc4 Mon Sep 17 00:00:00 2001 From: samskalicky Date: Fri, 2 Aug 2019 18:46:04 +0000 Subject: [PATCH 37/38] added cast to HMODULE for void* for windows --- src/common/library.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/library.cc b/src/common/library.cc index 7fdd70d07db6..9e79b5dbe1bc 100644 --- a/src/common/library.cc +++ b/src/common/library.cc @@ -95,7 +95,7 @@ void* load_lib(const char* path) { */ void close_lib(void* handle) { #if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) - FreeLibrary(handle); + FreeLibrary((HMODULE)handle); #else dlclose(handle); #endif // _WIN32 or _WIN64 or __WINDOWS__ From 134cc37d6b306514fde1a405d3b87cc946a56bd1 Mon Sep 17 00:00:00 2001 From: samskalicky Date: Fri, 2 Aug 2019 20:01:30 +0000 Subject: [PATCH 38/38] retrigger CI for flaky unix_cpu