[PATCH] D123225: [ThreadPool] add ability to group tasks into separate groups

Mehdi AMINI via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 6 22:13:13 PDT 2022


mehdi_amini added a comment.

That's a pretty nice improvement! :)

Reading the patch, I'm not sure I have a good grasp about all the interactions of this with the existing invariants of this class: concurrency is always complex...

> In essence the call stack would be: the thread loop in ThreadPool::grow() calls Task() which would call the TaskGroup logic lambda, which would call the user lambda. Regular non-TaskGroup would not go through that logic.

I don't quite get what you mean? Can you elaborate a bit? 
I agree that the complexity increase is worrisome, so any idea to manage it is welcome :)



================
Comment at: llvm/include/llvm/Support/ThreadPool.h:94
+  /// It is possible to recursively wait even inside a task, if the group is
+  /// different. There may be only one active wait() call for a given group.
+  /// It is possible to add new tasks while blocking on this call, if those
----------------
Do we have a way to assert on this?


================
Comment at: llvm/include/llvm/Support/ThreadPool.h:106
   bool isWorkerThread() const;
 
 private:
----------------
I think you need more documentation for the groups, at minima:
- in particular ownership model / lifetime expectation for the `TaskGroup` objects. 
- the existing APIs that don't take group should like be updated to be documented with respect to groups (is there a concept of a "default group" represented by the nullptr?).



================
Comment at: llvm/include/llvm/Support/ThreadPool.h:108
 private:
+  typedef std::deque<std::pair<std::function<void()>, TaskGroup *>> TaskQueue;
+
----------------
Why the change to `deque` in this patch?


================
Comment at: llvm/include/llvm/Support/ThreadPool.h:135
 
-  bool workCompletedUnlocked() { return !ActiveThreads && Tasks.empty(); }
+  bool workCompletedUnlocked(TaskGroup *Group) const;
 
----------------
Can you document it please?


================
Comment at: llvm/lib/Support/ThreadPool.cpp:91
+      NotifyGroup =
+          GroupOfTask != nullptr && workCompletedUnlocked(GroupOfTask);
+    }
----------------
Seems like if `GroupOfTask` is non-null you're calling `workCompletedUnlocked` twice, why?


================
Comment at: llvm/lib/Support/ThreadPool.cpp:97
+      CompletionCondition.notify_all();
+    // If this was a task in a group, notify also waiting for tasks in this
+    // function, to make a recursive wait() return after the group it's been
----------------
" notify also **threads** waiting" ?


================
Comment at: llvm/lib/Support/ThreadPool.cpp:98
+    // If this was a task in a group, notify also waiting for tasks in this
+    // function, to make a recursive wait() return after the group it's been
+    // waiting for has finished.
----------------
What does "this function" means here? 


================
Comment at: llvm/lib/Support/ThreadPool.cpp:111
+           return T.second == Group;
+         }) == Tasks.end();
+}
----------------
Nit: seems like The `find_if(...) == end()` could be replaced by `!llvm::any_of(...)`


================
Comment at: llvm/tools/llvm-profdata/llvm-profdata.cpp:41
 #include <algorithm>
+#include <queue>
 
----------------
aganea wrote:
> Is this related to the current patch?
I suspect this file was depending on this header transitively and the include was removed from the ThreadPool.h header.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D123225/new/

https://reviews.llvm.org/D123225



More information about the llvm-commits mailing list