| 124 | } |
| 125 | |
| 126 | void GPUTreeLearner::GPUHistogram(data_size_t leaf_num_data, bool use_all_features) { |
| 127 | // we have already copied ordered gradients, ordered hessians and indices to GPU |
| 128 | // decide the best number of workgroups working on one feature4 tuple |
| 129 | // set work group size based on feature size |
| 130 | // each 2^exp_workgroups_per_feature workgroups work on a feature4 tuple |
| 131 | int exp_workgroups_per_feature = GetNumWorkgroupsPerFeature(leaf_num_data); |
| 132 | int num_workgroups = (1 << exp_workgroups_per_feature) * num_dense_feature4_; |
| 133 | if (num_workgroups > preallocd_max_num_wg_) { |
| 134 | preallocd_max_num_wg_ = num_workgroups; |
| 135 | Log::Info("Increasing preallocd_max_num_wg_ to %d for launching more workgroups", preallocd_max_num_wg_); |
| 136 | device_subhistograms_.reset(new boost::compute::vector<char>( |
| 137 | preallocd_max_num_wg_ * dword_features_ * device_bin_size_ * hist_bin_entry_sz_, ctx_)); |
| 138 | // we need to refresh the kernel arguments after reallocating |
| 139 | for (int i = 0; i <= kMaxLogWorkgroupsPerFeature; ++i) { |
| 140 | // The only argument that needs to be changed later is num_data_ |
| 141 | histogram_kernels_[i].set_arg(7, *device_subhistograms_); |
| 142 | histogram_allfeats_kernels_[i].set_arg(7, *device_subhistograms_); |
| 143 | histogram_fulldata_kernels_[i].set_arg(7, *device_subhistograms_); |
| 144 | } |
| 145 | } |
| 146 | #if GPU_DEBUG >= 4 |
| 147 | printf("Setting exp_workgroups_per_feature to %d, using %u work groups\n", exp_workgroups_per_feature, num_workgroups); |
| 148 | printf("Constructing histogram with %d examples\n", leaf_num_data); |
| 149 | #endif |
| 150 | |
| 151 | // the GPU kernel will process all features in one call, and each |
| 152 | // 2^exp_workgroups_per_feature (compile time constant) workgroup will |
| 153 | // process one feature4 tuple |
| 154 | |
| 155 | if (use_all_features) { |
| 156 | histogram_allfeats_kernels_[exp_workgroups_per_feature].set_arg(4, leaf_num_data); |
| 157 | } else { |
| 158 | histogram_kernels_[exp_workgroups_per_feature].set_arg(4, leaf_num_data); |
| 159 | } |
| 160 | // for the root node, indices are not copied |
| 161 | if (leaf_num_data != num_data_) { |
| 162 | indices_future_.wait(); |
| 163 | } |
| 164 | // for constant hessian, hessians are not copied except for the root node |
| 165 | if (!is_constant_hessian_) { |
| 166 | hessians_future_.wait(); |
| 167 | } |
| 168 | gradients_future_.wait(); |
| 169 | // there will be 2^exp_workgroups_per_feature = num_workgroups / num_dense_feature4 sub-histogram per feature4 |
| 170 | // and we will launch num_feature workgroups for this kernel |
| 171 | // will launch threads for all features |
| 172 | // the queue should be asynchrounous, and we will can WaitAndGetHistograms() before we start processing dense feature groups |
| 173 | if (leaf_num_data == num_data_) { |
| 174 | kernel_wait_obj_ = boost::compute::wait_list(queue_.enqueue_1d_range_kernel(histogram_fulldata_kernels_[exp_workgroups_per_feature], 0, num_workgroups * 256, 256)); |
| 175 | } else { |
| 176 | if (use_all_features) { |
| 177 | kernel_wait_obj_ = boost::compute::wait_list( |
| 178 | queue_.enqueue_1d_range_kernel(histogram_allfeats_kernels_[exp_workgroups_per_feature], 0, num_workgroups * 256, 256)); |
| 179 | } else { |
| 180 | kernel_wait_obj_ = boost::compute::wait_list( |
| 181 | queue_.enqueue_1d_range_kernel(histogram_kernels_[exp_workgroups_per_feature], 0, num_workgroups * 256, 256)); |
| 182 | } |
| 183 | } |
nothing calls this directly
no test coverage detected