// ----------------------------------------------------------------------
// File: Parallel.hh
// Author: Andreas-Joachim Peters - CERN
// ----------------------------------------------------------------------
/************************************************************************
* EOS - the CERN Disk Storage System *
* Copyright (C) 2011 CERN/ASwitzerland *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see .*
************************************************************************/
/**
* @file Parallel.hh
*
* @brief Class providing a parallel for function using lambda functions/threads
*
*
*/
#include
#include
#include
#include
#include
#ifndef __EOSCOMMON__PARALLEL__HH
#define __EOSCOMMON__PARALLEL__HH
EOSCOMMONNAMESPACE_BEGIN
#if __GNUC_PREREQ(4,8) || defined(__clang__)
class Parallel
{
public:
template
static void For(Index start, Index end, Callable func)
{
// Estimate number of threads in the pool
const static unsigned nb_threads_hint = std::thread::hardware_concurrency();
const static unsigned nb_threads = (nb_threads_hint == 0u ? 8u :
nb_threads_hint);
// Size of a slice for the range functions
Index n = end - start + 1;
Index slice = (Index) std::round(n / static_cast(nb_threads));
slice = std::max(slice, Index(1));
// [Helper] Inner loop
auto launchRange = [&func](int k1, int k2) {
for (Index k = k1; k < k2; k++) {
func(k);
}
};
// Create pool and launch jobs
std::vector pool;
pool.reserve(nb_threads);
Index i1 = start;
Index i2 = std::min(start + slice, end);
for (unsigned i = 0; i + 1 < nb_threads && i1 < end; ++i) {
pool.emplace_back(launchRange, i1, i2);
i1 = i2;
i2 = std::min(i2 + slice, end);
}
if (i1 < end) {
pool.emplace_back(launchRange, i1, end);
}
// Wait for jobs to finish
for (std::thread& t : pool) {
if (t.joinable()) {
t.join();
}
}
}
// Serial version for easy comparison
template
static void SequentialFor(Index start, Index end, Callable func)
{
for (Index i = start; i < end; i++) {
func(i);
}
}
};
#endif
EOSCOMMONNAMESPACE_END
#endif