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