Skip to content

Commit dee0b69

Browse files
canonizerRAMitchell
authored andcommitted
Fixed copy constructor for HostDeviceVectorImpl. (dmlc#3657)
- previously, vec_ in DeviceShard wasn't updated on copy; as a result, the shards continued to refer to the old HostDeviceVectorImpl object, which resulted in a dangling pointer once that object was deallocated
1 parent 86d88c0 commit dee0b69

File tree

2 files changed

+42
-1
lines changed

2 files changed

+42
-1
lines changed

src/common/host_device_vector.cu

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,19 @@ struct HostDeviceVectorImpl {
5858
perm_d_ = vec_->perm_h_.Complementary();
5959
}
6060

61+
void Init(HostDeviceVectorImpl<T>* vec, const DeviceShard& other) {
62+
if (vec_ == nullptr) { vec_ = vec; }
63+
CHECK_EQ(vec, vec_);
64+
device_ = other.device_;
65+
index_ = other.index_;
66+
cached_size_ = other.cached_size_;
67+
start_ = other.start_;
68+
proper_size_ = other.proper_size_;
69+
SetDevice();
70+
data_.resize(other.data_.size());
71+
perm_d_ = other.perm_d_;
72+
}
73+
6174
void ScatterFrom(const T* begin) {
6275
// TODO(canonizer): avoid full copy of host data
6376
LazySyncDevice(GPUAccess::kWrite);
@@ -166,7 +179,12 @@ struct HostDeviceVectorImpl {
166179
// required, as a new std::mutex has to be created
167180
HostDeviceVectorImpl(const HostDeviceVectorImpl<T>& other)
168181
: data_h_(other.data_h_), perm_h_(other.perm_h_), size_d_(other.size_d_),
169-
distribution_(other.distribution_), mutex_(), shards_(other.shards_) {}
182+
distribution_(other.distribution_), mutex_() {
183+
shards_.resize(other.shards_.size());
184+
dh::ExecuteIndexShards(&shards_, [&](int i, DeviceShard& shard) {
185+
shard.Init(this, other.shards_[i]);
186+
});
187+
}
170188

171189
// Init can be std::vector<T> or std::initializer_list<T>
172190
template <class Init>

tests/cpp/common/test_host_device_vector.cu

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,29 @@ TEST(HostDeviceVector, TestExplicit) {
155155
TestHostDeviceVector(n, distribution, starts, sizes);
156156
}
157157

158+
TEST(HostDeviceVector, TestCopy) {
159+
size_t n = 1001;
160+
int n_devices = 2;
161+
auto distribution = GPUDistribution::Block(GPUSet::Range(0, n_devices));
162+
std::vector<size_t> starts{0, 501};
163+
std::vector<size_t> sizes{501, 500};
164+
SetCudaSetDeviceHandler(SetDevice);
165+
166+
HostDeviceVector<int> v;
167+
{
168+
// a separate scope to ensure that v1 is gone before further checks
169+
HostDeviceVector<int> v1;
170+
InitHostDeviceVector(n, distribution, &v1);
171+
v = v1;
172+
}
173+
CheckDevice(&v, starts, sizes, 0, GPUAccess::kRead);
174+
PlusOne(&v);
175+
CheckDevice(&v, starts, sizes, 1, GPUAccess::kWrite);
176+
CheckHost(&v, GPUAccess::kRead);
177+
CheckHost(&v, GPUAccess::kWrite);
178+
SetCudaSetDeviceHandler(nullptr);
179+
}
180+
158181
TEST(HostDeviceVector, Span) {
159182
HostDeviceVector<float> vec {1.0f, 2.0f, 3.0f, 4.0f};
160183
vec.Reshard(GPUSet{0, 1});

0 commit comments

Comments
 (0)