Vitis HLS 学习笔记--控制驱动TLP-处理deadlock

目录

1. 简介

2. 代码解析

2.1 HLS kernel代码

2.2 查看接口报告

2.3 TestBench

2.4 Dataflow 报告

3. Takeaways

4. 总结


1. 简介

本文是对《Hardware Acceleration Tutorials: FIFO Sizing for Performance and Avoiding Deadlocks》实验内容的详细解释。

首先需要了解,鉴于数据流优化具有动态特性,且不同并行任务的执行速度各不相同,设置不当的数据流通道可能会引发性能下降或死锁。

数据流通道有两种:FIFO 和 PIPO。可以由工具推断,或者用户自行创建。

FIFO:

  • Streams (including hls::streams and streamed arrays),用户创建。
  • Scalar propagation FIFOs,工具推断。
  • Streams of blocks,用户创建。

每个通道都有自己的握手信号。因为:

  • 它们的读写操作是被调度的。
  • 它们的读/写信号分别由流水线控制或有限状态机(FSM)单独驱动。
  • 它们的full_n/empty_n信号直接使流水线的单个迭代或FSM的状态暂停。

PIPO:

  • PIPO,用户创建。
  • Task Level FIFOs (TLF),工具推断。
  • Input and output ports to the upper level,用户创建。

其中,Task Level FIFOs (TLF) 是标量(scalar)FIFO,其连接到生产者的“done”握手信号以进行写入,并连接到消费者的“start”握手信号以进行读取。这些类型的FIFO是由工具自动推断的。由于底层同步机制的缘故,它们被视为类PIPO。

这些通道应该被视为“使用ap_ctrl_chain握手的通道”,因为:

  • 它们的写入和读取操作不会被调度。它们隐式地与进程的“done”握手或“start”握手相关联。
  • 它们的写入和读取信号分别连接到ap_done和ap_ready。
  • 它们的full_n和empty_n分别连接到ap_continue和ap_start。

总结一下,在分析存储深度、性能、死锁等方面,真正需要关系的是:

  • 通道是否拥有自己的握手机制(FIFOs)。它们的访问在其进程执行期间被分散开来。例如,你可以在管道的第一个II之外读取一个FIFO,或者甚至在数据流网络的最后一个过程中读取。
  • 通道是否通过ap_ctrl_chain进行握手(PIPOs)。它们的读取必须在管道的第一个II中,或者在数据流网络的第一个“层级”的过程中进行,类似地,它们的写入必须在最后一个II或在最后一个“层级”中进行。
  • 另一个区别基于一次操作中传输的数据量,这对于资源分析比对性能分析更为重要:对于PIPOs来说是数组,对于流来说是块流、标量流,对于标量传播FIFOs和任务级FIFOs来说是标量。

2. 代码解析

2.1 HLS kernel代码

#include "example.h"

void example(hls::stream<int>& A, hls::stream<int>& B){
#pragma HLS dataflow
#pragma HLS INTERFACE ap_fifo port=A
#pragma HLS INTERFACE ap_fifo port=B
    hls::stream<int> data_channel1;
    hls::stream<int> data_channel2;

    proc_1(A, data_channel1, data_channel2);
    proc_2(data_channel1, data_channel2, B);
}

void proc_1(hls::stream<int>& A, hls::stream<int>& B, hls::stream<int>& C){
#pragma HLS dataflow
    hls::stream<int> data_channel1;
    hls::stream<int> data_channel2;

    proc_1_1(A, data_channel1, data_channel2);
    proc_1_2(B, C, data_channel1, data_channel2);
}

void proc_1_1(hls::stream<int>& A, hls::stream<int>& data_channel1, hls::stream<int>& data_channel2){
  int i;
  int tmp;
  for(i = 0; i < 10; i++){
    tmp = A.read();
    data_channel1.write(tmp); 
  }
  for(i = 0; i < 10; i++){
    data_channel2.write(tmp); 
  }
}

void proc_1_2(hls::stream<int>& B, hls::stream<int>& C, hls::stream<int>& data_channel1, hls::stream<int>& data_channel2){
  int i;
  int tmp;
  
  for(i = 0; i < 10; i++){
    tmp = data_channel2.read() + data_channel1.read();
    B.write(tmp);
  }
  for(i = 0; i < 10; i++){
    C.write(tmp); 
  }
}

void proc_2(hls::stream<int>& A, hls::stream<int>& B, hls::stream<int>& C){
#pragma HLS dataflow
    hls::stream<int> data_channel1;
    hls::stream<int> data_channel2;

    proc_2_1(A, B, data_channel1, data_channel2);
    proc_2_2(C, data_channel1, data_channel2);
}

void proc_2_1(hls::stream<int>& A, hls::stream<int>& B, hls::stream<int>& data_channel1, hls::stream<int>& data_channel2){
  int i;
  int tmp;
  for(i = 0; i < 10; i++){
    tmp = A.read() + B.read();
    data_channel1.write(tmp); 
  }
  for(i = 0; i < 10; i++){
    data_channel2.write(tmp); 
  }
}

void proc_2_2(hls::stream<int>& C, hls::stream<int>& data_channel1, hls::stream<int>& data_channel2){
  int i;
  int tmp;
  for(i = 0; i < 10; i++){
    tmp = data_channel2.read() + data_channel1.read();
    C.write(tmp);
  }
}

与原示例相比,去掉了“&”符号。

#pragma HLS INTERFACE ap_fifo port=&A
#pragma HLS INTERFACE ap_fifo port=&B

以上 kernel 的功能框图:

2.2 查看接口报告

对于顶层文件,可以查看 example_csynth.rpt,观察顶层接口:

================================================================
== Interface
================================================================
* Summary: 
+-----------+-----+-----+------------+--------------+--------------+
| RTL Ports | Dir | Bits|  Protocol  | Source Object|    C Type    |
+-----------+-----+-----+------------+--------------+--------------+
|A_dout     |   in|   32|     ap_fifo|             A|       pointer|
|A_empty_n  |   in|    1|     ap_fifo|             A|       pointer|
|A_read     |  out|    1|     ap_fifo|             A|       pointer|
|B_din      |  out|   32|     ap_fifo|             B|       pointer|
|B_full_n   |   in|    1|     ap_fifo|             B|       pointer|
|B_write    |  out|    1|     ap_fifo|             B|       pointer|
|ap_clk     |   in|    1|  ap_ctrl_hs|       example|  return value|
|ap_rst     |   in|    1|  ap_ctrl_hs|       example|  return value|
|ap_start   |   in|    1|  ap_ctrl_hs|       example|  return value|
|ap_done    |  out|    1|  ap_ctrl_hs|       example|  return value|
|ap_ready   |  out|    1|  ap_ctrl_hs|       example|  return value|
|ap_idle    |  out|    1|  ap_ctrl_hs|       example|  return value|
+-----------+-----+-----+------------+--------------+--------------+

 针对 Dataflow 区域的每个函数体,均有对应的 Interface:

================================================================
== Interface
================================================================
* Summary: 
+-------------------------------+-----+-----+------------+----------------+--------------+
|           RTL Ports           | Dir | Bits|  Protocol  |  Source Object |    C Type    |
+-------------------------------+-----+-----+------------+----------------+--------------+
|ap_clk                         |   in|    1|  ap_ctrl_hs|        proc_1_1|  return value|
|ap_rst                         |   in|    1|  ap_ctrl_hs|        proc_1_1|  return value|
|ap_start                       |   in|    1|  ap_ctrl_hs|        proc_1_1|  return value|
|start_full_n                   |   in|    1|  ap_ctrl_hs|        proc_1_1|  return value|
|ap_done                        |  out|    1|  ap_ctrl_hs|        proc_1_1|  return value|
|ap_continue                    |   in|    1|  ap_ctrl_hs|        proc_1_1|  return value|
|ap_idle                        |  out|    1|  ap_ctrl_hs|        proc_1_1|  return value|
|ap_ready                       |  out|    1|  ap_ctrl_hs|        proc_1_1|  return value|
|start_out                      |  out|    1|  ap_ctrl_hs|        proc_1_1|  return value|
|start_write                    |  out|    1|  ap_ctrl_hs|        proc_1_1|  return value|
|A_dout                         |   in|   32|     ap_fifo|               A|       pointer|
|A_empty_n                      |   in|    1|     ap_fifo|               A|       pointer|
|A_read                         |  out|    1|     ap_fifo|               A|       pointer|
|data_channel12_din             |  out|   32|     ap_fifo|  data_channel12|       pointer|
|data_channel12_num_data_valid  |   in|    2|     ap_fifo|  data_channel12|       pointer|
|data_channel12_fifo_cap        |   in|    2|     ap_fifo|  data_channel12|       pointer|
|data_channel12_full_n          |   in|    1|     ap_fifo|  data_channel12|       pointer|
|data_channel12_write           |  out|    1|     ap_fifo|  data_channel12|       pointer|
|data_channel23_din             |  out|   32|     ap_fifo|  data_channel23|       pointer|
|data_channel23_num_data_valid  |   in|    2|     ap_fifo|  data_channel23|       pointer|
|data_channel23_fifo_cap        |   in|    2|     ap_fifo|  data_channel23|       pointer|
|data_channel23_full_n          |   in|    1|     ap_fifo|  data_channel23|       pointer|
|data_channel23_write           |  out|    1|     ap_fifo|  data_channel23|       pointer|
+-------------------------------+-----+-----+------------+----------------+--------------+

上述报告 Source  Object 所在列:

  • A - > hls::stream<int>& A, C type 为 pointer
  • data_channel12 -> hls::stream<int>& data_channel1, C type 为 pointer
  • data_channel23 -> hls::stream<int>& data_channel2, C type 为 pointer
​
void proc_1_1(hls::stream<int>& A, hls::stream<int>& data_channel1, hls::stream<int>& data_channel2){
  int i;
  int tmp;
  for(i = 0; i < 10; i++){
    tmp = A.read();
    data_channel1.write(tmp);
  }
  for(i = 0; i < 10; i++){
    data_channel2.write(tmp);
  }
}

2.3 TestBench

#include <stdio.h>
#include "hls_stream.h"

#define SIZE 10
extern void example(hls::stream<int>& A, hls::stream<int>& B);

int main()
{
  int i;
  hls::stream<int> A;
  hls::stream<int> B;
  
  int time = 0;
  for   (time = 0 ; time < 4; time ++) {
      for(i=0; i < SIZE; i++){
        A << (i + time);
      }
      example(A,B);
  }
  return 0;
}

2.4 Dataflow 报告

运行 C Synthesis 后,可以查看 Dataflow 报告,如下图,没有问题。

在运行 C/RTL Cosimulation 后,同样在 Dataflow 报告中可以看到错误。

3. Takeaways

总结而言,Dataflow查看器实现了以下吞吐量分析任务:

图表展示了 DATAFLOW 区域的整体拓扑结构,并显示了在 DATAFLOW 区域中任务之间用于通信的通道类型(FIFO/PIPO)。通过分析每个通道和进程,可以有效地解决死锁或由于FIFO大小不当导致的吞吐量不足等问题。

协同仿真数据通过在仿真过程中跟踪FIFO的最大使用量,为解决FIFO大小设置问题提供了参考依据,从而帮助用户调整FIFO大小。此外,运行协同仿真时的自动死锁检测功能能够突出显示涉及死锁的进程和通道,使用户能够快速定位并解决这些问题。

除了 FIFO 大小的调整,协同仿真后的数据还能按每个进程和通道报告因等待输入或输出而导致的停滞时间。这些图表帮助用户理解并解决这些问题,同时管理通道大小以满足慢速生产者与快速消费者之间的需求,或者相反。此外,图表还揭示了在DATAFLOW区域中途读取输入如何影响整体性能,这是一个常见的场景,可能会对性能产生重大影响。

4. 总结

在数据流优化中,通道类型、握手机制、FIFO大小和死锁避免都是关键因素。通过Dataflow查看器和协同仿真数据,您可以有效地优化设计,提高性能并避免潜在问题。

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

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

相关文章

蜜罐技术是一种什么防御技术?实现原理是什么?

前言&#xff1a;蜜罐技术的出现改变了这种被动态势&#xff0c;它通过吸引、诱骗攻击者&#xff0c;研究学习攻击者的攻击目的和攻击手段&#xff0c;从而延缓乃至阻止攻击破坏行为的发生&#xff0c;有效保护真实服务资源。 自网络诞生以来&#xff0c;攻击威胁事件层出不穷…

【数据结构(邓俊辉)学习笔记】图01——若干定义

文章目录 1. 概述1.1 邻接 关联1.2 无向 有向1.3 路径 环路 2. 邻接矩阵2.1 接口2.2 邻接矩阵 关联矩阵2.3 实例2.4 顶点和边2.5 邻接矩阵2.6 顶点静态操作2.7 边操作2.7 顶点动态操作2.8 综合评价 1. 概述 1.1 邻接 关联 相对于此前的线性以及半线性结构&#xff0c;图…

AT指令配置模块

图为用串口一发送字符串来配置AT指令模块的字符串发送格式。 后续更新接收字符串的数据处理。 利用stm32给WiFi模块发送AT指令&#xff0c;所以32的发送端连接WiFi模块的接收端&#xff0c;WiFi模块接收AT指令的返回值发送给ch340由电脑显示&#xff0c;所以WiFi模块的TX连接C…

2024年5月大语言模型论文推荐:模型优化、缩放到推理、基准测试和增强性能

前一篇文章总结了关于计算机视觉方面的论文&#xff0c;这篇文章将要总结了2024年5月发表的一些最重要的大语言模型的论文。这些论文涵盖了塑造下一代语言模型的各种主题&#xff0c;从模型优化和缩放到推理、基准测试和增强性能。 大型语言模型(llm)发展迅速&#xff0c;跟上…

0元入驻抖音小店,真的是好事吗?

大家好&#xff0c;我是喷火龙。 抖音小店去年推出0元入驻抖音小店个人店的政策&#xff0c;简而言之就是只要一张身份证就可以开店&#xff0c;不需要营业执照&#xff0c;也不需要交保证金。 很多人一听很心动&#xff0c;因为没有任何成本就可以开店&#xff0c;于是纷纷跑…

echarts配置记录,一些已经废弃的写法

1、normal&#xff0c;4.0以后无需将样式写在normal中了 改前&#xff1a; 改后&#xff1a; DEPRECATED: normal hierarchy in labelLine has been removed since 4.0. All style properties are configured in labelLine directly now. 2、axisLabel中的文字样式无需使用te…

C++Qt操作Lotus Domino数据库 Lotus Domino C++连接Lotus Domino C++快速开发Lotus Domino

java连接domino C#连接domino python连接domino go连接domino,delphi连接domino Excel连接domino Flutter、微信小程序连接domino C 操作 Lotus Domino 数据库&#xff1a;自动化与效率的结合 引言 在企业级应用中&#xff0c;Lotus Domino 提供了一个强大的协作平台&#xff0…

牛客NC324 下一个更大的数(三)【中等 双指针 Java/Go/PHP/C++】参考lintcode 52 · 下一个排列

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/475da0d4e37a481bacf9a09b5a059199 思路 第一步&#xff1a;获取数字上每一个数&#xff0c;组成数组arr 第二步&#xff1a;利用“下一个排列” 问题解题方法来继续作答&#xff0c;步骤&#xff1a;利用lintc…

【Apache Doris】BE宕机问题排查指南

【Apache Doris】BE宕机问题排查指南 背景BE宕机分类如何判断是BE进程是Crash还是OOMBE Crash 后如何排查BE OOM 后如何分析Cache 没及时释放导致BE OOM&#xff08;2.0.3-rc04&#xff09; 关于社区 作者&#xff5c;李渊渊 背景 在实际线上生产环境中&#xff0c;大家可能遇…

新建一个STM32工程(精简版)

一、新建一个STM32工程 二、建立三个文件夹 1、Start文件夹里的东西 &#xff08;1&#xff09;启动文件&#xff1a;STM32入门教程资料\固件库\STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm &#xff08;2&#xff09;STM32…

springboot社区助老志愿服务系统-计算机毕业设计源码96682

摘要 大数据时代下&#xff0c;数据呈爆炸式地增长。为了迎合信息化时代的潮流和信息化安全的要求&#xff0c;利用互联网服务于其他行业&#xff0c;促进生产&#xff0c;已经是成为一种势不可挡的趋势。在图书馆管理的要求下&#xff0c;开发一款整体式结构的社区助老志愿服务…

OFDM 802.11a的FPGA实现(二十)使用AXI-Stream FIFO进行跨时钟(含代码)

目录 1.前言 2.AXI-Stream FIFO时序 3.AXI-Stream FIFO配置信息 4.时钟控制模块MMCM 5.ModelSim仿真 6.总结 1.前言 至此&#xff0c;通过前面的文章讲解&#xff0c;对于OFDM 802.11a的发射基带的一个完整的PPDU帧的所有处理已经全部完成&#xff0c;其结构如下图所示&…

Linux echo命令(在终端输出文本)

文章目录 Linux Echo命令深度解析简介命令语法常见选项- -n&#xff1a;不输出行尾的换行符&#xff0c;这意味着输出后不会换到下一行。- -e&#xff1a;启用反斜杠转义的解释&#xff0c;允许使用特殊字符。- -E&#xff1a;禁用反斜杠转义的解释&#xff08;默认选项&#x…

CI/CD 管道中的自动化测试:类型和阶段

在上一篇文章中&#xff0c;我们讨论了敏捷团队自动化测试用例的各种用例。其中一种情况是&#xff0c;团队希望将测试与每个构建集成&#xff0c;并将持续集成作为构建过程的一部分。 在本文中&#xff0c;我们将讨论持续集成/持续交付平台中的集成测试。 让我们先从基础知识…

嵌入式全栈开发学习笔记---C语言笔试复习大全22

目录 结构体 结构体的声明 定义结构体变量 访问结构体成员进行初始化 通过结构体变量名访问结构体成员 结构体指针 结构体指针的定义 通过结构体指针访问结构体成员 结构体数组 结构体数组的定义 遍历结构体数组 结构体的长度&#xff08;笔试重点&#xff09; 上一…

Attention相关问题笔试解析。

Attention相关问题笔试解析。 题目描述一&#xff1a;【选择】题目描述二&#xff1a;【简答】题目描述三&#xff1a;【代码】Scaled Dot-Product Attention&#xff1a;下面是用PyTorch实现的一个Attention机制的代码。这个实现包括一个简单的Scaled Dot-Product Attention机…

【大模型部署】在C# Winform中使用文生图Stable Diffusion XL 模型

【大模型部署】在C# Winform中使用文生图Stable Diffusion XL 模型 前言 整了一个在C# Winform中调用文生图Stable Diffusion XL的小程序&#xff0c;基于百度智能云千帆平台 步骤 如何注册百度智能云和创建应用&#xff0c;获取API 密钥等和在之前的博客中基本相同&#…

P6160 [Cnoi2020] 向量

[Cnoi2020] 向量 题目背景 向量(vector)&#xff0c;指具有大小(Magnitude)和方向(Direction) 的量。 与向量对应的量叫做数量(Scalar)&#xff0c;数量只有大小&#xff0c;没有方向。 对于 Cirno 来说&#xff0c;整天环绕氷屋的旋转 Sangetsusei 们是向量而不是数量。 Sun…

spring模块(三)Spring AOP(2)使用

一、demo 1、spring项目 &#xff08;1&#xff09;pom <dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>4.3.13.RELEASE</version></dependency>&l…

[数组查找]1.图解线性查找及其代码实现

线性查找 线性查找是一种在数组中查找数据的算法。与二分查找不同&#xff0c;即便数据没有按顺序存储&#xff0c;也可以应用线性查找。线性查找的操作很简单&#xff0c;只要在数组中从头开始依次往下查找即可。虽然存储的数据类型没有限制&#xff0c;但为了便于理解&#x…