Vitis HLS 学习笔记--矢量数据类型

目录

1. 简介

2. 用法详解

2.1 存储器布局

2.2 示例展示 

2.3 综合报告

3. 总结


1. 简介

在 Vitis HLS 中,矢量数据类型是一种特殊的数据类型,它允许你一次处理多个数据元素,就像一排并排的盒子,每个盒子里都装着一个数据元素。这种方式非常适合于同时执行多个相同的操作,这就是所谓的 SIMD(单指令多数据)操作。

矢量数据类型用法

#include <hls_vector.h>
hls::vector<T,N> aVec;

在代码中,#include <hls_vector.h> 这行告诉程序,我们要使用 Vitis HLS 提供的矢量数据类型。hls::vector<T,N> aVec; 这行代码声明了一个矢量变量 aVec。这里的 T 表示数据的类型,比如整数或浮点数,而 N 表示这个矢量中有多少个元素。

当 T 的位宽(即每个数据元素占用的位数)和 N(矢量中元素的数量)都是 2 的幂(比如 2, 4, 8, 16…)时,这个矢量数据类型就能以最高效的方式运行,因为计算机处理这样的数字时更加高效。

打个简单的比方,就像你在超市买东西时,如果你有一个足够大的购物车,你可以一次性把所有东西放进去,然后一起结账,这样就比每次只买一个东西要快得多。在 Vitis HLS 中,矢量数据类型就像是一个大购物车,让你能够一次性处理很多数据,提高效率。

2. 用法详解

2.1 存储器布局

hls::vector<T,N> aVec;

这个数据结构被定义为 hls::vector<T,N>,其中 T 表示矢量中元素的类型,而 N 表示矢量中元素的数量。

存储器连续性:矢量中的元素在内存中是连续存储的。这意味着,如果你知道了矢量中第一个元素的内存地址,就可以通过这个地址和元素的索引(乘以元素的大小)来计算出任何一个元素的内存地址。

存储大小:矢量的总大小(以字节为单位)是元素类型大小 sizeof(T) 与元素数量 N 的乘积。这是因为所有元素都紧密地排列在一起,没有任何间隙。

对齐要求:矢量的对齐要求是其总大小的最大2的幂值。对齐是指数据的起始内存地址是某个数(通常是2的幂)的倍数。这有助于提高内存访问的效率。特别地,当 N 和 sizeof(T) 都是2的幂时,矢量应该对齐到其总大小。这意味着如果你有一个类型大小为4字节(2的2次幂),包含8个元素(2的3次幂)的矢量,那么这个矢量的总大小是32字节(2的5次幂),它应该对齐到32字节。

这种设计与许多计算机架构上的矢量实现相匹配,因为它们通常也有类似的连续存储和对齐要求。这样的设计可以使得数据结构在这些架构上运行得更有效率。

2.2 示例展示 

#include "hls_vector.h"
#include <ap_int.h>

// Each vector will be 64 bytes (16 x 4 bytes)
typedef hls::vector<float, 16> float16;

template <int N, typename T> void load(T (&out)[N], const T* in) {
#pragma HLS INLINE off
    for (int i = 0; i < N; ++i) {
#pragma HLS pipeline
        out[i] = in[i];
    }
}

template <int N, typename T> void store(T* out, const T (&in)[N]) {
#pragma HLS INLINE off
    for (int i = 0; i < N; ++i) {
#pragma HLS pipeline
        out[i] = in[i];
    }
}

template <int N, typename T, typename S>
void compute(T (&res)[N], const S (&lhs)[N], const S (&rhs)[N]) {
#pragma HLS INLINE off
    for (int i = 0; i < N; ++i) {
#pragma HLS pipeline
        res[i] = lhs[i] + rhs[i];
    }
}

extern "C" void example(float16* res, const float16* lhs, const float16* rhs,
                        int n) {
#pragma HLS INTERFACE m_axi port = lhs offset = slave bundle = gmem0 depth = 32
#pragma HLS INTERFACE m_axi port = rhs offset = slave bundle = gmem1 depth = 32
#pragma HLS INTERFACE m_axi port = res offset = slave bundle = gmem0 depth = 32

    for (int i = 0; i < n; ++i) {
        float16 lhs_buf[32];
        float16 rhs_buf[32];
        float16 res_buf[32];

#pragma HLS DATAFLOW
        load(lhs_buf, lhs);
        load(rhs_buf, rhs);
        compute(res_buf, lhs_buf, rhs_buf);
        store(res, res_buf);
    }
}

这段代码中,定义了一种特定的向量类型 float16(由16个浮点数组成,总共64字节),并实现了几个基本操作:从内存加载数据 (load)、将数据存储回内存 (store) 以及执行向量之间的加法 (compute)。

类型定义

  • float16:定义了一个包含16个float元素的向量,每个float占用4字节,因此整个float16占用64字节内存。

函数模板

  • load:从指定的输入指针位置(in)加载N个元素到数组(out)中。这个函数通过循环实现,并使用#pragma HLS pipeline来指示HLS工具将循环的每次迭代实现为一个流水线步骤,以提高执行速度。
  • store:将数组(in)中的N个元素存储到指定的输出指针位置(out)。同样使用#pragma HLS pipeline来优化性能。
  • compute:对两个输入数组(lhs和rhs)进行逐元素加法,将结果存储在数组(res)中。再次使用#pragma HLS pipeline实现流水线加速。

主函数 example

  • 功能:这个函数执行一系列操作,对于给定数量n的float16类型向量(lhs和rhs),它逐个处理这些向量,执行加法运算,并将结果存储在res数组中。
  • 接口指令:#pragma HLS INTERFACE指令定义了函数参数与外部世界的接口方式,这里使用m_axi接口,它是一种适用于内存访问的通用接口。offset = slave指定这些接口作为从设备端口,bundle参数定义了不同的接口被分配到的AXI总线接口,depth参数指定了接口期望的数据深度。
  • 内部缓冲区:函数内部定义了三个float16类型的数组作为缓冲区(lhs_buf、rhs_buf、res_buf),用于存储加载的数据、临时计算结果和最终结果。
  • 数据流:通过#pragma HLS DATAFLOW指令,函数内部的操作被组织成一个数据流图,允许这些操作并行执行,从而提高整体性能。

2.3 综合报告

================================================================
== SW I/O Information
================================================================
* Top Function Arguments
+----------+-----------+---------------------------+
| Argument | Direction | Datatype                  |
+----------+-----------+---------------------------+
| res      | inout     | vector<float, 16>*        |
| lhs      | inout     | vector<float, 16> const * |
| rhs      | in        | vector<float, 16> const * |
| n        | in        | int                       |
+----------+-----------+---------------------------+

 通过 Top Function Arguments 报告,可以查看矢量数据类型的具体信息。

================================================================
== HW Interfaces
================================================================
* M_AXI
+-------------+------------+---------------+---------+--------+----------+-----------+--------------+--------------+-------------+-------------+
| Interface   | Data Width | Address Width | Latency | Offset | Register | Max Widen | Max Read     | Max Write    | Num Read    | Num Write   |
|             | (SW->HW)   |               |         |        |          | Bitwidth  | Burst Length | Burst Length | Outstanding | Outstanding |
+-------------+------------+---------------+---------+--------+----------+-----------+--------------+--------------+-------------+-------------+
| m_axi_gmem0 | 512 -> 512 | 64            | 64      | slave  | 0        | 512       | 16           | 16           | 16          | 16          |
| m_axi_gmem1 | 512 -> 512 | 64            | 64      | slave  | 0        | 512       | 16           | 16           | 16          | 16          |
+-------------+------------+---------------+---------+--------+----------+-----------+--------------+--------------+-------------+-------------+

向量类型 float16(由16个浮点数组成,总共64字节),64*8=512,符合综合报告。

3. 总结

在 Vitis HLS 中,矢量数据类型提供了一种高效的数据处理方式,允许开发者利用 SIMD 操作一次性处理多个数据元素。通过使用 hls::vector<T,N>,开发者可以创建一个由 N 个类型为 T 的元素组成的矢量。这种数据结构在内存中连续存储,且当元素类型和数量都是 2 的幂时,对齐到其总大小,可以实现最优的内存访问效率。

示例代码展示了如何定义矢量类型 float16,以及如何实现加载、存储和计算操作。这些操作通过 HLS 指令优化,以流水线的形式执行,从而提高性能。主函数 example 则展示了如何将这些操作组织成数据流,以并行方式执行,进一步提升效率。

综合报告部分突出了矢量数据类型在硬件接口中的配置,如 M_AXI 接口的数据宽度和地址宽度,确保了与向量类型的内存布局相匹配。这种设计使得 Vitis HLS 中的矢量数据类型不仅在软件层面上高效,也在硬件层面上与现代计算机架构紧密对接,实现了数据处理的高效率和高性能。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

短视频矩阵源码---矩阵托管1000个账号如何正规开发规则实现

一、短视频矩阵源码开发实现规则&#xff1a; 1.首先是确保各个官方平台api接口的稳定性&#xff0c;一定要是各个平台正规的api 2.其次是保证服务器运行&#xff0c;带宽保证能够并行&#xff0c;目前我们这边用的是源码所需服务器配置&#xff1a;规格:最低8核16G2、硬盘:系…

易舟云财务软件:引领财务数字化转型的新篇章

在数字化浪潮的推动下&#xff0c;财务软件已经成为企业财务管理不可或缺的工具。而易舟云财务软件&#xff0c;作为一款深受用户喜爱的财务管理系统&#xff0c;正引领着财务数字化转型的新篇章。 财务软件行业背景与易舟云的定位 财务软件行业正经历着前所未有的变革。随着《…

视频行人搜索 (Person Search in Videos)

文章目录 视频行人搜索 (Person Search in Videos)图像行人搜索存在问题Video PS 定义MTA-PS数据集First person search dataset in videosComplicated ambient conditions and realistic monitoring scenariosPrivacy insensitivity 方法 视频行人搜索 (Person Search in Vide…

数字芯片——时钟与复位

关于此次章节我想要探讨的问题是门控时钟的处理&#xff08;Clock Gating Methodology&#xff09;和时钟复位策略。在低功耗设计中&#xff0c;门控时钟是结构最简洁&#xff0c;最容易实现的电路结构。如上期所讲的&#xff0c;一个控制信号和时钟逻辑与在一起输出的信号作用…

万界星空科技定制化MES系统,实现数字化生产

一、MES生产管理系统强调三个方面&#xff1a; 1、MES是对整个车间制造过程的优化&#xff0c;而不是单一的解决某个生产瓶颈。 2、MES必须提供实时收集生产过程中数据的功能&#xff0c;并作出相应的分析和处理。 3、MES需要与计划层和控制层进行信息交互&#xff0c;通过企业…

程序员,真有不变的技术和稳定的工作吗?

在程序员这个充满变化和创新的领域&#xff0c;很多人追求“稳定”的工作&#xff0c;认为找到一个合适的公司和岗位就能安心一辈子。然而&#xff0c;技术的快速更新迭代和市场需求的不断变化&#xff0c;使得真正的稳定变得越来越难以捉摸。作为程序员&#xff0c;我们需要反…

C# Winform内嵌窗体(在主窗体上显示子窗体)

在开发Winform项目中&#xff0c;经常会要切换不同的窗体。通常程序都有一个主窗体&#xff0c;在切换窗体时往往需要关闭其他子窗体&#xff0c;这个实例就来介绍MDI主窗体内嵌子窗体的实现方法。 MDI主窗体要设置一个比较重要的属性&#xff0c;IsMdiContainertrue。子窗体的…

【云原生】创建harbor私有仓库及使用aliyun个人仓库

1.安装docker #删除已有dockersystemctl stop docker yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine #安装docker yum install -y docker-ce-20.10.1…

NLP中的Tokenizer分词器的概念与实现

Tokenizer 在开始学习 NLP 相关知识之前&#xff0c;先要学习一个叫 Tokenizer 的概念&#xff0c;这可谓是所有 NLP 模型开始训练前需要做的一个步骤&#xff0c;那么 Tokenizer 是什么&#xff1f; 在计算机处理一行语句的时候&#xff0c;我们给其输入一个 String&#xff…

Android Media Framework(五)Tunnel Mode

本篇将聚焦Android Tunnel Mode&#xff0c;详细解析组件之间隧道连接过程、数据传递过程、组件销毁过程。通过阅读本篇内容&#xff0c;我们应能对tunneled组件的连接过程和buffer分配过程有所了解。 1、Tunnel Mode介绍 IL Spec详细描述了Tunnel Component的实现方式&#x…

【ArcGISProSDK】OpenItemDialog打开文件对话框

打开单个文件 效果 代码 public async void OpenFunction() {// 获取默认数据库var gdbPath Project.Current.DefaultGeodatabasePath;OpenItemDialog openItemDialog new OpenItemDialog() { Title "打开要素文件",InitialLocation gdbPath,Filter ItemFilte…

Linux 性能优化实战

文章目录 33 | 关于 Linux 网络&#xff0c;你必须知道这些&#xff08;上&#xff09;设计高并发架构需要考虑什么&#xff1f;如何理解分布式&#xff1f;如何理解云计算&#xff1f;如何理解微服务&#xff1f;TCP/IP网络分层模型是什么&#xff1f;每一层的功能是什么&…

矩阵练习2

48.旋转图像 规律&#xff1a; 对于矩阵中第 i行的第 j 个元素&#xff0c;在旋转后&#xff0c;它出现在倒数第i 列的第 j 个位置。 matrix[col][n−row−1]matrix[row][col] 可以使用辅助数组&#xff0c;如果不想使用额外的内存&#xff0c;可以用一个临时变量 。 还可以通…

STM32项目分享:智能窗帘系统

目录 一、前言 二、项目简介 1.功能详解 2.主要器件 三、原理图设计 四、PCB硬件设计 1.PCB图 2.PCB板打样焊接图 五、程序设计 六、实验效果 七、资料内容 项目分享 一、前言 项目成品图片&#xff1a; 哔哩哔哩视频链接&#xff1a; https://www.bilibili.c…

基于VLC可见光通信的室内光通信信道信噪比分析matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ..................................................................... % 接收功率计算Pr …

使用spark基于出租车GPS数据实现车辆数量统计以及北京每个城区的车辆位置点数分析

使用spark基于出租车GPS数据实现车辆数量统计以及北京每个城区的车辆位置点数分析 本文将介绍如何使用pyspark以及scala实现的spark分析出租车GPS数据&#xff0c;具体来说&#xff0c;我们将计算每个北京城区内的车辆位置点数&#xff0c;以及统计出租车的数量。我们将使用两…

Vue 3与ESLint、Prettier:构建规范化的前端开发环境

title: Vue 3与ESLint、Prettier&#xff1a;构建规范化的前端开发环境 date: 2024/6/11 updated: 2024/6/11 publisher: cmdragon excerpt: 这篇文章介绍了如何在Vue 3项目中配置ESLint和Prettier以统一代码风格&#xff0c;实现代码规范性与可读性的提升。通过设置规则、解…

49、Flink 的数据源的 SplitReader API 详解

SplitReader API a&#xff09;概述 核心的 SourceReader API 是完全异步的&#xff0c;但实际上&#xff0c;大多数 Sources 都会使用阻塞的操作&#xff0c;例如客户端&#xff08;如 KafkaConsumer&#xff09;的 poll() 阻塞调用&#xff0c;或者分布式文件系统&#xff…

商业智能(BI)期末复习

商业智能&#xff08;BI&#xff09;期末复习 商业智能&#xff08;BI&#xff09;期末复习 2024/06/17 13:30-15:00 1.工作簿包含工作表 2.tableau是一款轻型BI工具 3.敏捷BI成本比较低 因为可以不建立数据仓库 4.敏捷BI的能带来更高的质量系统 是在用户监督下建立起来的 …

Python易错点总结

目录 多分支选择结构 嵌套选择 用match模式识别 match与if的对比 案例&#xff1a;闰年判断 三角形的判断 用whlie循环 高斯求和 死循环 用for循环 ​编辑continue​编辑 whlie与else结合 pass 序列 列表&#xff08;有序&#xff09; 元组&#xff08;有序&…