| 56 | } |
| 57 | |
| 58 | void IScheduler::schedule_common(ICPPKernel *kernel, const Hints &hints, const Window &window, ITensorPack &tensors) |
| 59 | { |
| 60 | ARM_COMPUTE_ERROR_ON_MSG(!kernel, "The child class didn't set the kernel"); |
| 61 | #ifndef BARE_METAL |
| 62 | const Window &max_window = window; |
| 63 | if (hints.split_dimension() == IScheduler::split_dimensions_all) |
| 64 | { |
| 65 | /* |
| 66 | * if the split dim is size_t max then this signals we should parallelise over |
| 67 | * all dimensions |
| 68 | */ |
| 69 | const std::size_t m = max_window.num_iterations(Window::DimX); |
| 70 | const std::size_t n = max_window.num_iterations(Window::DimY); |
| 71 | |
| 72 | const unsigned int num_iterations = m * n; |
| 73 | const unsigned int num_threads = std::min(num_iterations, this->num_threads()); |
| 74 | |
| 75 | //in c++17 this can be swapped for auto [ m_threads, n_threads ] = split_2d(... |
| 76 | unsigned m_threads, n_threads; |
| 77 | std::tie(m_threads, n_threads) = scheduler_utils::split_2d(num_threads, m, n); |
| 78 | |
| 79 | // Clamp m_threads and n_threads if not all threads have work to do |
| 80 | unsigned int max_parallelism = std::min<unsigned int>(m, m_threads) * std::min<unsigned int>(n, n_threads); |
| 81 | if (max_parallelism < num_threads) |
| 82 | { |
| 83 | m_threads = std::min<unsigned int>(m, m_threads); |
| 84 | n_threads = std::min<unsigned int>(n, n_threads); |
| 85 | } |
| 86 | |
| 87 | std::vector<IScheduler::Workload> workloads; |
| 88 | for (unsigned int ni = 0; ni != n_threads; ++ni) |
| 89 | { |
| 90 | for (unsigned int mi = 0; mi != m_threads; ++mi) |
| 91 | { |
| 92 | workloads.push_back( |
| 93 | [ni, mi, m_threads, n_threads, &max_window, &kernel, &tensors](const ThreadInfo &info) |
| 94 | { |
| 95 | //narrow the window to our mi-ni workload |
| 96 | Window win = max_window.split_window(Window::DimX, mi, m_threads) |
| 97 | .split_window(Window::DimY, ni, n_threads); |
| 98 | |
| 99 | win.validate(); |
| 100 | |
| 101 | Window thread_locator; |
| 102 | thread_locator.set(Window::DimX, Window::Dimension(mi, m_threads)); |
| 103 | thread_locator.set(Window::DimY, Window::Dimension(ni, n_threads)); |
| 104 | |
| 105 | thread_locator.validate(); |
| 106 | |
| 107 | if (tensors.empty()) |
| 108 | { |
| 109 | kernel->run_nd(win, info, thread_locator); |
| 110 | } |
| 111 | else |
| 112 | { |
| 113 | kernel->run_op(tensors, win, info); |
| 114 | } |
| 115 | }); |
nothing calls this directly
no test coverage detected