Skip to content

Commit e4e8e62

Browse files
committed
[core] Fix TThreadExecutor's MapReduce on vectors with chunks
The last chunk of partial results of MapReduce with std::vectors had the size of all other chunks. This is dangerous, since the default vector values might cause unexpected results of the Reduce function. Test added to verify the correctness.
1 parent 400d4c7 commit e4e8e62

File tree

2 files changed

+25
-4
lines changed

2 files changed

+25
-4
lines changed

core/imt/inc/ROOT/TThreadExecutor.hxx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -412,8 +412,8 @@ namespace ROOT {
412412
using retType = decltype(func(args.front()));
413413
std::vector<retType> reslist(actualChunks);
414414
auto lambda = [&](unsigned int i) {
415-
std::vector<retType> partialResults(step);
416-
for (unsigned j = 0; j < step && (i + j) < nToProcess; j++) {
415+
std::vector<retType> partialResults(std::min(step, nToProcess - i));
416+
for (unsigned j = 0; j < partialResults.size(); j++) {
417417
partialResults[j] = func(args[i + j]);
418418
}
419419
reslist[i / step] = Reduce(partialResults, redfunc);
@@ -444,8 +444,8 @@ namespace ROOT {
444444
using retType = decltype(func(args.front()));
445445
std::vector<retType> reslist(actualChunks);
446446
auto lambda = [&](unsigned int i) {
447-
std::vector<retType> partialResults(step);
448-
for (unsigned j = 0; j < step && (i + j) < nToProcess; j++) {
447+
std::vector<retType> partialResults(std::min(step, nToProcess - i));
448+
for (unsigned j = 0; j < partialResults.size(); j++) {
449449
partialResults[j] = func(args[i + j]);
450450
}
451451
reslist[i / step] = Reduce(partialResults, redfunc);

core/imt/test/testRTaskArena.cxx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,4 +246,25 @@ TEST(TThreadExecutor, ThreadSafety) {
246246
EXPECT_TRUE(std::equal(counters.begin(), counters.end(), target.begin()));
247247
}
248248

249+
// Checking if we correctly handle uneven chunks
250+
TEST(TThreadExecutor, StdVectorChunks)
251+
{
252+
ROOT::TThreadExecutor ttex;
253+
auto func = [](int x) -> int { return x; };
254+
// redfunc must be such that does not have 0 as identity (i.e. not addition but multiplication)
255+
auto redfunc = [](const std::vector<int> &v) {
256+
return std::accumulate(v.begin(), v.end(), 1, std::multiplies<int>());
257+
};
258+
259+
// will be calculating 7 factorial = 5040, const and non-const vectors to invoke different overloads
260+
std::vector<int> vec{1, 2, 3, 4, 5, 6, 7};
261+
const std::vector<int> cvec{1, 2, 3, 4, 5, 6, 7};
262+
263+
EXPECT_EQ(ttex.MapReduce(func, vec, redfunc, 3), 5040); // with 3 chunks, last chunk is smaller
264+
EXPECT_EQ(ttex.MapReduce(func, cvec, redfunc, 3), 5040);
265+
266+
EXPECT_EQ(ttex.MapReduce(func, vec, redfunc, 9), 5040); // with 9 chunks, 2 empty chunks
267+
EXPECT_EQ(ttex.MapReduce(func, cvec, redfunc, 9), 5040);
268+
}
269+
249270
#endif

0 commit comments

Comments
 (0)