Improve HostDeviceVector exception safety (#4301)
* make the assignments of HostDeviceVector exception safe. * storing a dummy GPUDistribution instance in HDV for CPU based code. * change testxgboost binary location to build directory.
This commit is contained in:
parent
680a1b36f3
commit
2f7087eba1
@ -340,7 +340,7 @@ if(GOOGLE_TEST)
|
|||||||
$<TARGET_OBJECTS:objxgboost>)
|
$<TARGET_OBJECTS:objxgboost>)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
set_output_directory(testxgboost ${PROJECT_SOURCE_DIR})
|
set_output_directory(testxgboost ${CMAKE_BINARY_DIR})
|
||||||
target_include_directories(testxgboost
|
target_include_directories(testxgboost
|
||||||
PRIVATE ${GTEST_INCLUDE_DIRS})
|
PRIVATE ${GTEST_INCLUDE_DIRS})
|
||||||
target_link_libraries(testxgboost ${GTEST_LIBRARIES} ${LINK_LIBRARIES})
|
target_link_libraries(testxgboost ${GTEST_LIBRARIES} ${LINK_LIBRARIES})
|
||||||
|
|||||||
@ -166,7 +166,7 @@ environment variable:
|
|||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
ASAN_OPTIONS=protect_shadow_gap=0 ../testxgboost
|
ASAN_OPTIONS=protect_shadow_gap=0 ${BUILD_DIR}/testxgboost
|
||||||
|
|
||||||
For details, please consult `official documentation <https://github.com/google/sanitizers/wiki>`_ for sanitizers.
|
For details, please consult `official documentation <https://github.com/google/sanitizers/wiki>`_ for sanitizers.
|
||||||
|
|
||||||
|
|||||||
@ -15,41 +15,42 @@ namespace xgboost {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct HostDeviceVectorImpl {
|
struct HostDeviceVectorImpl {
|
||||||
explicit HostDeviceVectorImpl(size_t size, T v) : data_h_(size, v), distribution_() {}
|
explicit HostDeviceVectorImpl(size_t size, T v) : data_h_(size, v) {}
|
||||||
HostDeviceVectorImpl(std::initializer_list<T> init) : data_h_(init), distribution_() {}
|
HostDeviceVectorImpl(std::initializer_list<T> init) : data_h_(init) {}
|
||||||
explicit HostDeviceVectorImpl(std::vector<T> init) : data_h_(std::move(init)), distribution_() {}
|
explicit HostDeviceVectorImpl(std::vector<T> init) : data_h_(std::move(init)) {}
|
||||||
|
|
||||||
|
void Swap(HostDeviceVectorImpl &other) {
|
||||||
|
data_h_.swap(other.data_h_);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<T>& Vec() { return data_h_; }
|
std::vector<T>& Vec() { return data_h_; }
|
||||||
GPUDistribution& Dist() { return distribution_; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<T> data_h_;
|
std::vector<T> data_h_;
|
||||||
GPUDistribution distribution_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
HostDeviceVector<T>::HostDeviceVector(size_t size, T v, GPUDistribution distribution)
|
HostDeviceVector<T>::HostDeviceVector(size_t size, T v, const GPUDistribution &)
|
||||||
: impl_(nullptr) {
|
: impl_(nullptr) {
|
||||||
impl_ = new HostDeviceVectorImpl<T>(size, v);
|
impl_ = new HostDeviceVectorImpl<T>(size, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
HostDeviceVector<T>::HostDeviceVector(std::initializer_list<T> init, GPUDistribution distribution)
|
HostDeviceVector<T>::HostDeviceVector(std::initializer_list<T> init, const GPUDistribution &)
|
||||||
: impl_(nullptr) {
|
: impl_(nullptr) {
|
||||||
impl_ = new HostDeviceVectorImpl<T>(init);
|
impl_ = new HostDeviceVectorImpl<T>(init);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
HostDeviceVector<T>::HostDeviceVector(const std::vector<T>& init, GPUDistribution distribution)
|
HostDeviceVector<T>::HostDeviceVector(const std::vector<T>& init, const GPUDistribution &)
|
||||||
: impl_(nullptr) {
|
: impl_(nullptr) {
|
||||||
impl_ = new HostDeviceVectorImpl<T>(init);
|
impl_ = new HostDeviceVectorImpl<T>(init);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
HostDeviceVector<T>::~HostDeviceVector() {
|
HostDeviceVector<T>::~HostDeviceVector() {
|
||||||
HostDeviceVectorImpl<T>* tmp = impl_;
|
delete impl_;
|
||||||
impl_ = nullptr;
|
impl_ = nullptr;
|
||||||
delete tmp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -63,8 +64,10 @@ HostDeviceVector<T>& HostDeviceVector<T>::operator=(const HostDeviceVector<T>& o
|
|||||||
if (this == &other) {
|
if (this == &other) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
delete impl_;
|
|
||||||
impl_ = new HostDeviceVectorImpl<T>(*other.impl_);
|
HostDeviceVectorImpl<T> newInstance(*other.impl_);
|
||||||
|
newInstance.Swap(*impl_);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +79,8 @@ GPUSet HostDeviceVector<T>::Devices() const { return GPUSet::Empty(); }
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
const GPUDistribution& HostDeviceVector<T>::Distribution() const {
|
const GPUDistribution& HostDeviceVector<T>::Distribution() const {
|
||||||
return impl_->Dist();
|
static GPUDistribution dummyInstance;
|
||||||
|
return dummyInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|||||||
@ -171,7 +171,7 @@ struct HostDeviceVectorImpl {
|
|||||||
HostDeviceVectorImpl<T>* vec_;
|
HostDeviceVectorImpl<T>* vec_;
|
||||||
};
|
};
|
||||||
|
|
||||||
HostDeviceVectorImpl(size_t size, T v, GPUDistribution distribution)
|
HostDeviceVectorImpl(size_t size, T v, const GPUDistribution &distribution)
|
||||||
: distribution_(distribution), perm_h_(distribution.IsEmpty()), size_d_(0) {
|
: distribution_(distribution), perm_h_(distribution.IsEmpty()), size_d_(0) {
|
||||||
if (!distribution_.IsEmpty()) {
|
if (!distribution_.IsEmpty()) {
|
||||||
size_d_ = size;
|
size_d_ = size;
|
||||||
@ -194,7 +194,7 @@ struct HostDeviceVectorImpl {
|
|||||||
|
|
||||||
// Initializer can be std::vector<T> or std::initializer_list<T>
|
// Initializer can be std::vector<T> or std::initializer_list<T>
|
||||||
template <class Initializer>
|
template <class Initializer>
|
||||||
HostDeviceVectorImpl(const Initializer& init, GPUDistribution distribution)
|
HostDeviceVectorImpl(const Initializer& init, const GPUDistribution &distribution)
|
||||||
: distribution_(distribution), perm_h_(distribution.IsEmpty()), size_d_(0) {
|
: distribution_(distribution), perm_h_(distribution.IsEmpty()), size_d_(0) {
|
||||||
if (!distribution_.IsEmpty()) {
|
if (!distribution_.IsEmpty()) {
|
||||||
size_d_ = init.size();
|
size_d_ = init.size();
|
||||||
@ -435,19 +435,19 @@ struct HostDeviceVectorImpl {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
HostDeviceVector<T>::HostDeviceVector
|
HostDeviceVector<T>::HostDeviceVector
|
||||||
(size_t size, T v, GPUDistribution distribution) : impl_(nullptr) {
|
(size_t size, T v, const GPUDistribution &distribution) : impl_(nullptr) {
|
||||||
impl_ = new HostDeviceVectorImpl<T>(size, v, distribution);
|
impl_ = new HostDeviceVectorImpl<T>(size, v, distribution);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
HostDeviceVector<T>::HostDeviceVector
|
HostDeviceVector<T>::HostDeviceVector
|
||||||
(std::initializer_list<T> init, GPUDistribution distribution) : impl_(nullptr) {
|
(std::initializer_list<T> init, const GPUDistribution &distribution) : impl_(nullptr) {
|
||||||
impl_ = new HostDeviceVectorImpl<T>(init, distribution);
|
impl_ = new HostDeviceVectorImpl<T>(init, distribution);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
HostDeviceVector<T>::HostDeviceVector
|
HostDeviceVector<T>::HostDeviceVector
|
||||||
(const std::vector<T>& init, GPUDistribution distribution) : impl_(nullptr) {
|
(const std::vector<T>& init, const GPUDistribution &distribution) : impl_(nullptr) {
|
||||||
impl_ = new HostDeviceVectorImpl<T>(init, distribution);
|
impl_ = new HostDeviceVectorImpl<T>(init, distribution);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -461,8 +461,10 @@ template <typename T>
|
|||||||
HostDeviceVector<T>& HostDeviceVector<T>::operator=
|
HostDeviceVector<T>& HostDeviceVector<T>::operator=
|
||||||
(const HostDeviceVector<T>& other) {
|
(const HostDeviceVector<T>& other) {
|
||||||
if (this == &other) { return *this; }
|
if (this == &other) { return *this; }
|
||||||
|
|
||||||
|
std::unique_ptr<HostDeviceVectorImpl<T>> newImpl(new HostDeviceVectorImpl<T>(*other.impl_));
|
||||||
delete impl_;
|
delete impl_;
|
||||||
impl_ = new HostDeviceVectorImpl<T>(*other.impl_);
|
impl_ = newImpl.release();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -93,7 +93,7 @@ class GPUDistribution {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
GPUDistribution(GPUSet devices, int granularity, int overlap,
|
GPUDistribution(GPUSet devices, int granularity, int overlap,
|
||||||
std::vector<size_t> offsets)
|
std::vector<size_t> &&offsets)
|
||||||
: devices_(devices), granularity_(granularity), overlap_(overlap),
|
: devices_(devices), granularity_(granularity), overlap_(overlap),
|
||||||
offsets_(std::move(offsets)) {}
|
offsets_(std::move(offsets)) {}
|
||||||
|
|
||||||
@ -109,7 +109,7 @@ class GPUDistribution {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static GPUDistribution Explicit(GPUSet devices, std::vector<size_t> offsets) {
|
static GPUDistribution Explicit(GPUSet devices, std::vector<size_t> offsets) {
|
||||||
return GPUDistribution(devices, 1, 0, offsets);
|
return GPUDistribution(devices, 1, 0, std::move(offsets));
|
||||||
}
|
}
|
||||||
|
|
||||||
friend bool operator==(const GPUDistribution& a, const GPUDistribution& b) {
|
friend bool operator==(const GPUDistribution& a, const GPUDistribution& b) {
|
||||||
@ -195,11 +195,11 @@ template <typename T>
|
|||||||
class HostDeviceVector {
|
class HostDeviceVector {
|
||||||
public:
|
public:
|
||||||
explicit HostDeviceVector(size_t size = 0, T v = T(),
|
explicit HostDeviceVector(size_t size = 0, T v = T(),
|
||||||
GPUDistribution distribution = GPUDistribution());
|
const GPUDistribution &distribution = GPUDistribution());
|
||||||
HostDeviceVector(std::initializer_list<T> init,
|
HostDeviceVector(std::initializer_list<T> init,
|
||||||
GPUDistribution distribution = GPUDistribution());
|
const GPUDistribution &distribution = GPUDistribution());
|
||||||
explicit HostDeviceVector(const std::vector<T>& init,
|
explicit HostDeviceVector(const std::vector<T>& init,
|
||||||
GPUDistribution distribution = GPUDistribution());
|
const GPUDistribution &distribution = GPUDistribution());
|
||||||
~HostDeviceVector();
|
~HostDeviceVector();
|
||||||
HostDeviceVector(const HostDeviceVector<T>&);
|
HostDeviceVector(const HostDeviceVector<T>&);
|
||||||
HostDeviceVector<T>& operator=(const HostDeviceVector<T>&);
|
HostDeviceVector<T>& operator=(const HostDeviceVector<T>&);
|
||||||
|
|||||||
@ -5,4 +5,4 @@ cd python-package
|
|||||||
python setup.py install --user
|
python setup.py install --user
|
||||||
cd ..
|
cd ..
|
||||||
pytest -v -s --fulltrace -m "(not mgpu) and (not slow)" tests/python-gpu
|
pytest -v -s --fulltrace -m "(not mgpu) and (not slow)" tests/python-gpu
|
||||||
./testxgboost --gtest_filter=-*.MGPU_*
|
./build/testxgboost --gtest_filter=-*.MGPU_*
|
||||||
|
|||||||
@ -5,7 +5,7 @@ cd python-package
|
|||||||
python setup.py install --user
|
python setup.py install --user
|
||||||
cd ..
|
cd ..
|
||||||
pytest -v -s --fulltrace -m "(not slow) and mgpu" tests/python-gpu
|
pytest -v -s --fulltrace -m "(not slow) and mgpu" tests/python-gpu
|
||||||
./testxgboost --gtest_filter=*.MGPU_*
|
./build/testxgboost --gtest_filter=*.MGPU_*
|
||||||
|
|
||||||
cd tests/distributed
|
cd tests/distributed
|
||||||
./runtests-gpu.sh
|
./runtests-gpu.sh
|
||||||
|
|||||||
@ -123,8 +123,8 @@ if [ ${TASK} == "cmake_test" ]; then
|
|||||||
PLUGINS="-DPLUGIN_LZ4=ON -DPLUGIN_DENSE_PARSER=ON"
|
PLUGINS="-DPLUGIN_LZ4=ON -DPLUGIN_DENSE_PARSER=ON"
|
||||||
cmake .. -DGOOGLE_TEST=ON -DGTEST_ROOT=$PWD/../gtest/ ${PLUGINS}
|
cmake .. -DGOOGLE_TEST=ON -DGTEST_ROOT=$PWD/../gtest/ ${PLUGINS}
|
||||||
make
|
make
|
||||||
cd ..
|
|
||||||
./testxgboost
|
./testxgboost
|
||||||
|
cd ..
|
||||||
rm -rf build
|
rm -rf build
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -170,10 +170,10 @@ if [ ${TASK} == "sanitizer_test" ]; then
|
|||||||
-DCMAKE_CXX_FLAGS="-fuse-ld=gold" \
|
-DCMAKE_CXX_FLAGS="-fuse-ld=gold" \
|
||||||
-DCMAKE_C_FLAGS="-fuse-ld=gold"
|
-DCMAKE_C_FLAGS="-fuse-ld=gold"
|
||||||
make
|
make
|
||||||
cd ..
|
|
||||||
|
|
||||||
export ASAN_SYMBOLIZER_PATH=$(which llvm-symbolizer)
|
export ASAN_SYMBOLIZER_PATH=$(which llvm-symbolizer)
|
||||||
ASAN_OPTIONS=symbolize=1 ./testxgboost
|
ASAN_OPTIONS=symbolize=1 ./testxgboost
|
||||||
|
cd ..
|
||||||
rm -rf build
|
rm -rf build
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user