Intel FPGA OpenCL: выявить причину низкой тактовой частоты ядра
Я реализую проект OpenCL для ПЛИС Intel Cyclone V. Он основан на модифицированной версии стандартного OpenCL BSP Terasic DE10.
Модификация содержит подключение к плате внешнего аналого-цифрового преобразователя, подключенной к плате FPGA, для которой был реализован специальный блок Qsys на основе VHDL, который передает сэмплы с частотой дискретизации около 16 МГц в avalon dual-clock FIFO. Выходные данные FIFO подключаются к домену часов ядра, а выходные данные FIFO интерфейса Avalon Streaming экспортируются в ядро OpenCL как канал, как описано в Руководстве по программированию Intel® FPGA SDK для OpenCLTM Standard Edition в разделе 5.4.5.4. (Реализация каналов ввода-вывода с использованием атрибута io Channels).
В настоящее время ядро CL просто выбирает блоки непрерывных данных из канала и записывает их в глобальный буфер памяти. Затем хост добавляет образцы в файл. Это стабильно работает для частот дискретизации аналого-цифрового преобразователя до 1 МГц, более высокие частоты дискретизации приводят к большим потерям.
Включение профилирования и использование Intel Dynamic Profiler для OpenCL показало причину: средняя частота ядра составляет всего 1,3 МГц. Однако, поскольку система OpenCL компилируется не через Quartus IDE, а через командную строку черезaoc
, информации о том, что было синтезировано и в чем причина столь низкой тактовой частоты, не так много. Так как же отследить узкое место моего дизайна с помощью инструментов, предоставляемых Intel?
Вот скриншот результатов профилирования:
Редактировать:
Вот соответствующая часть ядра CL и проекта Qsys. Обратите внимание, что путь TX, который вы найдете в обоих, в настоящее время не используется.
#pragma OPENCL EXTENSION cl_intel_channels: enable
struct TwoChannelSample
{
short2 chanA;
short2 chanB;
};
#define FIFO_DEPTH 32768
channel struct TwoChannelSample rxSamps __attribute__((depth(0))) __attribute__((io("THDB_ADA_rxSamples")));
channel struct TwoChannelSample txSamps __attribute__((depth(0))) __attribute__((io("THDB_ADA_txSamples")));
channel ushort stateChan __attribute__((depth(0))) __attribute__((io("THDB_ADA_state")));
kernel void thdbADARxTxCallback (global const float2* restrict txSamples,
global float2* restrict rxSamples,
global ushort* restrict interfaceState)
{
// get state from interface
*interfaceState = read_channel_intel (stateChan);
// Process sample-wise
for (int i = 0; i < FIFO_DEPTH; ++i)
{
struct TwoChannelSample rxSample = read_channel_intel (rxSamps);
rxSamples[i].x = (float)rxSample.chanA.x;
rxSamples[i].y = (float)rxSample.chanA.y;
rxSamples[i + FIFO_DEPTH].x = (float)rxSample.chanB.x;
rxSamples[i + FIFO_DEPTH].y = (float)rxSample.chanB.y;
}
}