#include "fesa/assembly/parallel_for.hpp" #include #include #include #include #include #include #include namespace fesa { namespace { class ParallelForBodyError final : public std::runtime_error { public: using std::runtime_error::runtime_error; }; std::array, 2> parallelForBackends( const SerialParallelFor& serial, const TbbParallelFor& tbb) { return {std::cref(serial), std::cref(tbb)}; } TEST(ParallelFor, ZeroOneManyExecuteExactlyOnce) { const SerialParallelFor serial; const TbbParallelFor tbb; for (const ParallelFor& parallelFor : parallelForBackends(serial, tbb)) { bool zeroBodyCalled = false; parallelFor.execute(0U, [&zeroBodyCalled](std::size_t) { zeroBodyCalled = true; }); EXPECT_FALSE(zeroBodyCalled); for (const std::size_t count : {1U, 257U}) { std::vector visits(count, 0); parallelFor.execute(count, [&visits](std::size_t index) { ++visits[index]; }); EXPECT_EQ(visits, std::vector(count, 1)); } } } TEST(ParallelFor, SerialAndTbbProduceStableIndexedOutput) { constexpr std::size_t count = 1024U; std::vector serialOutput(count, 0U); std::vector tbbOutput(count, 0U); const auto valueForIndex = [](std::size_t index) { return (index + 17U) * (index + 3U); }; const SerialParallelFor serial; serial.execute(count, [&serialOutput, &valueForIndex](std::size_t index) { serialOutput[index] = valueForIndex(index); }); const TbbParallelFor tbb; tbb.execute(count, [&tbbOutput, &valueForIndex](std::size_t index) { tbbOutput[index] = valueForIndex(index); }); EXPECT_EQ(tbbOutput, serialOutput); for (std::size_t index = 0; index < count; ++index) { EXPECT_EQ(tbbOutput[index], valueForIndex(index)); } } TEST(ParallelFor, PropagatesBodyExceptionByContract) { const SerialParallelFor serial; const TbbParallelFor tbb; for (const ParallelFor& parallelFor : parallelForBackends(serial, tbb)) { try { // Every iteration throws the same value so the assertion is independent // of which oneTBB task reports the cancellation-triggering exception. parallelFor.execute(64U, [](std::size_t) { throw ParallelForBodyError{"parallel-for-body-failure"}; }); ADD_FAILURE() << "ParallelFor swallowed the body exception."; } catch (const ParallelForBodyError& error) { EXPECT_EQ(std::string{error.what()}, "parallel-for-body-failure"); } catch (...) { ADD_FAILURE() << "ParallelFor changed the body exception type."; } } } } // namespace } // namespace fesa