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