Rate This Document
Findability
Accuracy
Completeness
Readability

kupl::parallel_for

Create a "parallel for" loop. Compared with kupl_parallel_for, this interface uses the lambda function to capture the input parameters of the "parallel for" callback, eliminating the need for manual parameter encapsulation and improving interface usability.

Interface Definition

kupl::parallel_for(kupl_parallel_for_desc_t *desc, const pf_lambda &func);

Type Definition

using pf_lambda = std::function<void(const kupl_nd_range_t *nd_range, const int tid, const int tnum)>;

Table 1 Parameter definition

Parameter

Type

Description

Input/Output

desc

kupl_parallel_for_desc_t *

Description of the "parallel for" loop, which is a pointer to the kupl_parallel_for_desc_t structure. For details, see the description in the following table.

Input

func

pf_lambda

Function of the "parallel for" loop. The function must be defined in the format of std::function<void(const kupl_nd_range_t *nd_range, const int tid, const int tnum)>. nd_range indicates the actual loop range executed by the function, as determined by the internal logic of the kupl_parallel_for function. tid and tnum indicate the ID of the thread where the current function is executed and the total number of threads, respectively.

Input

Table 2 kupl_parallel_for_desc_t data structure definition

Parameter

Type

Description

field_mask

uint64_t

Mask of valid fields in the structure, similar to the bit flag of kupl_parallel_for_desc_field. Fields not specified in this mask will be ignored. Currently, this parameter is mandatory for all fields. You can set it to KUPL_PARALLEL_FOR_DESC_FIELD_DEFAULT to make all fields take effect.

Options:

  • KUPL_PARALLEL_FOR_DESC_FIELD_RANGE: The range takes effect.
  • KUPL_PARALLEL_FOR_DESC_FIELD_EGROUP: The egroup takes effect.
  • KUPL_PARALLEL_FOR_DESC_FIELD_CONCURRENCY: The concurrency takes effect.
  • KUPL_PARALLEL_FOR_DESC_FIELD_POLICY: The policy takes effect.
  • KUPL_PARALLEL_FOR_DESC_FIELD_DEFAULT: All the preceding fields take effect.

range

kupl_nd_range_t *

Range of the "parallel for" loop, which is a pointer to the kupl_nd_range_t structure. For details, see the following table.

egroup

kupl_egroup_h

egroup within which the "for" loop is executed, that is, the specific egroup whose executors will run the loop. This parameter can be set to a null pointer, meaning that the egroup is not specified.

concurrency

int

Concurrency of the "for" loop. This parameter can be set to KUPL_CONCURRENCY_DEFAULT, indicating that concurrency is not specified.

policy

kupl_loop_policy_type_t

Splitting policy that the "parallel for" loop follows. Currently, this parameter can be set to:

  • KUPL_LOOP_POLICY_STATIC: static splitting policy (even splitting).
  • KUPL_LOOP_POLICY_DYNAMIC: dynamic splitting policy.
  • KUPL_LOOP_POLICY_TASK: All tasks are statically split but submitted for dynamic scheduling.
Table 3 kupl_nd_range_t data structure definition

Parameter

Type

Description

dim

int

Dimension of the "parallel for" log range. The maximum value is KUPL_MAX_DIM_SIZE. The current value is 3.

nd_range

kupl_range_t[]

Specific range of each dimension. For example, nd_range[0] indicates the range of dimension 0. The size of the nd_range array is KUPL_MAX_DIM_SIZE. For details about the kupl_range_t data structure, see the following table.

Table 4 kupl_nd_range_t data structure definition

Parameter

Type

Description

dim

int

Dimension of the "parallel for" log range. The maximum value is KUPL_MAX_DIM_SIZE. The current value is 3.

nd_range

kupl_range_t[]

Specific range of each dimension. For example, nd_range[0] indicates the range of dimension 0. The size of the nd_range array is KUPL_MAX_DIM_SIZE. For details about the kupl_range_t data structure, see the following table.

Table 5 kupl_range_t data structure definition

Parameter

Type

Description

lower

int64_t

Start value of the "parallel for" loop, that is, the lower limit of the range.

upper

int64_t

End value of the "parallel for" loop, that is, the upper limit of the range.

step

int64_t

Step of the "parallel for" loop, that is, the value increased in each loop.

blocksize

int64_t

After a task is split, one block is executed at a time. The minimum number of iterations contained in each block is the block size. You can use KUPL_BLOCKSIZE_DEFAULT to specify the default block size. In the current static splitting policy, the block size does not take effect. KUPL evenly distributes data based on the number of threads. This parameter takes effect only in dynamic splitting and task splitting policies. The default block size is 1.

The data structure of kupl_nd_range_t is complex. In addition to allowing users to configure the data structure, corresponding macros are provided for users to easily configure kupl_nd_range_t with a dimension of 1. For details, see Table 5.

Note: The total number of tasks with more than one dimension must be less than the upper limit of int, that is, the number of total blocks is less than 2^31 – 1.

Table 6 Macro definitions of kupl_nd_range_t

Macro

Description

KUPL_1D_RANGE_INIT(_range, _col_begin, _col_end)

Configures the range of the "parallel for" loop with the dimension of 1 and the step of 1.

Details:

Sets the dimension of _range to 1.

Sets the lower limit, upper limit, step, and block size of (_range).nd_range[0] to _col_begin, _col_end, 1, and KUPL_BLOCKSIZE_DEFAULT, respectively.

KUPL_STRIDE_1D_RANGE_INIT(_range, _col_begin, _col_end, _col_step, _col_blocksize)

Configures the range of the "parallel for" loop with the dimension of 1.

Details:

Sets the dimension of _range to 1.

Sets the lower limit, upper limit, step, and block size of (_range).nd_range[0] to _col_begin, _col_end, _col_step, and _col_blocksize, respectively.

KUPL_2D_RANGE_INIT(_range, _row_begin, _row_end, _col_begin, _col_end)

Configures the range of the "parallel for" loop with the dimension of 2 and the step of 1.

Details:

Sets the dimension of _range to 2; sets the lower limit, upper limit, step, and block size of (_range).nd_range[0] to _col_begin, _col_end, 1, and KUPL_BLOCKSIZE_DEFAULT, respectively; and sets the upper limit, lower limit, step, and block size of (_range).nd_range[1] to _row_begin, _row_end, 1, and KUPL_BLOCKSIZE_DEFAULT, respectively.

KUPL_STRIDE_2D_RANGE_INIT(_range, _row_begin, _row_end, _row_step, _row_blocksize, _col_begin, _col_end, _col_step, _col_blocksize)

Configures the range of the "parallel for" loop with the dimension of 2.

Details:

Sets the dimension of _range to 2; sets the lower limit, upper limit, step, and block size of (_range).nd_range[0] to _col_begin, _col_end, _col_step, and _col_blocksize, respectively; and sets the upper limit, lower limit, step, and block size of (_range).nd_range[1] to _row_begin, _row_end, _row_step, and _row_blocksize, respectively.

KUPL_3D_RANGE_INIT(_range, _page_begin, _page_end, _row_begin, _row_end, _col_begin, _col_end)

Configures the range of the "parallel for" loop with the dimension of 3 and the step of 1.

Details:

Sets the dimension of _range to 3; sets the lower limit, upper limit, step, and block size of (_range).nd_range[0] to _col_begin, _col_end, 1, and KUPL_BLOCKSIZE_DEFAULT, respectively; sets the lower limit, upper limit, step, and block size of (_range).nd_range[1] to _row_begin, _row_end, 1, and KUPL_BLOCKSIZE_DEFAULT, respectively; and sets the lower limit, upper limit, step, and block size of (_range).nd_range[2] to _page_begin, _page_end, 1, and KUPL_BLOCKSIZE_DEFAULT, respectively.

KUPL_STRIDE_3D_RANGE_INIT(_range, _page_begin, _page_end, _page_step, _page_blocksize, _row_begin, _row_end, _row_step, _row_blocksize, _col_begin, _col_end, _col_step, _col_blocksize)

Configures the range of the "parallel for" loop with the dimension of 3.

Details:

Sets the dimension of _range to 3; sets the lower limit, upper limit, step, and block size of (_range).nd_range[0] to _col_begin, _col_end, _col_step, and _col_blocksize, respectively; sets the lower limit, upper limit, step, and block size of (_range).nd_range[1] to _row_begin, _row_end, _row_step, and _row_blocksize, respectively; and sets the lower limit, upper limit, step, and block size of (_range).nd_range[2] to _page_begin, _page_end, _page_step, and _page_blocksize, respectively.

Return Value

  • Success: KUPL_OK
  • Failure: KUPL_ERROR

Examples

 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
#include <atomic>
#include <assert.h>
#include "kupl.h"

int main()
{
    int count = 10;
    kupl_nd_range_t range;
    KUPL_1D_RANGE_INIT(range, 0, count);
    kupl_parallel_for_desc_t desc = {
        .field_mask = KUPL_PARALLEL_FOR_DESC_FIELD_DEFAULT,
        .range = &range,
        .egroup = nullptr,
        .concurrency = count,
        .policy = KUPL_LOOP_POLICY_STATIC,
    };

    std::atomic<size_t> sum(0);
    const size_t loop_size = 1000000;
    size_t sum_cal = (1 + loop_size) * loop_size / 2;
    size_t *data = (size_t *)malloc(loop_size * sizeof(loop_size));
    for (size_t i = 0; i < loop_size; i++) {
        data[i] = i + 1;
    }

    int ret = kupl::parallel_for(&desc, [&](const kupl_nd_range_t *nd_range, int tid, int tnum) {
        int start_index = nd_range->nd_range[0].lower * (loop_size / count);
        size_t local_sum = 0;
        for (size_t i = 0; i < loop_size / count; i++) {
            local_sum += data[start_index + i];
        }
        sum += local_sum;
    });
    assert(ret == KUPL_OK);
    assert(sum.load() == sum_cal);
    printf("sum: %lu\n", sum.load());
}

The execution result is as follows:

sum: 500000500000

The preceding example demonstrates how to use kupl::parallel_for to perform parallel computation of the sum of 1 to 1000000. First, the KUPL_1D_RANGE_INIT macro is used to configure the "parallel for" range for a single dimension with one step, spanning from 0 to count. Then, the "parallel for" loop description is configured, designating concurrency as count and employing all executors and the static splitting policy. Finally, the "for" loop is executed using the kupl_parallel_for function. Note that the preceding result is for reference only.