feat(linear-static-3d-euler-beam): step 17 - parallel-for-tbb

This commit is contained in:
KOKO\Mimi
2026-08-09 18:52:35 +09:00
parent cfdac70756
commit 2f5e737fa1
6 changed files with 211 additions and 0 deletions
+92
View File
@@ -0,0 +1,92 @@
#include "fesa/assembly/parallel_for.hpp"
#include <gtest/gtest.h>
#include <array>
#include <cstddef>
#include <functional>
#include <stdexcept>
#include <string>
#include <vector>
namespace fesa {
namespace {
class ParallelForBodyError final : public std::runtime_error {
public:
using std::runtime_error::runtime_error;
};
std::array<std::reference_wrapper<const ParallelFor>, 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<int> visits(count, 0);
parallelFor.execute(count, [&visits](std::size_t index) {
++visits[index];
});
EXPECT_EQ(visits, std::vector<int>(count, 1));
}
}
}
TEST(ParallelFor, SerialAndTbbProduceStableIndexedOutput) {
constexpr std::size_t count = 1024U;
std::vector<std::size_t> serialOutput(count, 0U);
std::vector<std::size_t> 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