xref: /llvm-project/llvm/unittests/Support/ParallelTest.cpp (revision 06b617064a997574df409c7d846b6f6b492f5124)
1 //===- llvm/unittest/Support/ParallelTest.cpp -----------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// Parallel.h unit tests.
11 ///
12 //===----------------------------------------------------------------------===//
13 
14 #include "llvm/Support/Parallel.h"
15 #include "llvm/Support/ThreadPool.h"
16 #include "gtest/gtest.h"
17 #include <array>
18 #include <random>
19 
20 uint32_t array[1024 * 1024];
21 
22 using namespace llvm;
23 
24 // Tests below are hanging up on mingw. Investigating.
25 #if !defined(__MINGW32__)
26 
27 TEST(Parallel, sort) {
28   std::mt19937 randEngine;
29   std::uniform_int_distribution<uint32_t> dist;
30 
31   for (auto &i : array)
32     i = dist(randEngine);
33 
34   parallelSort(std::begin(array), std::end(array));
35   ASSERT_TRUE(llvm::is_sorted(array));
36 }
37 
38 TEST(Parallel, parallel_for) {
39   // We need to test the case with a TaskSize > 1. We are white-box testing
40   // here. The TaskSize is calculated as (End - Begin) / 1024 at the time of
41   // writing.
42   uint32_t range[2050];
43   std::fill(range, range + 2050, 1);
44   parallelFor(0, 2049, [&range](size_t I) { ++range[I]; });
45 
46   uint32_t expected[2049];
47   std::fill(expected, expected + 2049, 2);
48   ASSERT_TRUE(std::equal(range, range + 2049, expected));
49   // Check that we don't write past the end of the requested range.
50   ASSERT_EQ(range[2049], 1u);
51 }
52 
53 TEST(Parallel, TransformReduce) {
54   // Sum an empty list, check that it works.
55   auto identity = [](uint32_t v) { return v; };
56   uint32_t sum = parallelTransformReduce(ArrayRef<uint32_t>(), 0U,
57                                          std::plus<uint32_t>(), identity);
58   EXPECT_EQ(sum, 0U);
59 
60   // Sum the lengths of these strings in parallel.
61   const char *strs[] = {"a", "ab", "abc", "abcd", "abcde", "abcdef"};
62   size_t lenSum =
63       parallelTransformReduce(strs, static_cast<size_t>(0), std::plus<size_t>(),
64                               [](const char *s) { return strlen(s); });
65   EXPECT_EQ(lenSum, static_cast<size_t>(21));
66 
67   // Check that we handle non-divisible task sizes as above.
68   uint32_t range[2050];
69   std::fill(std::begin(range), std::end(range), 1);
70   sum = parallelTransformReduce(range, 0U, std::plus<uint32_t>(), identity);
71   EXPECT_EQ(sum, 2050U);
72 
73   std::fill(std::begin(range), std::end(range), 2);
74   sum = parallelTransformReduce(range, 0U, std::plus<uint32_t>(), identity);
75   EXPECT_EQ(sum, 4100U);
76 
77   // Avoid one large task.
78   uint32_t range2[3060];
79   std::fill(std::begin(range2), std::end(range2), 1);
80   sum = parallelTransformReduce(range2, 0U, std::plus<uint32_t>(), identity);
81   EXPECT_EQ(sum, 3060U);
82 }
83 
84 TEST(Parallel, ForEachError) {
85   int nums[] = {1, 2, 3, 4, 5, 6};
86   Error e = parallelForEachError(nums, [](int v) -> Error {
87     if ((v & 1) == 0)
88       return createStringError(std::errc::invalid_argument, "asdf");
89     return Error::success();
90   });
91   EXPECT_TRUE(e.isA<ErrorList>());
92   std::string errText = toString(std::move(e));
93   EXPECT_EQ(errText, std::string("asdf\nasdf\nasdf"));
94 }
95 
96 TEST(Parallel, TaskGroupSequentialFor) {
97   size_t Count = 0;
98   {
99     parallel::TaskGroup tg;
100     for (size_t Idx = 0; Idx < 500; Idx++)
101       tg.spawn([&Count, Idx]() { EXPECT_EQ(Count++, Idx); }, true);
102   }
103   EXPECT_EQ(Count, 500ul);
104 }
105 
106 TEST(Parallel, NestedTaskGroup) {
107   // This test checks:
108   // 1. Root TaskGroup is in Parallel mode.
109   // 2. Nested TaskGroup is not in Parallel mode.
110   parallel::TaskGroup tg;
111 
112   tg.spawn([&]() {
113     EXPECT_TRUE(tg.isParallel() || (parallel::strategy.ThreadsRequested == 1));
114   });
115 
116   tg.spawn([&]() {
117     parallel::TaskGroup nestedTG;
118     EXPECT_FALSE(nestedTG.isParallel());
119 
120     nestedTG.spawn([&]() {
121       // Check that root TaskGroup is in Parallel mode.
122       EXPECT_TRUE(tg.isParallel() ||
123                   (parallel::strategy.ThreadsRequested == 1));
124 
125       // Check that nested TaskGroup is not in Parallel mode.
126       EXPECT_FALSE(nestedTG.isParallel());
127     });
128   });
129 }
130 
131 #if LLVM_ENABLE_THREADS
132 TEST(Parallel, ParallelNestedTaskGroup) {
133   // This test checks that it is possible to have several TaskGroups
134   // run from different threads in Parallel mode.
135   std::atomic<size_t> Count{0};
136 
137   {
138     std::function<void()> Fn = [&]() {
139       parallel::TaskGroup tg;
140 
141       tg.spawn([&]() {
142         // Check that root TaskGroup is in Parallel mode.
143         EXPECT_TRUE(tg.isParallel() ||
144                     (parallel::strategy.ThreadsRequested == 1));
145 
146         // Check that nested TaskGroup is not in Parallel mode.
147         parallel::TaskGroup nestedTG;
148         EXPECT_FALSE(nestedTG.isParallel());
149         ++Count;
150 
151         nestedTG.spawn([&]() {
152           // Check that root TaskGroup is in Parallel mode.
153           EXPECT_TRUE(tg.isParallel() ||
154                       (parallel::strategy.ThreadsRequested == 1));
155 
156           // Check that nested TaskGroup is not in Parallel mode.
157           EXPECT_FALSE(nestedTG.isParallel());
158           ++Count;
159         });
160       });
161     };
162 
163     ThreadPool Pool;
164 
165     Pool.async(Fn);
166     Pool.async(Fn);
167     Pool.async(Fn);
168     Pool.async(Fn);
169     Pool.async(Fn);
170     Pool.async(Fn);
171 
172     Pool.wait();
173   }
174   EXPECT_EQ(Count, 12ul);
175 }
176 #endif
177 
178 #endif
179