Vitis HLS 学习笔记--HLS流水线基本用法

2024-05-05 11:04

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

目录

1. 简介

2. 示例

2.1 对内层循环打拍

2.2 对外层循环打拍

2.3 优化数组访问后打拍

3. 总结


1. 简介

本文介绍pipeline的基本用法。pipeline是一种用于提高硬件设计性能的技术。本文介绍了pipeline在累加计算函数中的应用。通过优化内外层循环和数组访问,显著提高了函数的时序性能,实现更高效的硬件设计。

2. 示例

这个程序定义了一个名为func的函数,接受一个长度为20的ap_int类型的数组A,数组中每个元素都是一个长度为5的ap_int类型。函数的目标是计算一个累加值并返回。

函数通过两个嵌套的循环对数组A进行遍历:

  • 外部循环(LOOP_I)遍历数组A的所有元素。
  • 内部循环(LOOP_J)对每个元素执行一个操作。
  • 在内部循环中,数组A的第j个元素与外部循环的迭代次数i相乘,结果累加到一个名为acc的静态ap_int类型变量中。
  • 最终,函数返回累加值acc。

2.1 对内层循环打拍

#include "ap_int.h"ap_int<20> func(ap_int<5> A[20]) {int i, j;static ap_int<20> acc;LOOP_I:for (i = 0; i < 20; i++) {LOOP_J:for (j = 0; j < 20; j++) {
#pragma HLS PIPELINEacc += A[j] * i;}}return acc;
}

C综合后,可以看到时序报告,函数func的Latency=405。循环II=1,Trip Count=400。

+ Performance & Resource Estimates: PS: '+' for module; 'o' for loop; '*' for dataflow+------------------+------+------+---------+-----------+----------+---------+------+----------+------+---------+----------+-----------+-----+|      Modules     | Issue|      | Latency |  Latency  | Iteration|         | Trip |          |      |         |          |           |     ||      & Loops     | Type | Slack| (cycles)|    (ns)   |  Latency | Interval| Count| Pipelined| BRAM |   DSP   |    FF    |    LUT    | URAM|+------------------+------+------+---------+-----------+----------+---------+------+----------+------+---------+----------+-----------+-----+|+ func            |     -|  4.92|      405|  4.050e+03|         -|      406|     -|        no|     -|  1 (~0%)|  68 (~0%)|  171 (~0%)|    -|| o LOOP_I_LOOP_J  |     -|  7.30|      403|  4.030e+03|         5|        1|   400|       yes|     -|        -|         -|          -|    -|+------------------+------+------+---------+-----------+----------+---------+------+----------+------+---------+----------+-----------+-----+

可以理解,两层循环20*20=400,II=1,所以Trip Count=400。符合我们的预期。

2.2 对外层循环打拍

#include "ap_int.h"ap_int<20> func(ap_int<5> A[20]) {int i, j;static ap_int<20> acc;LOOP_I:for (i = 0; i < 20; i++) {
#pragma HLS PIPELINELOOP_J:for (j = 0; j < 20; j++) {acc += A[j] * i;}}return acc;
}

 C综合后,可以看到时序报告,func的Latency=13,II=14。

+ Performance & Resource Estimates: PS: '+' for module; 'o' for loop; '*' for dataflow+--------+------+------+---------+---------+----------+---------+------+----------+------+---------+----------+-----------+-----+| Modules| Issue|      | Latency | Latency | Iteration|         | Trip |          |      |         |          |           |     || & Loops| Type | Slack| (cycles)|   (ns)  |  Latency | Interval| Count| Pipelined| BRAM |   DSP   |    FF    |    LUT    | URAM|+--------+------+------+---------+---------+----------+---------+------+----------+------+---------+----------+-----------+-----+|+ func  |     -|  0.82|       13|  130.000|         -|       14|     -|        no|     -|  1 (~0%)|  93 (~0%)|  444 (~0%)|    -|+--------+------+------+---------+---------+----------+---------+------+----------+------+---------+----------+-----------+-----+

通过观察Schedule可以发现, 数组A被默认绑定为ap_memory,实现形式是双端口ram,每个周期可读取2个元素,共计10个周期读取完毕,额外有4个周期进行了乘法运算和回写。所以II=14。

此结果并不符合预期,理论上,内层循环应该展开,外层循环被流水线打拍,func的Latency=20才对。

尝试使用 ARRAY_PARTITION 优化数组 A 访问。

#include "ap_int.h"ap_int<20> func(ap_int<5> A[20]) {
#pragma HLS ARRAY_PARTITION dim=0 type=complete variable=Aint i, j;static ap_int<20> acc;LOOP_I:for (i = 0; i < 20; i++) {
#pragma HLS PIPELINELOOP_J:for (j = 0; j < 20; j++) {acc += A[j] * i;}}return acc;
}

 C综合后的结果如下:

+ Performance & Resource Estimates: PS: '+' for module; 'o' for loop; '*' for dataflow+--------+------+------+---------+--------+----------+---------+------+----------+------+---------+----------+-----------+-----+| Modules| Issue|      | Latency | Latency| Iteration|         | Trip |          |      |         |          |           |     || & Loops| Type | Slack| (cycles)|  (ns)  |  Latency | Interval| Count| Pipelined| BRAM |   DSP   |    FF    |    LUT    | URAM|+--------+------+------+---------+--------+----------+---------+------+----------+------+---------+----------+-----------+-----+|+ func  |     -|  1.50|        3|  30.000|         -|        4|     -|        no|     -|  1 (~0%)|  24 (~0%)|  278 (~0%)|    -|+--------+------+------+---------+--------+----------+---------+------+----------+------+---------+----------+-----------+-----+

其中II=4,我无法理解。从Schedule Viewer来看,似乎是乘法运算和回写占用了4个周期。

此结果的原因未知。后续研究之后再补充吧。 

2.3 优化数组访问后打拍

#include "ap_int.h"ap_int<20> func(ap_int<5> A[20]) {
#pragma HLS ARRAY_PARTITION dim=0 type=complete variable=Aint i, j;static ap_int<20> acc;#pragma HLS PIPELINE
LOOP_I:for (i = 0; i < 20; i++) {LOOP_J:for (j = 0; j < 20; j++) {acc += A[j] * i;}}return acc;
}

为了最大化榨取并行处理能力,我们做了“最疯狂”的优化:

  • 使用 ARRAY_PARTITION 对数组A进行分区,将其完全分割为独立元素,每个周期可以访问所有元素。
  • PIPELINE 在函数提内,HLS 工具会展开所有循环,即双层循环会在一个周期内完成。
+ Performance & Resource Estimates: PS: '+' for module; 'o' for loop; '*' for dataflow+--------+------+------+---------+--------+----------+---------+------+----------+------+---------+-----------+-----------+-----+| Modules| Issue|      | Latency | Latency| Iteration|         | Trip |          |      |         |           |           |     || & Loops| Type | Slack| (cycles)|  (ns)  |  Latency | Interval| Count| Pipelined| BRAM |   DSP   |     FF    |    LUT    | URAM|+--------+------+------+---------+--------+----------+---------+------+----------+------+---------+-----------+-----------+-----+|+ func  |    II|  1.50|        3|  30.000|         -|        1|     -|       yes|     -|  1 (~0%)|  240 (~0%)|  649 (~0%)|    -|+--------+------+------+---------+--------+----------+---------+------+----------+------+---------+-----------+-----------+-----+

查看C综合结果,符合我们的预期。

 

3. 总结

本文介绍了使用pipeline进行硬件优化的基本方法,并通过示例展示了不同优化方式的性能影响。针对累加计算函数,我们通过内外层循环的pipeline优化和数组访问优化,显著提高了时序性能,从405个周期降至3个周期。这些优化方法可有效应用于其他硬件设计中,提高性能和效率。

这篇关于Vitis HLS 学习笔记--HLS流水线基本用法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/961553

相关文章

C++/类与对象/默认成员函数@构造函数的用法

《C++/类与对象/默认成员函数@构造函数的用法》:本文主要介绍C++/类与对象/默认成员函数@构造函数的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录名词概念默认成员函数构造函数概念函数特征显示构造函数隐式构造函数总结名词概念默认构造函数:不用传参就可以

javascript fetch 用法讲解

《javascriptfetch用法讲解》fetch是一个现代化的JavaScriptAPI,用于发送网络请求并获取资源,它是浏览器提供的全局方法,可以替代传统的XMLHttpRequest,这篇... 目录1. 基本语法1.1 语法1.2 示例:简单 GET 请求2. Response 对象3. 配置请求

MySQL基本查询示例总结

《MySQL基本查询示例总结》:本文主要介绍MySQL基本查询示例总结,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录Create插入替换Retrieve(读取)select(确定列)where条件(确定行)null查询order by语句li

Go 语言中的 Struct Tag 的用法详解

《Go语言中的StructTag的用法详解》在Go语言中,结构体字段标签(StructTag)是一种用于给字段添加元信息(metadata)的机制,常用于序列化(如JSON、XML)、ORM映... 目录一、结构体标签的基本语法二、json:"token"的具体含义三、常见的标签格式变体四、使用示例五、使用

mysql中的group by高级用法详解

《mysql中的groupby高级用法详解》MySQL中的GROUPBY是数据聚合分析的核心功能,主要用于将结果集按指定列分组,并结合聚合函数进行统计计算,本文给大家介绍mysql中的groupby... 目录一、基本语法与核心功能二、基础用法示例1. 单列分组统计2. 多列组合分组3. 与WHERE结合使

MySQL 字符串截取函数及用法详解

《MySQL字符串截取函数及用法详解》在MySQL中,字符串截取是常见的操作,主要用于从字符串中提取特定部分,MySQL提供了多种函数来实现这一功能,包括LEFT()、RIGHT()、SUBST... 目录mysql 字符串截取函数详解RIGHT(str, length):从右侧截取指定长度的字符SUBST

SQL Server中的PIVOT与UNPIVOT用法具体示例详解

《SQLServer中的PIVOT与UNPIVOT用法具体示例详解》这篇文章主要给大家介绍了关于SQLServer中的PIVOT与UNPIVOT用法的具体示例,SQLServer中PIVOT和U... 目录引言一、PIVOT:将行转换为列核心作用语法结构实战示例二、UNPIVOT:将列编程转换为行核心作用语

重新对Java的类加载器的学习方式

《重新对Java的类加载器的学习方式》:本文主要介绍重新对Java的类加载器的学习方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍1.1、简介1.2、符号引用和直接引用1、符号引用2、直接引用3、符号转直接的过程2、加载流程3、类加载的分类3.1、显示

Java中 instanceof 的用法详细介绍

《Java中instanceof的用法详细介绍》在Java中,instanceof是一个二元运算符(类型比较操作符),用于检查一个对象是否是某个特定类、接口的实例,或者是否是其子类的实例,这篇文章... 目录引言基本语法基本作用1. 检查对象是否是指定类的实例2. 检查对象是否是子类的实例3. 检查对象是否

Java中的内部类和常用类用法解读

《Java中的内部类和常用类用法解读》:本文主要介绍Java中的内部类和常用类用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录内部类和常用类内部类成员内部类静态内部类局部内部类匿名内部类常用类Object类包装类String类StringBuffer和Stri