Когда мы пишем код, предназначенный для реализации HLS, мы склонны реализовывать повторяющиеся алгоритмы, обрабатывающие блоки данных — например, обработку сигналов или изображений.

Таким образом, наш исходный код HLS на C или C++ имеет тенденцию включать несколько циклов или вложенных циклов. Когда дело доходит до оптимизации, циклы производительности — это одно из мест, с которых мы можем начать изучение оптимизации.

По умолчанию циклы HLS сохраняются. Это означает, что каждая итерация цикла использует одно и то же оборудование. Конечно, это обеспечивает наихудшую производительность, поскольку каждая итерация является последовательной.

Возьмем простой аккумулятор, как показано ниже.

Без оптимизации мы заметим, что в представлении анализа реализация является последовательной. Это можно подтвердить, взглянув на счетчик поездок, который показывает количество итераций цикла и интервал запуска. Интервал инициализации — это количество тактов, после которых модуль может принимать новые входные значения.

Чтобы получить оптимальную пропускную способность, мы хотим, чтобы интервал запуска был как можно короче.

Чтобы повысить производительность, мы можем развернуть цикл и реализовать параллельные реализации, если границы цикла являются статическими.

Когда это будет синтезировано, мы увидим значительное сокращение Интервала Инициации.

Количество поездок не определено, так как цикл полностью развернут.

Когда мы развертываем циклы, мы получаем более высокую производительность для увеличения использования логики.

Конечно, могут быть случаи, когда мы не можем работать с производительностью свернутого цикла, но не можем приспособить логические требования к полностью развернутому циклу.

В этой ситуации мы можем частично развернуть циклы, определив фактор развертывания. Для примера изменим размер аккумулятора.

Установив коэффициент развертывания, мы можем контролировать степень распараллеливания цикла.

В отчете об анализе будет показана факторизованная развернутая производительность. В этом случае tt занимает половину задержки свернутого примера.

Вы также увидите это в средстве просмотра расписания. В средстве просмотра расписания вы увидите реализации алгоритма.

Когда мы частично разворачиваем код, инструмент HLS реализует проверку выхода в цикле, если коэффициент развертывания не дает целое число. Однако, если это целое число, мы можем пропустить проверку выхода.

Но как нам обрабатывать вложенные циклы, например, если мы выполняем матричные операции или обработку изображений?

В этом случае у нас есть несколько вариантов, хотя это зависит от того, как мы реализуем наши циклы. Чтобы получить наилучшую производительность (наименьшую задержку) при работе с вложенными циклами, мы хотим создать идеальные вложенные циклы.

В идеальном вложенном цикле снова границы цикла постоянны, и только самый внутренний цикл содержит какую-либо функциональность.

В случае идеального цикла мы можем сгладить цикл, объединив внешний и внутренний циклы, что обеспечит лучшую производительность при синтезе. Сглаженный цикл будет иметь свернутое число проходов n * m, где n и m — количество итераций каждого цикла.

Если у нас есть несколько циклов, реализованных последовательно, мы также можем их объединить.

Слияние петель отличается от сглаживания петли. В выравнивающем цикле мы объединяем вложенные циклы; при слиянии мы объединяем несколько независимых петель.

При объединении циклов используется максимальное связанное ограничение.

Если мы хотим объединить циклы, сначала нужно рассмотреть несколько ограничений. Мы не можем объединять циклы, которые имеют доступ к FIFO, границы переменных или побочные эффекты выполнения.

Давайте рассмотрим очень простой пример слияния циклов, код которого можно увидеть ниже.

Когда этот код синтезируется без оптимизации, количество задержек и срабатываний составляет:

Однако, если мы воспользуемся возможностью объединить три цикла:

Результаты, когда все три петли объединены, можно увидеть ниже: общая задержка намного ниже.

При оптимизации нашего дизайна для HLS мы хотим исследовать не только развертывание цикла. Мы также хотим рассмотреть, среди прочего, конвейерную обработку и разбиение памяти. Скоро буду делать подобные по глубине глубокие погружения!

Посмотрите мои проекты FPGA/SoC:Адам Тейлор на Hackster.io

Получите код:ATaylorCEngFIET (Адам Тейлор)

Доступ к архивам MicroZed Chronicles с более чем 300 статьями о FPGA / Zynq / Zynq MpSoC, которые еженедельно обновляются на MicroZed Chronicles.