@@ -3,6 +3,7 @@ | |||
#include <dds/build/file_deps.hpp> | |||
#include <dds/error/errors.hpp> | |||
#include <dds/proc.hpp> | |||
#include <dds/util/parallel.hpp> | |||
#include <dds/util/string.hpp> | |||
#include <dds/util/time.hpp> | |||
@@ -20,59 +21,6 @@ using namespace ranges; | |||
namespace { | |||
template <typename Range, typename Fn> | |||
bool parallel_run(Range&& rng, int n_jobs, Fn&& fn) { | |||
// We don't bother with a nice thread pool, as the overhead of most build | |||
// tasks dwarf the cost of interlocking. | |||
std::mutex mut; | |||
auto iter = rng.begin(); | |||
const auto stop = rng.end(); | |||
std::vector<std::exception_ptr> exceptions; | |||
auto run_one = [&]() mutable { | |||
while (true) { | |||
std::unique_lock lk{mut}; | |||
if (!exceptions.empty()) { | |||
break; | |||
} | |||
if (iter == stop) { | |||
break; | |||
} | |||
auto&& item = *iter; | |||
++iter; | |||
lk.unlock(); | |||
try { | |||
fn(item); | |||
} catch (...) { | |||
lk.lock(); | |||
exceptions.push_back(std::current_exception()); | |||
break; | |||
} | |||
} | |||
}; | |||
std::unique_lock lk{mut}; | |||
std::vector<std::thread> threads; | |||
if (n_jobs < 1) { | |||
n_jobs = std::thread::hardware_concurrency() + 2; | |||
} | |||
std::generate_n(std::back_inserter(threads), n_jobs, [&] { return std::thread(run_one); }); | |||
lk.unlock(); | |||
for (auto& t : threads) { | |||
t.join(); | |||
} | |||
for (auto eptr : exceptions) { | |||
try { | |||
std::rethrow_exception(eptr); | |||
} catch (const std::exception& e) { | |||
spdlog::error(e.what()); | |||
} | |||
} | |||
return exceptions.empty(); | |||
} | |||
/// The actual "real" information that we need to perform a compilation. | |||
struct compile_file_full { | |||
const compile_file_plan& plan; |
@@ -3,6 +3,7 @@ | |||
#include <dds/build/iter_compilations.hpp> | |||
#include <dds/build/plan/compile_exec.hpp> | |||
#include <dds/error/errors.hpp> | |||
#include <dds/util/parallel.hpp> | |||
#include <range/v3/view/concat.hpp> | |||
#include <range/v3/view/filter.hpp> | |||
@@ -20,60 +21,6 @@ using namespace dds; | |||
namespace { | |||
/// XXX: Duplicated in compile_exec.cpp !! | |||
template <typename Range, typename Fn> | |||
bool parallel_run(Range&& rng, int n_jobs, Fn&& fn) { | |||
// We don't bother with a nice thread pool, as the overhead of most build | |||
// tasks dwarf the cost of interlocking. | |||
std::mutex mut; | |||
auto iter = rng.begin(); | |||
const auto stop = rng.end(); | |||
std::vector<std::exception_ptr> exceptions; | |||
auto run_one = [&]() mutable { | |||
while (true) { | |||
std::unique_lock lk{mut}; | |||
if (!exceptions.empty()) { | |||
break; | |||
} | |||
if (iter == stop) { | |||
break; | |||
} | |||
auto&& item = *iter; | |||
++iter; | |||
lk.unlock(); | |||
try { | |||
fn(item); | |||
} catch (...) { | |||
lk.lock(); | |||
exceptions.push_back(std::current_exception()); | |||
break; | |||
} | |||
} | |||
}; | |||
std::unique_lock lk{mut}; | |||
std::vector<std::thread> threads; | |||
if (n_jobs < 1) { | |||
n_jobs = std::thread::hardware_concurrency() + 2; | |||
} | |||
std::generate_n(std::back_inserter(threads), n_jobs, [&] { return std::thread(run_one); }); | |||
lk.unlock(); | |||
for (auto& t : threads) { | |||
t.join(); | |||
} | |||
for (auto eptr : exceptions) { | |||
try { | |||
std::rethrow_exception(eptr); | |||
} catch (const std::exception& e) { | |||
spdlog::error(e.what()); | |||
} | |||
} | |||
return exceptions.empty(); | |||
} | |||
template <typename T, typename Range> | |||
decltype(auto) pair_up(T& left, Range& right) { | |||
auto rep = ranges::view::repeat(left); |
@@ -0,0 +1,13 @@ | |||
#include "./parallel.hpp" | |||
#include <spdlog/spdlog.h> | |||
using namespace dds; | |||
void dds::log_exception(std::exception_ptr eptr) noexcept { | |||
try { | |||
std::rethrow_exception(eptr); | |||
} catch (const std::exception& e) { | |||
spdlog::error(e.what()); | |||
} | |||
} |
@@ -0,0 +1,62 @@ | |||
#pragma once | |||
#include <algorithm> | |||
#include <mutex> | |||
#include <stdexcept> | |||
#include <thread> | |||
#include <vector> | |||
namespace dds { | |||
void log_exception(std::exception_ptr) noexcept; | |||
template <typename Range, typename Func> | |||
bool parallel_run(Range&& rng, int n_jobs, Func&& fn) { | |||
// We don't bother with a nice thread pool, as the overhead of most build | |||
// tasks dwarf the cost of interlocking. | |||
std::mutex mut; | |||
auto iter = rng.begin(); | |||
const auto stop = rng.end(); | |||
std::vector<std::exception_ptr> exceptions; | |||
auto run_one = [&]() mutable { | |||
while (true) { | |||
std::unique_lock lk{mut}; | |||
if (!exceptions.empty()) { | |||
break; | |||
} | |||
if (iter == stop) { | |||
break; | |||
} | |||
auto&& item = *iter; | |||
++iter; | |||
lk.unlock(); | |||
try { | |||
fn(item); | |||
} catch (...) { | |||
lk.lock(); | |||
exceptions.push_back(std::current_exception()); | |||
break; | |||
} | |||
} | |||
}; | |||
std::unique_lock lk{mut}; | |||
std::vector<std::thread> threads; | |||
if (n_jobs < 1) { | |||
n_jobs = std::thread::hardware_concurrency() + 2; | |||
} | |||
std::generate_n(std::back_inserter(threads), n_jobs, [&] { return std::thread(run_one); }); | |||
lk.unlock(); | |||
for (auto& t : threads) { | |||
t.join(); | |||
} | |||
for (auto eptr : exceptions) { | |||
log_exception(eptr); | |||
} | |||
return exceptions.empty(); | |||
} | |||
} // namespace dds |