| 122 | } |
| 123 | #ifndef DOXYGEN_SKIP_THIS |
| 124 | void OMPScheduler::run_workloads(std::vector<arm_compute::IScheduler::Workload> &workloads) |
| 125 | { |
| 126 | const unsigned int amount_of_work = static_cast<unsigned int>(workloads.size()); |
| 127 | const unsigned int num_threads_to_use = std::min(_num_threads, amount_of_work); |
| 128 | |
| 129 | if (num_threads_to_use < 1) |
| 130 | { |
| 131 | return; |
| 132 | } |
| 133 | |
| 134 | ThreadInfo info; |
| 135 | info.cpu_info = &cpu_info(); |
| 136 | info.num_threads = num_threads_to_use; |
| 137 | |
| 138 | ARM_COMPUTE_ERROR_ON(amount_of_work > _num_threads); |
| 139 | |
| 140 | #if !defined(__ANDROID__) |
| 141 | // Use fixed number of omp threads in the thread pool because changing this |
| 142 | // in-between kernel execution negatively affects the scheduler performance, |
| 143 | // possibly switching between X and Y number of threads, causing reconfiguration |
| 144 | // of the synchronization mechanism. This has been only tested in a subset of |
| 145 | // operating systems, thus we limit the change using guards. |
| 146 | const unsigned int omp_num_threads = _num_threads; |
| 147 | #else /* !__ANDROID__ */ |
| 148 | const unsigned int omp_num_threads = num_threads_to_use; |
| 149 | #endif /* __ANDROID__ */ |
| 150 | |
| 151 | #pragma omp parallel for firstprivate(info) num_threads(omp_num_threads) default(shared) proc_bind(close) \ |
| 152 | schedule(static, 1) |
| 153 | for (unsigned int wid = 0; wid < amount_of_work; ++wid) |
| 154 | { |
| 155 | info.thread_id = wid; |
| 156 | workloads[wid](info); |
| 157 | } |
| 158 | } |
| 159 | #endif /* DOXYGEN_SKIP_THIS */ |
| 160 | } // namespace arm_compute |
| 161 | #endif /* ARM_COMPUTE_OPENMP_SCHEDULER */ |