Rate This Document
Findability
Accuracy
Completeness
Readability

kupl::queue_submit(kernel)

Submit kernels to be executed to a queue. Compared with kupl::queue_submit(item), this interface submits kernels to a queue. A kernel refers to a parallel computing task submitted to a queue for execution. The primary distinction is found in the input parameters. This interface relies on C++ function overloading.

This interface requires the C++ compiler. Currently, the range supports only 1D.

Interface Definition

int kupl::queue_submit(kupl_queue_h queue, kupl_queue_kernel_desc_t *desc, const std::function<void(const kupl_nd_range_t *)> &kernel);

Parameters

Table 1 Parameter definition

Parameter

Type

Description

Input/Output

queue

kupl_queue_h

Queue for executing kernels

Input

desc

kupl_queue_kernel_desc_t

Kernel description

Input

kernel

const std::function<void(const kupl_nd_range_t *)>

Kernel content, which is usually a lambda expression.

Input

Table 2 kupl_queue_kernel_desc_t data structure

Parameter

Type

Description

field_mask

uint64_t

(Mandatory) Mask of the kernel description, which is used to indicate which parameters are enabled. If there is no need to enable parameters, set the value to 0.

Available option:

KUPL_QUEUE_KERNEL_DESC_FIELD_NAME

range

kupl_nd_range_t *

(Mandatory) Range information of the kernel.

egroup

kupl_egroup_h

(Mandatory) Information about the executor available to the kernel.

name

const char *

(Optional) Kernel name.

Return Value

Success: KUPL_OK

Failure: KUPL_ERROR

Examples

#include <atomic>
#include <assert.h>
#include "kupl.h"

int main() {
    auto queue = kupl_queue_create();
    const int num_executors = 10;
    kupl_nd_range_t range;
    KUPL_1D_RANGE_INIT(range, 0, num_executors);
    int exe[num_executors];
    for (int i = 0; i < num_executors; i++) {
        exe[i] = i;
    }
    kupl_egroup_h egroup = kupl_egroup_create(exe, num_executors);
    kupl_queue_kernel_desc_t desc = {
        .range = &range,
        .egroup = egroup,
        .field_mask = 0,
    };

    std::atomic<size_t> sum(0);
    const size_t count = 1000000;
    size_t sum_cal = (1 + count) * count / 2;
    size_t *data = (size_t *)malloc(count * sizeof(count));
    for (size_t i = 0; i < count; i++) {
        data[i] = i + 1;
    }
    int ret = kupl::queue_submit(queue, &desc, [&](const kupl_nd_range_t *nd_range) {
        int start_index = nd_range->nd_range[0].lower * (count / num_executors);
        for (size_t i = 0; i < count / num_executors; i++) {
            sum += data[start_index + i];
        }
    });
    assert(ret == KUPL_OK);
    kupl_queue_wait(queue);
    assert(sum.load() == sum_cal);
    printf("sum: %lu\n", sum.load());
    kupl_egroup_destroy(egroup);
    kupl_queue_destroy(queue);
}

The execution result is as follows:

sum: 500000500000

The preceding example demonstrates the process of submitting kernels to a queue, calculating the sum of an array with a length of 1000000 across 10 threads, waiting until all kernels in the queue are executed, comparing the result with the direct calculation result, and outputting the result.