| 76 | } |
| 77 | |
| 78 | template <typename func_t> inline void parallel_2d(int m, int n, const func_t& f) { |
| 79 | // make sure we have even num_threads |
| 80 | int nth = adjust_num_threads(m); |
| 81 | |
| 82 | // [NOTE] thread blocking: |
| 83 | // |
| 84 | // 1) prefer square block per thread |
| 85 | // 2) use even number of CPU cores |
| 86 | // 3) use all `num_threads` cores |
| 87 | // |
| 88 | // we have: |
| 89 | // TM * TN = T |
| 90 | // BM / TM = BN / TN |
| 91 | // then: |
| 92 | // TM = ((BM / BN) * T) ^ 0.5 |
| 93 | // |
| 94 | float r = float(m) / n; |
| 95 | int nth_m = std::ceil(std::sqrt(r * nth)); |
| 96 | int nth_n = 1; |
| 97 | for (; nth_m > 0; --nth_m) { |
| 98 | nth_n = nth / nth_m; |
| 99 | if (nth_m * nth_n == nth) { |
| 100 | break; |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | #if defined(_OPENMP) |
| 105 | #pragma omp parallel num_threads(nth) |
| 106 | { |
| 107 | int ith = omp_get_thread_num(); |
| 108 | int ith_m = ith / nth_n; |
| 109 | int ith_n = ith % nth_n; |
| 110 | |
| 111 | int thread_block_m = div_up(m, nth_m); |
| 112 | int thread_block_n = div_up(n, nth_n); |
| 113 | |
| 114 | int begin_m = ith_m * thread_block_m; |
| 115 | int end_m = std::min(m, begin_m + thread_block_m); |
| 116 | int begin_n = ith_n * thread_block_n; |
| 117 | int end_n = std::min(n, begin_n + thread_block_n); |
| 118 | |
| 119 | f(begin_m, end_m, begin_n, end_n); |
| 120 | } |
| 121 | #else |
| 122 | f(0, m, 0, n); |
| 123 | #endif |
| 124 | } |
| 125 | |
| 126 | void quantize_cpu(float* code, float* A, float* absmax, unsigned char* out, long long blocksize, long long n); |
| 127 |
no test coverage detected