Vitis HLS 学习笔记--优化指令-BIND_OP_STORAGE

2024-04-23 05:12

本文主要是介绍Vitis HLS 学习笔记--优化指令-BIND_OP_STORAGE,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

1. BIND_OP_STORAGE 概述

1.1 BIND_OP

1.2 BIND_STORAGE

2. 语法解析

2.1 BIND_OP

2.2 BIND_OP 用法示例

2.3 BIND_STORAGE

2.4 BIND_STORAGE 示例

3. 实例演示

4. 总结


1. BIND_OP_STORAGE 概述

BIND_OP_STORAGE 其实是两个优化指令的合称:BIND_OP 和 BIND_STORAGE。

1.1 BIND_OP

Vitis HLS 使用特定 impl 来实现代码中的运算。BIND_OP 编译指示用于指定针对每个特定变量,都应将一项运算(mul、add、div)映射到特定器件资源,以便在 RTL 内实现 (impl)。如果不指定 BIND_OP 编译指示,Vitis HLS 会自动判定用于运算的资源。

1.2 BIND_STORAGE

BIND_STORAGE 编译指示用于将代码中的变量(阵列或函数实参)分配给 RTL 中的特定存储器类型 (type)。如果不指定此编译指示,那么 Vitis HLS 工具会判定要分配的存储器类型。HLS 工具在硬件中使用指定的实现 (impl) 来实现该存储器。

2. 语法解析

2.1 BIND_OP

#pragma HLS bind_op variable=<variable> op=<type> impl=<value> latency=<int>
  • variable=<variable>:用于定义要将 BIND_OP 编译指示分配到的变量
  • op=<type>:用于定义要绑定到特定实现资源的运算。受支持的函数运算包括:mul、add 和 sub 受支持的浮点运算包括:fadd、fsub、fdiv、fexp、flog、fmul、frsqrt、frecip、fsqrt、dadd、dsub、ddiv、dexp、dlog、dmul、drsqrt、drecip、dsqrt、hadd、hsub、hdiv、hmul 和 hsqrt。
  • impl=<value>:定义用于指定运算的实现。受支持的函数运算实现包括 fabric 和 dsp。受支持的浮点运算实现包括:fabric、meddsp、fulldsp、maxdsp 和 primitivedsp。
  • latency=<int>:定义运算的实现的默认时延。有效的时延值因指定的 op 和 impl 而异。默认值为 -1,即交由 Vitis HLS 选择时延。

支持的整数运算操作:

OP

Impl

Min Latency

Max Latency

add

fabric

0

4

add

dsp

0

4

mul

fabric

0

4

mul

dsp

0

4

sub

fabric

0

4

sub

dsp

0

0

 支持的浮点数运算操作:

操作

实现

Min Latency

Max Latency

fadd

fabric

0

13

fadd

fulldsp

0

12

fadd

primitivedsp

0

3

fexp

meddsp

0

21

fmul

maxdsp

0

7

快速记忆方法:

受支持的函数运算包括:
mul、add 、 sub受支持的浮点运算包括:
fadd fsub fdiv fexp flog fmul frsqrt frecip fsqrt
dadd dsub ddiv dexp dlog dmul drsqrt drecip dsqrt
hadd hsub hdiv           hmul               hsqrt

Impl解释:

  • fabric: 使用 FPGA 的逻辑单元和 RAM 块来实现算法。
  • dsp: 使用 FPGA DSP 功能来实现算法,例如 FFTFIRDDS 等。
  • meddsp: 使用 FPGA DSP 功能和一些逻辑单元来实现算法,适合中等复杂度的算法。
  • maxdsp: 使用 FPGA DSP 功能和更多的逻辑单元来实现算法,适合高复杂度的算法。
  • fulldsp: 使用 FPGA 的所有可用资源来实现算法,包括 DSPRAM 和逻辑单元。

2.2 BIND_OP 用法示例

double mult (double a, double b) {double c, d;
#pragma HLS BIND_OP variable=c op=dmul impl=fabric  latency=2
#pragma HLS BIND_OP variable=d op=dmul impl=fulldsp latency=10c = a * b;d = a * c;return d;
}

解释: 

  • 指定变量 的双精度浮点运算,实现方式fabric,延时为2
  • 指定变量 的双精度浮点运算,实现方式为fulldsp,延时为10

Vitis HLS 编译器得到的结果如下:

从命名可以看出:

  • dmul: 双精度乘法器。
  • 64ns: 输入数据的位宽是 64 位,ns的含义不明
  • 64: 输出数据的位宽是 64 位,3和5的含义不明。
  • max_dsp: 实现方法是使用最大数量的 DSP 功能。
  • U2: 模块的实例名字。

注意:

  • 编译器对待手动指定latency,会优先满足时钟频率上的要求,然后尽量靠近用户指定的latency
  • 如上述案例,虽然指定了latency=2,但是编译器需要latency等于3才能满足时钟频率要求。
  • 给定更多latency,系统能运行在更高的时钟频率上。

2.3 BIND_STORAGE

#pragma HLS bind_storage variable=<variable> type=<type> [ impl=<value> latency=<int> ]
  • variable=<variable>:定义要将 BIND_STORAGE 编译指示分配到的变量。
  • type=<type>:定义要绑定到指定变量的存储器的类型。受支持的类型包括:fifo、ram_1p、ram_1wnr、ram_2p、ram_s2p、ram_t2p、rom_1p、rom_2p、rom_np。
  • impl=<value>:定义指定存储器类型的实现。受支持的实现包括:bram、bram_ecc、lutram、uram、uram_ecc、srl、memory 和 auto,如下所述。
  • latency=<int>:定义用于绑定类型的默认时延。如下表所示,有效的时延值因指定的 type 和 impl 而异。默认值为 -1,即交由 Vitis HLS 选择时延。

存储类型:

类型

描述

FIFO

FIFOVitis HLS 可判定如何在 RTL 中将其实现,除非指定 -impl 选项。

RAM_1WNR

1 个写入端口和 N 个读取端口的 RAM,内部使用 N bank

RAM_2P

双端口 RAM,允许在某一端口上执行操作,并在另一个端口上执行读写操作。

RAM_S2P

双端口 RAM,允许在某一端口上执行操作,并在另一个端口上执行操作。

RAM_T2P

真正的双端口 RAM,支持在 2 个端口上执行读写操作。

ROM_1P

单端口 ROMVitis HLS 可判定如何在 RTL 中将其实现,除非指定 -impl 选项。

ROM_2P

双端口 ROM

ROM_NP

多端口 ROM

实现类型:

名称

描述

MEMORY

通用存储器,允许 Vivado 工具选择实现。

URAM

UltraRAM 资源

URAM_ECC

ECC UltraRAM

SRL

移位寄存器逻辑资源,Shift Register Look-up Table(移位寄存器查找表)

LUTRAM

分布式 RAM 资源

BRAM

RAM 资源

BRAM_ECC

ECC 的块 RAM

AUTO

Vitis HLS 会自动判定变量的实现。

受支持的存储器类型、实现和时延组合:

操作

实现

Min Latency

Max Latency

FIFO

BRAM

0

0

FIFO

LUTRAM

0

0

FIFO

MEMORY

0

0

FIFO

SRL

0

0

FIFO

URAM

0

0

RAM_1P

AUTO

1

3

RAM_1P

BRAM

1

3

RAM_1P

LUTRAM

1

3

RAM_1P

URAM

1

3

RAM_1WNR

AUTO

1

3

RAM_1WNR

BRAM

1

3

RAM_1WNR

LUTRAM

1

3

RAM_1WNR

URAM

1

3

RAM_2P

AUTO

1

3

RAM_2P

BRAM

1

3

RAM_2P

LUTRAM

1

3

RAM_2P

URAM

1

3

操作

实现

Min Latency

Max Latency

RAM_S2P

BRAM

1

3

RAM_S2P

BRAM_ECC

1

3

RAM_S2P

LUTRAM

1

3

RAM_S2P

URAM

1

3

RAM_S2P

URAM_ECC

1

3

RAM_T2P

BRAM

1

3

RAM_T2P

URAM

1

3

ROM_1P

AUTO

1

3

ROM_1P

BRAM

1

3

ROM_1P

LUTRAM

1

3

ROM_2P

AUTO

1

3

ROM_2P

BRAM

1

3

ROM_2P

LUTRAM

1

3

ROM_NP

BRAM

1

3

ROM_NP

LUTRAM

1

3

2.4 BIND_STORAGE 示例

#pragma HLS bind_storage variable=coeffs type=RAM_1P impl=bram

解释:

指令告诉HLS工具将 coeffs 数组绑定到一个单端口RAM上,并且使用块RAM作为其实现方式。

3. 实例演示

#define BUFFER_SIZE 1024
#define DATA_SIZE 4096// TRIPCOUNT identifier
const unsigned int c_len = DATA_SIZE / BUFFER_SIZE;
const unsigned int c_size = BUFFER_SIZE;extern "C" {
void vadd(const unsigned int* in1, // Read-Only Vector 1const unsigned int* in2, // Read-Only Vector 2unsigned int* out_r,     // Output Resultint size                 // Size in integer) {unsigned int v1_buffer[BUFFER_SIZE];   // Local memory to store vector1unsigned int v2_buffer[BUFFER_SIZE];   // Local memory to store vector2unsigned int vout_buffer[BUFFER_SIZE]; // Local Memory to store result// Using the BIND_OP pragma the user can specify the operator, implementation
// and latency
#pragma HLS BIND_OP variable = v1_buffer op = mul impl = DSP latency = 2
#pragma HLS BIND_OP variable = v2_buffer op = mul impl = DSP latency = 2
#pragma HLS BIND_OP variable = vout_buffer op = add impl = DSP
// Using the BIND STORAGE the used can choose the type, resource and latency
#pragma HLS BIND_STORAGE variable = v1_buffer type = RAM_1P impl = BRAM latency = 2
#pragma HLS BIND_STORAGE variable = v2_buffer type = RAM_1P impl = LUTRAM latency = 2
#pragma HLS BIND_STORAGE variable = vout_buffer type = RAM_1P impl = URAM// Per iteration of this loop perform BUFFER_SIZE vector additionfor (int i = 0; i < size; i += BUFFER_SIZE) {
#pragma HLS LOOP_TRIPCOUNT min = c_len max = c_lenint chunk_size = BUFFER_SIZE;// boundary checksif ((i + BUFFER_SIZE) > size) chunk_size = size - i;// Auto-pipeline is going to apply pipeline to these loopsread1:for (int j = 0; j < chunk_size; j++) {
#pragma HLS LOOP_TRIPCOUNT min = c_size max = c_sizev1_buffer[j] = in1[i + j] * in1[i + j];}read2:for (int j = 0; j < chunk_size; j++) {
#pragma HLS LOOP_TRIPCOUNT min = c_size max = c_sizev2_buffer[j] = in2[i + j] * in2[i + j];}vadd:for (int j = 0; j < chunk_size; j++) {
// As the outer loop is not a perfect loop
#pragma HLS loop_flatten off
#pragma HLS LOOP_TRIPCOUNT min = c_size max = c_size// perform vector additionvout_buffer[j] = v1_buffer[j] + v2_buffer[j];}// burst write the resultwrite:for (int j = 0; j < chunk_size; j++) {
#pragma HLS LOOP_TRIPCOUNT min = c_size max = c_sizeout_r[i + j] = vout_buffer[j];}}
}
}

其中关键的优化指令如下:

// Using the BIND_OP pragma the user can specify the operator, implementation and latency
#pragma HLS BIND_OP variable = v1_buffer    op = mul impl = DSP latency = 2
#pragma HLS BIND_OP variable = v2_buffer    op = mul impl = DSP latency = 2
#pragma HLS BIND_OP variable = vout_buffer op = add impl = DSP


// Using the BIND STORAGE the used can choose the type, resource and latency
#pragma HLS BIND_STORAGE variable = v1_buffer    type = RAM_1P impl = BRAM     latency = 2
#pragma HLS BIND_STORAGE variable = v2_buffer    type = RAM_1P impl = LUTRAM latency = 2
#pragma HLS BIND_STORAGE variable = vout_buffer type = RAM_1P impl = URAM

运行 Vitis HLS 编译器,我们得到如下结果:

================================================================
== Pragma Report
================================================================
* Valid Pragma Syntax
+----------------+----------------------------------------------------------------+-------------------------+
| Type           | Options                                                        | Location                |
+----------------+----------------------------------------------------------------+-------------------------+
| bind_op        | variable = v1_buffer     op = mul    impl = DSP    latency = 2 | src/vadd.cpp:20 in vadd |
| bind_op        | variable = v2_buffer     op = mul    impl = DSP    latency = 2 | src/vadd.cpp:21 in vadd |
| bind_op        | variable = vout_buffer   op = add    impl = DSP                | src/vadd.cpp:22 in vadd |
| bind_storage   | variable = v1_buffer   type = RAM_1P impl = BRAM   latency = 2 | src/vadd.cpp:24 in vadd |
| bind_storage   | variable = v2_buffer   type = RAM_1P impl = LUTRAM latency = 2 | src/vadd.cpp:25 in vadd |
| bind_storage   | variable = vout_buffer type = RAM_1P impl = URAM               | src/vadd.cpp:26 in vadd |
+----------------+----------------------------------------------------------------+-------------------------+

请注意区分,一个变量可以同时使用这两种绑定,例如 v1_buffer 既被指定了op,又被指定了storage,op 绑定和 storage 绑定关注不同的方面。op 绑定关心的是如何执行计算,而storage 绑定关心的是如何存储数据。

4. 总结

这些指令指导了高级综合(HLS)工具在优化指定数组的存储和操作实现时的行为。它们有助于在 FPGA 设计中实现更好的性能和资源利用率。存储类型的选择(BRAM、LUTRAM 或 URAM)以及专用 DSP 资源的使用会影响设计的整体效率。指定的延迟控制了这些操作的时序特性。

这篇关于Vitis HLS 学习笔记--优化指令-BIND_OP_STORAGE的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/927873

相关文章

从原理到实战解析Java Stream 的并行流性能优化

《从原理到实战解析JavaStream的并行流性能优化》本文给大家介绍JavaStream的并行流性能优化:从原理到实战的全攻略,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的... 目录一、并行流的核心原理与适用场景二、性能优化的核心策略1. 合理设置并行度:打破默认阈值2. 避免装箱

Python实战之SEO优化自动化工具开发指南

《Python实战之SEO优化自动化工具开发指南》在数字化营销时代,搜索引擎优化(SEO)已成为网站获取流量的重要手段,本文将带您使用Python开发一套完整的SEO自动化工具,需要的可以了解下... 目录前言项目概述技术栈选择核心模块实现1. 关键词研究模块2. 网站技术seo检测模块3. 内容优化分析模

Java实现复杂查询优化的7个技巧小结

《Java实现复杂查询优化的7个技巧小结》在Java项目中,复杂查询是开发者面临的“硬骨头”,本文将通过7个实战技巧,结合代码示例和性能对比,手把手教你如何让复杂查询变得优雅,大家可以根据需求进行选择... 目录一、复杂查询的痛点:为何你的代码“又臭又长”1.1冗余变量与中间状态1.2重复查询与性能陷阱1.

Python内存优化的实战技巧分享

《Python内存优化的实战技巧分享》Python作为一门解释型语言,虽然在开发效率上有着显著优势,但在执行效率方面往往被诟病,然而,通过合理的内存优化策略,我们可以让Python程序的运行速度提升3... 目录前言python内存管理机制引用计数机制垃圾回收机制内存泄漏的常见原因1. 循环引用2. 全局变

Unity新手入门学习殿堂级知识详细讲解(图文)

《Unity新手入门学习殿堂级知识详细讲解(图文)》Unity是一款跨平台游戏引擎,支持2D/3D及VR/AR开发,核心功能模块包括图形、音频、物理等,通过可视化编辑器与脚本扩展实现开发,项目结构含A... 目录入门概述什么是 UnityUnity引擎基础认知编辑器核心操作Unity 编辑器项目模式分类工程

Python多线程应用中的卡死问题优化方案指南

《Python多线程应用中的卡死问题优化方案指南》在利用Python语言开发某查询软件时,遇到了点击搜索按钮后软件卡死的问题,本文将简单分析一下出现的原因以及对应的优化方案,希望对大家有所帮助... 目录问题描述优化方案1. 网络请求优化2. 多线程架构优化3. 全局异常处理4. 配置管理优化优化效果1.

MySQL中优化CPU使用的详细指南

《MySQL中优化CPU使用的详细指南》优化MySQL的CPU使用可以显著提高数据库的性能和响应时间,本文为大家整理了一些优化CPU使用的方法,大家可以根据需要进行选择... 目录一、优化查询和索引1.1 优化查询语句1.2 创建和优化索引1.3 避免全表扫描二、调整mysql配置参数2.1 调整线程数2.

Python学习笔记之getattr和hasattr用法示例详解

《Python学习笔记之getattr和hasattr用法示例详解》在Python中,hasattr()、getattr()和setattr()是一组内置函数,用于对对象的属性进行操作和查询,这篇文章... 目录1.getattr用法详解1.1 基本作用1.2 示例1.3 原理2.hasattr用法详解2.

深入解析Java NIO在高并发场景下的性能优化实践指南

《深入解析JavaNIO在高并发场景下的性能优化实践指南》随着互联网业务不断演进,对高并发、低延时网络服务的需求日益增长,本文将深入解析JavaNIO在高并发场景下的性能优化方法,希望对大家有所帮助... 目录简介一、技术背景与应用场景二、核心原理深入分析2.1 Selector多路复用2.2 Buffer

SpringBoot利用树形结构优化查询速度

《SpringBoot利用树形结构优化查询速度》这篇文章主要为大家详细介绍了SpringBoot利用树形结构优化查询速度,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一个真实的性能灾难传统方案为什么这么慢N+1查询灾难性能测试数据对比核心解决方案:一次查询 + O(n)算法解决