| 231 | } |
| 232 | |
| 233 | void GPUTreeLearner::AllocateGPUMemory() { |
| 234 | num_dense_feature_groups_ = 0; |
| 235 | for (int i = 0; i < num_feature_groups_; ++i) { |
| 236 | if (ordered_bins_[i] == nullptr) { |
| 237 | num_dense_feature_groups_++; |
| 238 | } |
| 239 | } |
| 240 | // how many feature-group tuples we have |
| 241 | num_dense_feature4_ = (num_dense_feature_groups_ + (dword_features_ - 1)) / dword_features_; |
| 242 | // leave some safe margin for prefetching |
| 243 | // 256 work-items per workgroup. Each work-item prefetches one tuple for that feature |
| 244 | int allocated_num_data_ = num_data_ + 256 * (1 << kMaxLogWorkgroupsPerFeature); |
| 245 | // clear sparse/dense maps |
| 246 | dense_feature_group_map_.clear(); |
| 247 | device_bin_mults_.clear(); |
| 248 | sparse_feature_group_map_.clear(); |
| 249 | // do nothing if no features can be processed on GPU |
| 250 | if (!num_dense_feature_groups_) { |
| 251 | Log::Warning("GPU acceleration is disabled because no non-trivial dense features can be found"); |
| 252 | return; |
| 253 | } |
| 254 | // allocate memory for all features (FIXME: 4 GB barrier on some devices, need to split to multiple buffers) |
| 255 | device_features_.reset(); |
| 256 | device_features_ = std::unique_ptr<boost::compute::vector<Feature4>>(new boost::compute::vector<Feature4>(num_dense_feature4_ * num_data_, ctx_)); |
| 257 | // unpin old buffer if necessary before destructing them |
| 258 | if (ptr_pinned_gradients_) { |
| 259 | queue_.enqueue_unmap_buffer(pinned_gradients_, ptr_pinned_gradients_); |
| 260 | } |
| 261 | if (ptr_pinned_hessians_) { |
| 262 | queue_.enqueue_unmap_buffer(pinned_hessians_, ptr_pinned_hessians_); |
| 263 | } |
| 264 | if (ptr_pinned_feature_masks_) { |
| 265 | queue_.enqueue_unmap_buffer(pinned_feature_masks_, ptr_pinned_feature_masks_); |
| 266 | } |
| 267 | // make ordered_gradients and hessians larger (including extra room for prefetching), and pin them |
| 268 | ordered_gradients_.reserve(allocated_num_data_); |
| 269 | ordered_hessians_.reserve(allocated_num_data_); |
| 270 | pinned_gradients_ = boost::compute::buffer(); // deallocate |
| 271 | pinned_gradients_ = boost::compute::buffer(ctx_, allocated_num_data_ * sizeof(score_t), |
| 272 | boost::compute::memory_object::read_write | boost::compute::memory_object::use_host_ptr, |
| 273 | ordered_gradients_.data()); |
| 274 | ptr_pinned_gradients_ = queue_.enqueue_map_buffer(pinned_gradients_, boost::compute::command_queue::map_write_invalidate_region, |
| 275 | 0, allocated_num_data_ * sizeof(score_t)); |
| 276 | pinned_hessians_ = boost::compute::buffer(); // deallocate |
| 277 | pinned_hessians_ = boost::compute::buffer(ctx_, allocated_num_data_ * sizeof(score_t), |
| 278 | boost::compute::memory_object::read_write | boost::compute::memory_object::use_host_ptr, |
| 279 | ordered_hessians_.data()); |
| 280 | ptr_pinned_hessians_ = queue_.enqueue_map_buffer(pinned_hessians_, boost::compute::command_queue::map_write_invalidate_region, |
| 281 | 0, allocated_num_data_ * sizeof(score_t)); |
| 282 | // allocate space for gradients and hessians on device |
| 283 | // we will copy gradients and hessians in after ordered_gradients_ and ordered_hessians_ are constructed |
| 284 | device_gradients_ = boost::compute::buffer(); // deallocate |
| 285 | device_gradients_ = boost::compute::buffer(ctx_, allocated_num_data_ * sizeof(score_t), |
| 286 | boost::compute::memory_object::read_only, nullptr); |
| 287 | device_hessians_ = boost::compute::buffer(); // deallocate |
| 288 | device_hessians_ = boost::compute::buffer(ctx_, allocated_num_data_ * sizeof(score_t), |
| 289 | boost::compute::memory_object::read_only, nullptr); |
| 290 | // allocate feature mask, for disabling some feature-groups' histogram calculation |
nothing calls this directly
no test coverage detected