GCC Code Coverage Report


Directory: ../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 59 / 0 / 59
Functions: 100.0% 8 / 0 / 8
Branches: 67.2% 39 / 0 / 58

src/util/ThreadPool.cpp
Line Branch Exec Source
1 // Copyright (c) 2021-2026 ChilliBits. All rights reserved.
2
3 #include "ThreadPool.h"
4
5 #include <cassert>
6 #include <utility>
7
8 namespace spice::compiler {
9
10
1/2
✓ Branch 3 → 4 taken 4 times.
✗ Branch 3 → 25 not taken.
4 ThreadPool::ThreadPool(size_t threadCount) {
11
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 4 times.
4 assert(threadCount > 0);
12
1/2
✓ Branch 10 → 11 taken 4 times.
✗ Branch 10 → 17 not taken.
4 workers.reserve(threadCount);
13
2/2
✓ Branch 14 → 12 taken 14 times.
✓ Branch 14 → 15 taken 4 times.
18 for (size_t i = 0; i < threadCount; i++)
14
1/2
✓ Branch 12 → 13 taken 14 times.
✗ Branch 12 → 16 not taken.
28 workers.emplace_back([this] { workerLoop(); });
15 4 }
16
17 4 ThreadPool::~ThreadPool() {
18 {
19 4 std::lock_guard lock(mutex);
20 4 shuttingDown = true;
21 4 }
22 4 taskAvailable.notify_all();
23
2/2
✓ Branch 19 → 7 taken 14 times.
✓ Branch 19 → 20 taken 4 times.
22 for (std::thread &worker : workers)
24 14 worker.join();
25 4 }
26
27 /**
28 * Enqueue a task for execution on one of the worker threads
29 *
30 * @param task Task to execute
31 */
32 1305 void ThreadPool::submit(std::function<void()> task) {
33 {
34
1/2
✓ Branch 2 → 3 taken 1305 times.
✗ Branch 2 → 14 not taken.
1305 std::lock_guard lock(mutex);
35
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1305 times.
1305 assert(!shuttingDown);
36
1/2
✓ Branch 7 → 8 taken 1305 times.
✗ Branch 7 → 11 not taken.
2610 tasks.emplace(nextTaskIndex++, std::move(task));
37 1305 pendingCount++;
38 1305 }
39 1305 taskAvailable.notify_one();
40 1305 }
41
42 /**
43 * Block until all submitted tasks are done and re-throw the exception of the first failing task, if there was one.
44 * Afterwards the pool is reset and can be used for the next batch of tasks.
45 */
46 5 void ThreadPool::waitForAll() {
47 5 std::exception_ptr failure;
48 {
49
1/2
✓ Branch 3 → 4 taken 5 times.
✗ Branch 3 → 17 not taken.
5 std::unique_lock lock(mutex);
50
1/2
✓ Branch 4 → 5 taken 5 times.
✗ Branch 4 → 15 not taken.
15 allTasksDone.wait(lock, [this] { return pendingCount == 0; });
51 // Reset for the next batch
52 5 failure = std::exchange(firstException, nullptr);
53 5 canceled = false;
54 5 nextTaskIndex = 0;
55 5 }
56
2/2
✓ Branch 10 → 11 taken 2 times.
✓ Branch 10 → 13 taken 3 times.
5 if (failure)
57 4 std::rethrow_exception(failure);
58 5 }
59
60 /**
61 * Body of a worker thread: take tasks off the queue until the pool shuts down
62 */
63 14 void ThreadPool::workerLoop() {
64 while (true) {
65 1311 Task task;
66 bool skip;
67 {
68
1/2
✓ Branch 4 → 5 taken 1319 times.
✗ Branch 4 → 36 not taken.
1313 std::unique_lock lock(mutex);
69
5/6
✓ Branch 2 → 3 taken 1448 times.
✓ Branch 2 → 5 taken 14 times.
✓ Branch 4 → 5 taken 1305 times.
✓ Branch 4 → 6 taken 143 times.
✓ Branch 5 → 6 taken 1319 times.
✗ Branch 5 → 34 not taken.
2781 taskAvailable.wait(lock, [this] { return shuttingDown || !tasks.empty(); });
70
2/2
✓ Branch 7 → 8 taken 14 times.
✓ Branch 7 → 11 taken 1305 times.
1319 if (tasks.empty()) {
71
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 14 times.
14 assert(shuttingDown);
72 27 return;
73 }
74 2610 task = std::move(tasks.front());
75 1305 tasks.pop();
76 // Do not start new work after another task has already failed
77 1305 skip = canceled;
78
2/2
✓ Branch 18 → 19 taken 1305 times.
✓ Branch 18 → 21 taken 14 times.
1319 }
79
80
2/2
✓ Branch 20 → 22 taken 1113 times.
✓ Branch 20 → 23 taken 192 times.
1305 if (!skip) {
81 try {
82
2/2
✓ Branch 22 → 23 taken 1108 times.
✓ Branch 22 → 37 taken 2 times.
1113 task.job();
83 2 } catch (...) {
84
1/2
✓ Branch 39 → 40 taken 2 times.
✗ Branch 39 → 52 not taken.
2 std::lock_guard lock(mutex);
85 // Keep the exception of the earliest submitted task, to make error reporting independent of the scheduling
86
2/6
✗ Branch 41 → 42 not taken.
✓ Branch 41 → 43 taken 2 times.
✗ Branch 42 → 43 not taken.
✗ Branch 42 → 44 not taken.
✓ Branch 45 → 46 taken 2 times.
✗ Branch 45 → 50 not taken.
2 if (!firstException || task.index < firstExceptionTaskIndex) {
87 2 firstException = std::current_exception();
88 2 firstExceptionTaskIndex = task.index;
89 }
90 2 canceled = true;
91
1/2
✓ Branch 51 → 23 taken 2 times.
✗ Branch 51 → 56 not taken.
2 }
92 }
93
94 {
95
1/2
✓ Branch 23 → 24 taken 1305 times.
✗ Branch 23 → 55 not taken.
1302 std::lock_guard lock(mutex);
96 1305 pendingCount--;
97
2/2
✓ Branch 24 → 25 taken 59 times.
✓ Branch 24 → 26 taken 1246 times.
1305 if (pendingCount == 0)
98 59 allTasksDone.notify_all();
99 1305 }
100
2/2
✓ Branch 29 → 30 taken 1297 times.
✓ Branch 29 → 32 taken 13 times.
1319 }
101 }
102
103 } // namespace spice::compiler
104