iMSTK
Interactive Medical Simulation Toolkit
Docs/Extras/Parallelism.md
1 # Parallelism
2 
3 Parallelization is used in iMSTK in various locations. Primarily one will find loop parallelization. TBB is used as the parallelization backend which maintains a thread pool and does its own scheduling.
4 
5 iMSTK haptics also, by default, runs on a separate STL thread.
6 
7 ## Loop Parallelism
8 
9 iMSTK uses loop based parallelism throughout code. For this use parallelFor.
10 
11 ```cpp
12 #include "imstkParallelUtils.h"
13 
14 int main()
15 {
16  ParallelUtils::parallelFor(100000, [&](const size_T i)
17  {
18  // Do something
19  });
20  return 1;
21 }
22 ```
23 
24 Here something is done 100000 times in parallel. The optimal number of threads is used.
25 
26 ## Task Graph
27 
28 The `TaskGraph` in iMSTK contains a source and sink. A set of `TaskNode`'s, and set of directional edges. The edges express the succeeding and preceding tasks. A task may not execute until all its preceding tasks are complete. See examples here.
29 
30 Task graphs are used internally in iMSTK as well. Every DynamicalModel (PBD, SPH, FEM) contains a TaskGraph. Sometimes it's as simple as a few tasks in sequence. Sometimes it's more complex. This is especially useful for inserting intermediate tasks and defining custom physics pipelines.
31 
32 Here is a simple task graph construction:
33 
34 ```cpp
35 TaskGraph graph;
36 
37 // Create and add the nodes
38 std::shared_ptr<TaskNode> task1Node = graph.addFunction("Task1Name",
39  [&]()
40  {
41  // Do task 1 here
42  });
43 std::shared_ptr<TaskNode> task2Node = graph.addFunction("Task2Name",
44  [&]()
45  {
46  // Do task 2 here
47  });
48 
49 // Define the edges, add and mult steps will be done in parallel
50 graph.addEdge(graph.getSource(), task1Node );
51 graph.addEdge(graph.getSource(), task2Node );
52 graph.addEdge(task1Node, graph.getSink());
53 graph.addEdge(task2Node, graph.getSink());
54 ```
55 
56 This defines the following graph where Task1Name and Task2Name may be done in parallel.
57 
58 <p align="center">
59  <img src="../media/parallelism.png" alt="A simple TaskGraph"/>
60 </p>
61 
62 There are also numerous convenience functions in TaskGraph's. One may insert a node after or before a existing node in the graph (automatically adding edges).
63 
64 ```cpp
65 auto task = std::make_shared<TaskNode>("MyTask",
66  [&]()
67  {
68  // do task here
69  });
70 graph->insertAfter(task1Node, task);
71 ```
72 
73 There are also functions to check for cyclic dependencies, remove non-functional nodes, remove redundant edges (transient reduction), and topological sort.
74 
75 Additionally, if TaskNode timing is enabled, a stopwatch may be used for every node and times reported. In many iMSTK examples, if you press `P` twice, you may see the Scene's task graph node timings making bottlenecks very easy to find.
76 
77 <p align="center">
78  <img src="../media/profiler.png" alt="A simple TaskGraph"/>
79 </p>