| 334 | |
| 335 | template <typename T> |
| 336 | void BiasGrad2DInternal(const CPUDevice& d, typename TTypes<T>::ConstFlat input, |
| 337 | Eigen::DSizes<int, 2>& two_dims, |
| 338 | typename TTypes<T>::Flat output) { |
| 339 | const int sum_size = two_dims[0]; |
| 340 | const int channel = two_dims[1]; |
| 341 | // NOTE(zycao): This is only threads number of Eigen threadpool. In MKL |
| 342 | // handeled cases, threads number for computing will be decided by OpenMP. |
| 343 | const T* in = input.data(); |
| 344 | T* out = output.data(); |
| 345 | |
| 346 | // NOTE(zycao): These conditions are based on modern CPU architechure |
| 347 | // features and verified by batch of tests on CPU. They are expected to |
| 348 | // make positive impact on most cases. |
| 349 | #define CPU_CACHE_LINE_SIZE 64 |
| 350 | #define HALF_L1_CACHE_SIZE 16384 |
| 351 | |
| 352 | const int num_threads = d.numThreads(); |
| 353 | |
| 354 | // Small cases would be explicitly done by single thread. |
| 355 | if (sizeof(T) * sum_size * channel <= HALF_L1_CACHE_SIZE || |
| 356 | sum_size / num_threads <= 2 || num_threads == 1) { |
| 357 | SumIntoOneRow(in, sum_size, channel, channel, out); |
| 358 | return; |
| 359 | } |
| 360 | // Seperate the array by rows and parallel sum into temp array, |
| 361 | // then sum the temp array in to output vector. |
| 362 | std::vector<std::vector<T>> sum_vec(num_threads + 1); |
| 363 | |
| 364 | auto work_on_rows = [&in, &sum_vec, d, channel] |
| 365 | (int64 start, int64 end) { |
| 366 | // If running in caller thread, currentThreadId would return -1. |
| 367 | int tid = d.currentThreadId() + 1; |
| 368 | std::vector<T>& vec = sum_vec[tid]; |
| 369 | if (vec.empty()) vec.resize(channel, static_cast<T>(0)); |
| 370 | SumIntoOneRow(&(in[start * channel]), end - start, channel, channel, |
| 371 | vec.data(), false); |
| 372 | }; |
| 373 | auto cost = Eigen::TensorOpCost(sizeof(T) * channel, // ld bytes |
| 374 | sizeof(T) * channel, // st bytes |
| 375 | channel); // compute cycles |
| 376 | d.parallelFor(sum_size, cost, work_on_rows); |
| 377 | |
| 378 | // Sum temp array to output vector. |
| 379 | for (int j = 0; j < channel; ++j) { |
| 380 | out[j] = static_cast<T>(0); |
| 381 | } |
| 382 | for (int i = 0; i < num_threads + 1; ++i) { |
| 383 | std::vector<T>& vec = sum_vec[i]; |
| 384 | if (!vec.empty()) { |
| 385 | for (int j = 0; j < channel; ++j) { |
| 386 | out[j] += vec[j]; |
| 387 | } |
| 388 | } |
| 389 | } |
| 390 | #undef CPU_CACHE_LINE_SIZE |
| 391 | #undef HALF_L1_CACHE_SIZE |
| 392 | } |
| 393 |
nothing calls this directly
no test coverage detected