一、流水线设计说明1.流水线设计dataflow中的task的内部来执行if-else条件分支2.不要将dataflow中的task放在if-else条件分支内这种有条件的执行task任务会造成流水线性能的大打折扣。3.if-else条件中执行task任务这种选择性执行任务会影响性能4.将if-else放在task任务中任务总是启动工作的内部的if-else只是路径不同这个不影响性能。二、具体说明1.在pipeline循环中避免在循环内if-else包裹整个函数调用而应把函数调用放在外面内部if-else处理数据。2.在dataflow区域不要使用if(cond) task1() else task2()而是让数据流进入一个合并的任务任务内部根据条件处理。三、vivado hls优化哲学思考1.尽可能的让数据在task任务和pipeline数据流中持续的流动2.把条件判断下沉为数据通路的选择逻辑3.不要用条件语句来控制任务是否执行这三条是流水线free-run设计和task-parallel并发设计的基本要求。四、核心思想任务Task在 HLS 中通常指 dataflow 区域内的一个函数或一个被 #pragma HLS pipeline 修饰的循环/函数。有条件地执行任务指通过 if(cond) task() 或条件循环体来决定是否启动或执行一个完整的任务。在流水线任务内部执行条件分支任务总是被启动或数据总是流入但在任务内部通过 if-else 选择不同的处理路径。前者将条件暴露在任务调度层面后者将条件封装在任务数据通路内部。前者会破坏流水线的连续性后者则允许流水线始终满负荷运行条件仅作为数据路径上的多路选择器来实现。五、流水线循环中的条件执行案例for (int i 0; i N; i) {if (cond[i]) {heavy_task(A[i], B[i]); // 条件执行整个任务}}若 heavy_task 流水线化了但由于 if 的存在当 cond[i] false 时该迭代根本不会启动任务。这导致流水线出现“气泡”——某些周期没有新任务进入已进入的任务也会因缺少后续任务而无法满流水。突发访存被打断任务不启动则可能不读 A[i]/B[i]见前文分析。六、dataflow 区域中的条件任务#pragma HLS dataflow...if (cond) {task1(in, out);} else {task2(in, out);}综合工具必须在硬件中同时实现 task1 和 task2 的模块并加入选择逻辑。由于任务可能在不同时刻执行不同的分支数据流通道FIFO的深度和行为难以静态分析容易导致反压或死锁。task1 和 task2 的延迟通常不同这会使整体数据流吞吐率受限于最差情况且调度复杂。七、pipeline低效的写法和高效的写法1.低效的写法for (int i 0; i N; i) {if (mask[i]) {process(A[i], B[i]); // 有些迭代不启动任务}}2.高效的写法for (int i 0; i N; i) {process(A[i], B[i], mask[i]); // 每个迭代都启动}void process(int in, int* out, bool en) {#pragma HLS pipeline II1if (en) {*out complex_op(in);} else {*out in; // 直通或保持原值}}流水线的每个迭代都按时启动II1 可以维持。条件 en 在流水线内部只是一个多路选择器不影响吞吐。访存 A[i] 和 B[i] 在每个周期都发生可以形成高效突发。八、dataflow的低效写法和高效写法1.dataflow低效的写法#pragma HLS dataflowhls::streamint s1, s2;producer(s1, s2, cond);if (cond) {consumer_A(s1, out);} else {consumer_B(s2, out);}#pragma HLS dataflowhls::streamint s1, s2;producer(s1, s2, cond);if (cond) {consumer_A(s1, out);} else {consumer_B(s2, out);}2.dataflow高效的写法#pragma HLS dataflowhls::streamint s;producer(s); // 数据无差别流入consumer(s, cond, out); // 消费者内部根据cond处理void consumer(hls::streamint s, bool cond, int* out) {#pragma HLS pipeline II1int data s.read();if (cond) {*out pathA(data);} else {*out pathB(data);}}producer 只需向一个流写入consumer 连续读取。条件在 consumer 内部作为数据路径分支流水线始终保持 II1。硬件实现为 pathA 和 pathB 并行计算最后通过 cond 选择结果资源可能增加但吞吐率最高。九、总结1.有条件的执行任务这种方式效率低流水线有气泡吞吐率做不高这种方式可能会节约资源但是流水线稳定性差突发和流水线设计被打断。2.任务内部执行条件分支这种设计的吞吐率高每个周期稳定输出并行路径造成资源稍微高但是流水线稳定性比较良好永远满流水的运行。