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

news2024/11/17 20:20:37

目录

1. ARRAY_PARTITION 概述

2. 语法解析

2.1 参数解释

2.1.1 variable

2.1.2 type

2.1.3 factor

2.1.4 dim

2.2 典型示例

2.2.1 dim=1

2.2.2 dim=2

2.2.3 dim=0

3. 实例演示

4. 总结


1. ARRAY_PARTITION 概述

ARRAY_PARTITION 指令中非常重要,它用于优化数组的存储和访问。该指令可以将一个大数组分割成多个小数组,以提高并行处理能力和减少访问延迟。

其实这个过程类比到RTL种,就是手动分配如下数组:

reg [数据位宽-1:0] my_array [维度2:0][维度1:0];

HLS 提供了一个更高级的抽象层次,允许我们在不需要关心将 my_array 分解为多少个子数组以优化访问时序的情况下进行操作。它为数组分割的快速分析和实施提供了一种极为便捷的方法。

2. 语法解析

#pragma HLS array_partition variable=<name> type=<type> factor=<int> dim=<int>

2.1 参数解释

2.1.1 variable

必要实参,用于指定要分区的阵列变量。

2.1.2 type

指定分区类型,可选。默认类型为 complete。支持以下类型:

  • cyclic:循环分区会通过交织来自原始阵列的元素来创建更小的阵列。该阵列按循环进行分区,具体方式是在每个新阵列中放入一个元素,然后回到第一个阵列以重复该循环直至阵列完全完成分区为止。例如,如果使用 factor=3:
    • 向第 1 个新阵列分配元素 0
    • 向第 2 个新阵列分配元素 1
    • 向第 3 个新阵列分配元素 2
    • 向第 4 个新阵列分配元素 3
  • block:块分区会从原始阵列的连续块创建更小阵列。这样可将阵列有效分区为 N 个相等的块,其中 N 为 factor= 实参定义的整数。
  • complete:完全分区可将阵列分解为多个独立元素。对于一维阵列,这对应于将存储器解析为独立寄存器。这是默认 <type>。

2.1.3 factor

指定要创建的更小的阵列数量。

仅对于 block 和 cyclic 型分区生效!

2.1.4 dim

指定要分区的多维阵列的维度。针对含 <N> 维的阵列,指定范围介于 0 到 <N> 之间的整数:

  • 如果使用 0 值,则使用指定的类型和因子选项对多维阵列的所有维度进行分区。
  • 任意非零值均表示只对指定维度进行分区。例如,如果使用的值为 1,则仅对第 1 个维度进行分区。

2.2 典型示例

complete类型比较多见,故选择此类型进行分析。

int l_A[2][5];
#pragma HLS ARRAY_PARTITION variable=l_A type=complete dim=?

对于l_A[2][5],其元素分布如下:

l_A[0][0]

l_A[0][1]

l_A[0][2]

l_A[0][3]

l_A[0][4]

l_A[1][0]

l_A[1][1]

l_A[1][2]

l_A[1][3]

l_A[1][4]

2.2.1 dim=1

第 1 个维度进行分区,相当于将l_A[2][5]拆分成两个2元素数组。

它们分别存储在2个 ram_1p 的存储器中。

可以同时访问所有l_A[0][x]和l_A[1][x]。

该分区方法,每个时钟周期可以读取两个数据。

2.2.2 dim=2

第 1 个维度进行分区,相当于将l_A[2][5]拆分成两个5元素数组。

它们分别存储在5个 ram_1p 的存储器种。

可以同时访问所有l_A[x][0]、l_A[x][1]、l_A[x][2]、l_A[x][3]、l_A[x][4]。

该分区方法,每个时钟周期可以读取5个数据。

2.2.3 dim=0

当dim=0时,表示对整个数组进行完全分区,不考虑具体的维度。这意味着数组的每个元素都将被单独存储,完全独立地占用资源。对于l_A[2][5],这将导致所有10个元素都被独立存储,每个元素可以被单独访问,这最大化了并行访问能力,但也大量占用资源。

3. 实例演示

#include <stdio.h>
#include <string.h>

#define MAX_SIZE 16

const unsigned int c_dim = MAX_SIZE;

extern "C" {
void matmul(int* in1, int* in2, int* out_r, int size, int rep_count) {
    // Local buffers to hold input data
    int A[MAX_SIZE][MAX_SIZE];
    int B[MAX_SIZE][MAX_SIZE];
    int C[MAX_SIZE][MAX_SIZE];
    int temp_sum[MAX_SIZE];

// Read data from global memory and write into local buffer for in1
readA:
    for (int itr = 0, i = 0, j = 0; itr < size * size; itr++, j++) {
#pragma HLS LOOP_TRIPCOUNT min = c_dim* c_dim max = c_dim * c_dim
        if (j == size) {
            j = 0;
            i++;
        }
        A[i][j] = in1[itr];
    }

// Read data from global memory and write into local buffer for in2
readB:
    for (int itr = 0, i = 0, j = 0; itr < size * size; itr++, j++) {
#pragma HLS LOOP_TRIPCOUNT min = c_dim* c_dim max = c_dim * c_dim
        if (j == size) {
            j = 0;
            i++;
        }
        B[i][j] = in2[itr];
    }

// Calculate matrix multiplication using local data buffer based on input size,
// and write results into C
count_loop:
    for (int i = 0; i < rep_count; i++) {
    nopart1:
        for (int row = 0; row < size; row++) {
#pragma HLS LOOP_TRIPCOUNT min = c_dim max = c_dim
        nopart2:
            for (int col = 0; col < size; col++) {
#pragma HLS LOOP_TRIPCOUNT min = c_dim max = c_dim
            nopart3:
                for (int j = 0; j < MAX_SIZE; j++) {
#pragma HLS LOOP_TRIPCOUNT min = c_dim max = c_dim
                    int result = (col == 0) ? 0 : temp_sum[j];
                    result += A[row][col] * B[col][j];
                    temp_sum[j] = result;
                    if (col == size - 1) C[row][j] = result;
                }
            }
        }
    }

// Write results from local buffer to global memory for out
writeC:
    for (int itr = 0, i = 0, j = 0; itr < size * size; itr++, j++) {
#pragma HLS LOOP_TRIPCOUNT min = c_dim* c_dim max = c_dim * c_dim
        if (j == size) {
            j = 0;
            i++;
        }
        out_r[itr] = C[i][j];
    }
}
}

添加这几行指令:

#pragma HLS ARRAY_PARTITION variable = B dim = 2 complete
#pragma HLS ARRAY_PARTITION variable = C dim = 2 complete
#pragma HLS ARRAY_PARTITION variable = temp_sum dim = 1 complete

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

================================================================
== Bind Storage Report
================================================================
+--------------------+------+------+--------+----------+---------+------+---------+
| Name               | BRAM | URAM | Pragma | Variable | Storage | Impl | Latency |
+--------------------+------+------+--------+----------+---------+------+---------+
| + matmul_partition | 1    | 0    |        |          |         |      |         |
|   A_U              | 2    | -    |        | A        | ram_1p  | auto | 1       |
|   B_U              | -    | -    |        | B        | ram_1p  | auto | 1       |
|   B_1_U            | -    | -    |        | B_1      | ram_1p  | auto | 1       |
|   B_2_U            | -    | -    |        | B_2      | ram_1p  | auto | 1       |
|   B_3_U            | -    | -    |        | B_3      | ram_1p  | auto | 1       |
|   B_4_U            | -    | -    |        | B_4      | ram_1p  | auto | 1       |
|   B_5_U            | -    | -    |        | B_5      | ram_1p  | auto | 1       |
|   B_6_U            | -    | -    |        | B_6      | ram_1p  | auto | 1       |
|   B_7_U            | -    | -    |        | B_7      | ram_1p  | auto | 1       |
|   B_8_U            | -    | -    |        | B_8      | ram_1p  | auto | 1       |
|   B_9_U            | -    | -    |        | B_9      | ram_1p  | auto | 1       |
|   B_10_U           | -    | -    |        | B_10     | ram_1p  | auto | 1       |
|   B_11_U           | -    | -    |        | B_11     | ram_1p  | auto | 1       |
|   B_12_U           | -    | -    |        | B_12     | ram_1p  | auto | 1       |
|   B_13_U           | -    | -    |        | B_13     | ram_1p  | auto | 1       |
|   B_14_U           | -    | -    |        | B_14     | ram_1p  | auto | 1       |
|   B_15_U           | -    | -    |        | B_15     | ram_1p  | auto | 1       |
|   C_U              | -    | -    |        | C        | ram_1p  | auto | 1       |
|   C_1_U            | -    | -    |        | C_1      | ram_1p  | auto | 1       |
|   C_2_U            | -    | -    |        | C_2      | ram_1p  | auto | 1       |
|   C_3_U            | -    | -    |        | C_3      | ram_1p  | auto | 1       |
|   C_4_U            | -    | -    |        | C_4      | ram_1p  | auto | 1       |
|   C_5_U            | -    | -    |        | C_5      | ram_1p  | auto | 1       |
|   C_6_U            | -    | -    |        | C_6      | ram_1p  | auto | 1       |
|   C_7_U            | -    | -    |        | C_7      | ram_1p  | auto | 1       |
|   C_8_U            | -    | -    |        | C_8      | ram_1p  | auto | 1       |
|   C_9_U            | -    | -    |        | C_9      | ram_1p  | auto | 1       |
|   C_10_U           | -    | -    |        | C_10     | ram_1p  | auto | 1       |
|   C_11_U           | -    | -    |        | C_11     | ram_1p  | auto | 1       |
|   C_12_U           | -    | -    |        | C_12     | ram_1p  | auto | 1       |
|   C_13_U           | -    | -    |        | C_13     | ram_1p  | auto | 1       |
|   C_14_U           | -    | -    |        | C_14     | ram_1p  | auto | 1       |
|   C_15_U           | -    | -    |        | C_15     | ram_1p  | auto | 1       |
+--------------------+------+------+--------+----------+---------+------+---------+

数组A未指定特定分区,因此将整体存储于单个ram_1p存储器中。而数组B与数组C经过特定设置,按照dim=2的维度被分割为16个区块(即16个ramp_1p存储器),这意味着数组B和数组C能够并行读取16个数据项。此举显著提升了程序处理的吞吐率。

4. 总结

ARRAY_PARTITION指令是高层次综合中一个强大的工具,它可以帮助设计者在保证性能的同时,更有效地利用硬件资源。合理的数组分区可以在不牺牲性能的前提下,优化硬件资源的使用,尤其是在资源受限的设计中。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

银河麒麟redis安装

一.编译和安装Redis wget http://download.redis.io/releases/redis-4.0.9.tar.gz 执行如下命令&#xff0c;解压包。 tar -zxvf redis-4.0.9.tar.gz 执行如下命令&#xff0c;进入deps目录 cd redis-4.0.9/deps 执行如下命令&#xff0c;编译Redis依赖库。 make -j4 hiredis l…

民航电子数据库:CAEMigrator迁移工具

目录 一、场景二、迁移步骤 一、场景 1、对接民航电子数据库 2、需要将mysql数据库迁移到民航电子数据库 3、使用CAEMigrator迁移工具 二、迁移步骤

VMware 15 虚拟机网络遇到的问题

剧情提要 通过Cent os7 的镜像文件&#xff0c;创建了一个虚拟机A&#xff08;后面简称A&#xff09;&#xff0c;事后发现&#xff0c;宿主机无法ping通A 在虚拟机中通过IP a 看到的IP信息也没有只管的ip信息如图 然后执行&#xff0c;宿主机才能访问A。 sudo dhclient ens…

MySQL 基础语法(2)

文章目录 创建表查看表修改表表数据插入 本文为表结构相关的基础语言库相关的基础语句 创建表 CREATE TABLE table_name ( field1 datatype comment xxx, field2 datatype, field3 datatype ) character set 字符集 collate 校验规则 engine 存储引擎;CREATE TABLE&#xff1…

白蚁自动化监测系统解放方案

一、系统介绍 白蚁自动化监测系统是基于物联网的各项白蚁监测点数据的采集形成智能控制系统。提供白蚁实时预警及解决方案&#xff0c;真正实现区域内白蚁种群消灭。白蚁入侵&#xff0c;系统第一时间自动报警&#xff0c;显示入侵位置&#xff0c;实现抓获白蚁于现场的关键环…

算法库应用-有序单链表插入节点

学习源头: 模仿贺利坚老师单链表排序文章浏览阅读5.9k次。  本文针对数据结构基础系列网络课程(2)&#xff1a;线性表中第11课时单链表应用举例。例&#xff1a;拆分单链表 &#xff08;linklist.h是单链表“算法库”中的头文件&#xff0c;详情单击链接…&#xff09;//本程…

JS 分片任务的高阶函数封装

前言 在我们的实际业务开发场景中&#xff0c;有时候我们会遇到渲染大量元素的场景&#xff0c;往往这些操作会使页面卡顿&#xff0c;给用户带来非常不好的体验&#xff0c;这时候我们就需要给任务分片执行。 场景复现 我们看一段代码&#xff1a; <!DOCTYPE html> &l…

P2P面试题

1&#xff09;描述一下你的项目流程以及你在项目中的职责&#xff1f; 一个借款产品的发布&#xff0c;投资人购买&#xff0c;借款人还款的一个业务流程&#xff0c;我主要负责测注册&#xff0c;登录&#xff0c;投资理财这三个模块 2&#xff09;你是怎么测试投资模块的&am…

T1级,生产环境事故—Shell脚本一键备份K8s的YAML文件

大家好&#xff0c;我叫秋意零。 最近对公司进行日常运维工作时&#xff0c;出现了一个 T1 级别事故。导致公司的“酒云网”APP的无法使用。我和我领导一起搞了一个多小时&#xff0c;业务也停了一个多小时。 起因是&#xff1a;我的部门直系领导&#xff0c;叫我**删除一个 …

vcruntime140.dll文件丢失的解决办法,为什么导致vcruntime140.dll文件丢失

废话少说&#xff0c;今天这篇文章直接和大家聊聊vcruntime140.dll文件丢失的解决办法&#xff0c;同时给大家分析vcruntime140.dll文件为什么会导致文件丢失。一起来看看吧。 vcruntime140.dll文件缺失的可能原因 A. 文件损坏或删除&#xff1a;vcruntime140.dll文件可能会…

《人工智能》大作业反馈

0 写在前面 春学期带了一门很有意思的课《人工智能与机器学习》&#xff0c;在学期初就在构思怎么才能把这门课上好&#xff0c;怎么才能让一群土木大类专业的小孩对人工智能这个领域感兴趣&#xff0c;怎么才能让他们将这个专业与自己专业结合起来。我对自己的要求就是希望自…

【C++类和对象】初始化列表与隐式类型转换

&#x1f49e;&#x1f49e; 前言 hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#x…

Canal1--搭建Canal监听数据库变化

1.安装mysql 默认安装了mysql&#xff08;版本8.0.x&#xff09;&#xff1b; 新创建用户 -- 创建用户 用户名&#xff1a;canal 密码&#xff1a;Canal123456 create user canal% identified by Canal123456;授权 grant SELECT, REPLICATION SLAVE, REPLICATION CLIENT on…

使用AOP切面做防止用户重复提交功能

在我们的项目中&#xff0c;需要考虑到有时候因为网络原因或者其他原因用户对同一个接口进行同一批数据的重复性操作&#xff0c;如果不做这样的处理很可能会在数据库中添加多条同样的数据。 我们可以通过使用aop来解决这样的问题&#xff0c;接下来看看具体怎么做吧~ 自定义…

c语言中,数组取地址的书写格式

数组取地址 为了更好的区分数组取地址时的情况&#xff0c;我们建立两个数组&#xff0c;arr1一维数组和arr2二维数组&#xff0c;用printf函数来打印出每个例子arr1和arr2的地址&#xff0c;这样可以更加直观的区分出来。 首先我们看到第一组打印&#xff0c;可以看到若是直接…

Python | Leetcode Python题解之第37题解数独

题目&#xff1a; 题解&#xff1a; class Solution:def solveSudoku(self, board: List[List[str]]) -> None:def dfs(pos: int):nonlocal validif pos len(spaces):valid Truereturni, j spaces[pos]for digit in range(9):if line[i][digit] column[j][digit] bloc…

jmeter 指定QPS压测接口

文章目录 jmeter 指定QPS压测接口更换语言为中文创建测试任务新建线程组右键线程组&#xff0c;新建http request&#xff0c;填写要你要压测的接口地址、参数如果需要自定义请求头&#xff0c;添加一个Http头信息管理器要查看结果和QPS统计数据&#xff0c;给上门的http请求添…

JVM虚拟机(十二)ParallelGC、CMS、G1垃圾收集器的 GC 日志解析

目录 一、如何开启 GC 日志&#xff1f;二、GC 日志分析2.1 PSPO 日志分析2.2 ParNewCMS 日志分析2.3 G1 日志分析 三、GC 发生的原因3.1 Allocation Failure&#xff1a;新生代空间不足&#xff0c;触发 Minor GC3.2 Metadata GC Threshold&#xff1a;元数据&#xff08;方法…

poll实现echo服务器的并发

poll实现echo服务器的并发 代码实现 #include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <stdlib.h> #include <arpa/inet.h> #include <sys/time.h> #include <unistd.h> #…

c++的智能指针(5) -- weak_ptr

概述 我们在使用shared_ptr会出现以下的问题&#xff0c;会导致内存泄露。 代码1: 类内指针循环指向 #include <iostream> #include <memory>class B;class A { public:A() {std::cout << "Construct" << std::endl;}~A() {std::cout <…