forked from taskflow/taskflow
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPartitioningAlgorithm.xml
More file actions
75 lines (75 loc) · 8.63 KB
/
Copy pathPartitioningAlgorithm.xml
File metadata and controls
75 lines (75 loc) · 8.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.9.1" xml:lang="en-US">
<compounddef id="PartitioningAlgorithm" kind="page">
<compoundname>PartitioningAlgorithm</compoundname>
<title>Partitioning Algorithm</title>
<tableofcontents>
<tocsect>
<name>Define a Partitioner for Parallel Algorithms</name>
<reference>PartitioningAlgorithm_1DefineAPartitionerForParallelAlgorithms</reference>
</tocsect>
<tocsect>
<name>Define a Static Partitioner</name>
<reference>PartitioningAlgorithm_1DefineAStaticPartitioner</reference>
</tocsect>
<tocsect>
<name>Define a Dynamic Partitioner</name>
<reference>PartitioningAlgorithm_1DefineADynamicPartitioner</reference>
</tocsect>
<tocsect>
<name>Define a Guided Partitioner</name>
<reference>PartitioningAlgorithm_1DefineAGuidedPartitioner</reference>
</tocsect>
</tableofcontents>
<briefdescription>
</briefdescription>
<detaileddescription>
<para>A partitioning algorithm allows applications to optimize parallel algorithms using different scheduling methods, such as static partitioning, dynamic partitioning, and guided partitioning.</para>
<sect1 id="PartitioningAlgorithm_1DefineAPartitionerForParallelAlgorithms">
<title>Define a Partitioner for Parallel Algorithms</title>
<para>A partitioner defines how to partition and distribute iterations to different workers when running parallel algorithms in Taskflow, such as <ref refid="classtf_1_1FlowBuilder_1a025717373e424a6ccf9a61163bdaa585" kindref="member">tf::Taskflow::for_each</ref> and <ref refid="classtf_1_1FlowBuilder_1ab2db36500ea85146772acc75fc586ced" kindref="member">tf::Taskflow::transform</ref>. The following example shows how to create parallel-iteration tasks with different execution policies:</para>
<para><programlisting filename=".cpp"><codeline><highlight class="normal"><ref refid="cpp/container/vector" kindref="compound" external="/home/thuang295/Code/taskflow/doxygen/cppreference-doxygen-web.tag.xml">std::vector<int></ref><sp/>data<sp/>=<sp/>{1,<sp/>2,<sp/>3,<sp/>4,<sp/>5,<sp/>6,<sp/>7,<sp/>8,<sp/>9,<sp/>10}</highlight></codeline>
<codeline><highlight class="normal"></highlight></codeline>
<codeline><highlight class="normal"></highlight><highlight class="comment">//<sp/>create<sp/>different<sp/>partitioners</highlight><highlight class="normal"></highlight></codeline>
<codeline><highlight class="normal"><ref refid="classtf_1_1GuidedPartitioner" kindref="compound">tf::GuidedPartitioner</ref><sp/>guided_partitioner;</highlight></codeline>
<codeline><highlight class="normal"><ref refid="classtf_1_1StaticPartitioner" kindref="compound">tf::StaticPartitioner</ref><sp/>static_partitioner;</highlight></codeline>
<codeline><highlight class="normal"><ref refid="classtf_1_1RandomPartitioner" kindref="compound">tf::RandomPartitioner</ref><sp/>random_partitioner;</highlight></codeline>
<codeline><highlight class="normal"><ref refid="classtf_1_1DynamicPartitioner" kindref="compound">tf::DynamicPartitioner</ref><sp/>dynamic_partitioner;</highlight></codeline>
<codeline><highlight class="normal"></highlight></codeline>
<codeline><highlight class="normal"></highlight><highlight class="comment">//<sp/>create<sp/>four<sp/>parallel-iteration<sp/>tasks<sp/>from<sp/>the<sp/>four<sp/>execution<sp/>policies</highlight><highlight class="normal"></highlight></codeline>
<codeline><highlight class="normal">taskflow.for_each(data.begin(),<sp/>data.end(),<sp/>[](</highlight><highlight class="keywordtype">int</highlight><highlight class="normal"><sp/>i){},<sp/>guided_partitioner);</highlight></codeline>
<codeline><highlight class="normal">taskflow.for_each(data.begin(),<sp/>data.end(),<sp/>[](</highlight><highlight class="keywordtype">int</highlight><highlight class="normal"><sp/>i){},<sp/>static_partitioner);</highlight></codeline>
<codeline><highlight class="normal">taskflow.for_each(data.begin(),<sp/>data.end(),<sp/>[](</highlight><highlight class="keywordtype">int</highlight><highlight class="normal"><sp/>i){},<sp/>random_partitioner);</highlight></codeline>
<codeline><highlight class="normal">taskflow.for_each(data.begin(),<sp/>data.end(),<sp/>[](</highlight><highlight class="keywordtype">int</highlight><highlight class="normal"><sp/>i){},<sp/>dynamic_partitioner);</highlight></codeline>
</programlisting></para>
<para>Each partitioner has a specific algorithm to partition iterations into a set of <emphasis>chunks</emphasis> and distribute chunks to workers. A chunk is the basic unit of work that will be run by a worker during the execution of parallel iterations. The following figure illustrates the scheduling diagram for three major partitioners, <ref refid="classtf_1_1StaticPartitioner" kindref="compound">tf::StaticPartitioner</ref>, <ref refid="classtf_1_1DynamicPartitioner" kindref="compound">tf::DynamicPartitioner</ref>, and <ref refid="classtf_1_1GuidedPartitioner" kindref="compound">tf::GuidedPartitioner</ref>:</para>
<para><image type="html" name="parallel_for_partition_algorithms.png"></image>
</para>
<para>Depending on applications, partitioning algorithms can impact the performance a lot. For example, if a parallel-iteration workload contains a regular work unit per iteration, <ref refid="classtf_1_1StaticPartitioner" kindref="compound">tf::StaticPartitioner</ref> may deliver the best performance. On the other hand, if the work unit per iteration is irregular and unbalanced, <ref refid="classtf_1_1GuidedPartitioner" kindref="compound">tf::GuidedPartitioner</ref> or <ref refid="classtf_1_1DynamicPartitioner" kindref="compound">tf::DynamicPartitioner</ref> can outperform <ref refid="classtf_1_1StaticPartitioner" kindref="compound">tf::StaticPartitioner</ref>.</para>
<para><simplesect kind="note"><para>By default, all parallel algorithms in Taskflow use tf::DefaultExecutionPolicy, which is based on guided scheduling via <ref refid="classtf_1_1GuidedPartitioner" kindref="compound">tf::GuidedPartitioner</ref>.</para>
</simplesect>
</para>
</sect1>
<sect1 id="PartitioningAlgorithm_1DefineAStaticPartitioner">
<title>Define a Static Partitioner</title>
<para>Static partitioner splits iterations into <computeroutput>iter_size/chunk_size</computeroutput> chunks and distribute chunks to workers in order. If no chunk size is given (<computeroutput>chunk_size</computeroutput> is <computeroutput>1</computeroutput>), Taskflow will partition iterations into chunks that are approximately equal in size. The following code creates a static partitioner with chunk size equal to 100:</para>
<para><programlisting filename=".cpp"><codeline><highlight class="normal"><ref refid="classtf_1_1StaticPartitioner" kindref="compound">tf::StaticPartitioner</ref><sp/>static_partitioner(100);</highlight></codeline>
</programlisting></para>
</sect1>
<sect1 id="PartitioningAlgorithm_1DefineADynamicPartitioner">
<title>Define a Dynamic Partitioner</title>
<para>Dynamic partitioner splits iterations into <computeroutput>iter_size/chunk_size</computeroutput> chunks and distribute chunks to workers without any specific order. The default chunk size is <computeroutput>1</computeroutput>, if not specified. The following code creates a dynamic partitioner with chunk size equal to 2:</para>
<para><programlisting filename=".cpp"><codeline><highlight class="normal"><ref refid="classtf_1_1DynamicPartitioner" kindref="compound">tf::DynamicPartitioner</ref><sp/>dynamic_partitioner(2);</highlight></codeline>
</programlisting></para>
</sect1>
<sect1 id="PartitioningAlgorithm_1DefineAGuidedPartitioner">
<title>Define a Guided Partitioner</title>
<para>Guided partitioner dynamically decides the chunk size. The size of a chunk is proportional to the number of unassigned iterations divided by the number of the threads, and the size will gradually decrease to the specified chunk size (default <computeroutput>1</computeroutput>). The last chunk may be smaller than the specified chunk size. The following code creates a guided partitioner with chunk size equal to 10:</para>
<para><programlisting filename=".cpp"><codeline><highlight class="normal"><ref refid="classtf_1_1GuidedPartitioner" kindref="compound">tf::GuidedPartitioner</ref><sp/>guided_partitioner(10);</highlight></codeline>
</programlisting></para>
<para>In most situations, guided partitioner can achieve decent performance due to adaptive parallelism, especially for those with irregular and unbalanced workload per iteration. As a result, guided partitioner is used as the default partitioner for our parallel algorithms. </para>
</sect1>
</detaileddescription>
<location file="algorithms/partitioner.dox"/>
</compounddef>
</doxygen>