Intel® FPGA SDK for OpenCL™ Pro Edition: Programming Guide

ID 683846
Date 3/28/2022
Public

A newer version of this document is available. Customers should click here to go to the newest version.

Document Table of Contents

5.4.5.7. Implementing Buffered Channels Using the depth Channels Attribute

You may have buffered or unbuffered channels in your kernel program. If there are imbalances in channel read and write operations, create buffered channels to prevent kernel stalls by including the depth attribute in your channel declaration. Buffered channels decouple the operation of concurrent work-items executing in different kernels.

You may use a buffered channel to control data traffic, such as limiting throughput or synchronizing accesses to shared memory. In an unbuffered channel, a write operation cannot proceed until the read operation reads a data value. In a buffered channel, a write operation cannot proceed until the data value is copied to the buffer. If the buffer is full, the operation cannot proceed until the read operation reads a piece of data and removes it from the channel.

If you expect any temporary mismatch between the consumption rate and the production rate to the channel, set the buffer size using the depth channel attribute.
The following example demonstrates the use of the depth channel attribute in kernel code that implements the Intel® FPGA SDK for OpenCL™ channels extension. The depth(N) attribute specifies the minimum depth of a buffered channel, where N is the number of data values.
channel int c __attribute__((depth(10)));

__kernel void producer (__global int * in_data)
{
    for (int i = 0; i < N; i++)
    {
        if (in_data[i])
        {
            write_channel_intel(c, in_data[i]);
        }
    }
}

__kernel void consumer (__global int * restrict check_data,
                        __global int * restrict out_data)
{
    int last_val = 0;

    for (int i = 0; i < N, i++)
    {
        if (check_data[i])
        {
            last_val = read_channel_intel(c);
        }
        out_data[i] = last_val;
    }
}

In this example, the write operation can write ten data values to the channel without blocking. Once the channel is full, the write operation cannot proceed until an associated read operation to the channel occurs.

Because the channel read and write calls are conditional statements, the channel might experience an imbalance between read and write calls. You may add a buffer capacity to the channel to ensure that the producer and consumer kernels are decoupled. This step is particularly important if the producer kernel is writing data to the channel when the consumer kernel is not reading from it.