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 #if LLVM_ENABLE_THREADS 98 TEST(Parallel, NestedTaskGroup) { 99 // This test checks: 100 // 1. Root TaskGroup is in Parallel mode. 101 // 2. Nested TaskGroup is not in Parallel mode. 102 parallel::TaskGroup tg; 103 104 tg.spawn([&]() { 105 EXPECT_TRUE(tg.isParallel() || (parallel::strategy.ThreadsRequested == 1)); 106 }); 107 108 tg.spawn([&]() { 109 parallel::TaskGroup nestedTG; 110 EXPECT_FALSE(nestedTG.isParallel()); 111 112 nestedTG.spawn([&]() { 113 // Check that root TaskGroup is in Parallel mode. 114 EXPECT_TRUE(tg.isParallel() || 115 (parallel::strategy.ThreadsRequested == 1)); 116 117 // Check that nested TaskGroup is not in Parallel mode. 118 EXPECT_FALSE(nestedTG.isParallel()); 119 }); 120 }); 121 } 122 123 TEST(Parallel, ParallelNestedTaskGroup) { 124 // This test checks that it is possible to have several TaskGroups 125 // run from different threads in Parallel mode. 126 std::atomic<size_t> Count{0}; 127 128 { 129 std::function<void()> Fn = [&]() { 130 parallel::TaskGroup tg; 131 132 tg.spawn([&]() { 133 // Check that root TaskGroup is in Parallel mode. 134 EXPECT_TRUE(tg.isParallel() || 135 (parallel::strategy.ThreadsRequested == 1)); 136 137 // Check that nested TaskGroup is not in Parallel mode. 138 parallel::TaskGroup nestedTG; 139 EXPECT_FALSE(nestedTG.isParallel()); 140 ++Count; 141 142 nestedTG.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 EXPECT_FALSE(nestedTG.isParallel()); 149 ++Count; 150 }); 151 }); 152 }; 153 154 DefaultThreadPool Pool; 155 156 Pool.async(Fn); 157 Pool.async(Fn); 158 Pool.async(Fn); 159 Pool.async(Fn); 160 Pool.async(Fn); 161 Pool.async(Fn); 162 163 Pool.wait(); 164 } 165 EXPECT_EQ(Count, 12ul); 166 } 167 #endif 168 169 #endif 170