66 size_t problem_size = 0,
size_t batch_size = 1,
size_t memory_per_problem = 0) {
77 base_wg_size = std::min(
size_t(64), max_compute_units * 2);
87 switch (kernel_type) {
90 base_wg_size = std::min(base_wg_size,
size_t(512));
92 base_wg_size = std::min(base_wg_size,
size_t(128));
98 base_wg_size = std::min(base_wg_size,
size_t(512));
100 base_wg_size = std::min(base_wg_size,
size_t(64));
103 base_wg_size = size_t(1) << (31 - __builtin_clzl(base_wg_size));
107 base_wg_size = std::min(base_wg_size,
size_t(256));
108 base_wg_size = size_t(1) << (31 - __builtin_clzl(base_wg_size));
112 base_wg_size = std::min(base_wg_size,
size_t(128));
117 base_wg_size = std::min(base_wg_size,
size_t(1024));
122 base_wg_size = std::min(base_wg_size,
size_t(128));
126 base_wg_size = std::min(base_wg_size,
size_t(256));
130 base_wg_size = std::min({base_wg_size, problem_size, size_t(64)});
134 base_wg_size = std::min(base_wg_size,
size_t(32));
137 if (problem_size > 0) {
138 base_wg_size = std::min(base_wg_size, problem_size);
141 base_wg_size = std::min(base_wg_size, max_wg_size);
143 if (memory_per_problem > 0) {
147 return std::max(base_wg_size,
size_t(1));
174 size_t preferred_wg_size = 0,
175 size_t footprint_per_problem = 0,
176 size_t max_wg_size_for_kernel = 0
180 const size_t INT32_MAX_SAFE =
static_cast<size_t>(std::numeric_limits<int32_t>::max()) / 2;
181 bool use_grid_stride = total_work > INT32_MAX_SAFE;
183 auto vendor =
device.get_vendor();
184 auto shedulers_per_cu = 2;
186 shedulers_per_cu = 4;
188 shedulers_per_cu = 8;
196 if (preferred_wg_size > 0) {
197 local_size = preferred_wg_size;
204 if (footprint_per_problem > 0) {
205 size_t problems_in_L2 = L2_cache_size / footprint_per_problem;
206 global_size = std::min(batch_size, problems_in_L2) * local_size;
209 if (use_grid_stride) {
210 size_t target_workgroups = max_compute_units * 4;
211 global_size = target_workgroups * local_size;
213 global_size = std::min(global_size, INT32_MAX_SAFE);
215 if (batch_size >= max_compute_units) {
216 size_t workgroups_per_matrix = 1;
217 size_t target_elements_per_workgroup = problem_size;
219 if (target_elements_per_workgroup > local_size) {
220 workgroups_per_matrix = (target_elements_per_workgroup + local_size - 1) / local_size;
223 global_size = batch_size * workgroups_per_matrix * local_size;
225 size_t workgroups_per_matrix = (max_compute_units + batch_size - 1) / batch_size;
227 size_t max_workgroups_per_matrix = (problem_size + local_size - 1) / local_size;
228 workgroups_per_matrix = std::min(workgroups_per_matrix, max_workgroups_per_matrix);
230 global_size = batch_size * workgroups_per_matrix * local_size;
233 size_t min_global_size = ((total_work + local_size - 1) / local_size) * local_size;
234 global_size = std::max(global_size, min_global_size);
237 return {.global_size = global_size,
238 .local_size = local_size,
239 .use_grid_stride = use_grid_stride};
261 size_t elements_per_matrix,
264 size_t preferred_wg_size = 0)
268 size_t local_size = preferred_wg_size > 0
272 const size_t required_wgs_per_matrix = (elements_per_matrix + local_size - 1) / local_size;
274 size_t work_groups_per_matrix;
275 if (batch_size >= max_compute_units) {
276 work_groups_per_matrix = 1;
278 const size_t target_wgs_per_matrix = (max_compute_units + batch_size - 1) / batch_size;
279 work_groups_per_matrix = std::min(target_wgs_per_matrix, required_wgs_per_matrix);
280 work_groups_per_matrix = std::max(work_groups_per_matrix,
size_t(1));
283 const size_t INT32_MAX_SAFE =
static_cast<size_t>(std::numeric_limits<int32_t>::max()) - local_size;
284 size_t global_size = batch_size * work_groups_per_matrix * local_size;
286 if (global_size > INT32_MAX_SAFE) {
287 const size_t max_total_wgs = INT32_MAX_SAFE / local_size;
288 const size_t max_wgs_per_mat = std::max<size_t>(1, max_total_wgs / batch_size);
289 work_groups_per_matrix = std::min(work_groups_per_matrix, max_wgs_per_mat);
290 global_size = batch_size * work_groups_per_matrix * local_size;
293 return {.global_size = global_size,
294 .local_size = local_size,
295 .work_groups_per_matrix = work_groups_per_matrix};
310 size_t preferred_wg_size = 0) {
312 if (preferred_wg_size > 0) {
313 local_size = preferred_wg_size;
318 const size_t max_safe_work_items = std::numeric_limits<int>::max() / 2;
321 if (total_work > max_safe_work_items) {
323 global_size = max_work_groups * local_size;
325 global_size = ((total_work + local_size - 1) / local_size) * local_size;
328 return {global_size, local_size};
BatchedMatrixDecomposition compute_batched_matrix_decomposition(size_t batch_size, size_t elements_per_matrix, const Device &device, KernelType kernel_type, size_t preferred_wg_size=0)
Compute batched matrix decomposition for work-group assignment.
size_t compute_optimal_wg_size(const Device &device, KernelType kernel_type, size_t problem_size=0, size_t batch_size=1, size_t memory_per_problem=0)
Compute a work-group size from the device type and kernel type.
std::pair< size_t, size_t > compute_nd_range_sizes(size_t total_work, const Device &device, KernelType kernel_type, size_t preferred_wg_size=0)
Compute optimal global and local work sizes for nd_range kernels with overflow protection.
BatchedNdRangeSizes compute_batched_nd_range_sizes(size_t total_work, const Device &device, KernelType kernel_type, size_t batch_size, size_t problem_size, size_t preferred_wg_size=0, size_t footprint_per_problem=0, size_t max_wg_size_for_kernel=0)
Compute nd_range sizes for a batched operation.