欢迎光临
我们一直在努力

BM1688 双核架构

概述

BM1688 把两个独立的计算核封装在一颗芯片里,每个核有自己的指令队列、局部存储和 L2

理解“双核(双 die)”是什么

BM1684X 的架构(对比基准)

BM1684X 是单核组、64 Lane:
在这里插入图片描述

  • 一条指令流,同时广播给 64 个 Lane。
  • 64 个 Lane 的局部存储统一编址(16MB),但每个 Lane 只能访问自己那份。
  • 所有 Lane 同步执行,SIMD 模式。

BM1688 的架构(双核)

BM1688 是双核组,每核 8 TOPS:
在这里插入图片描述

关键区别:

特性BM1684X(单核组)BM1688(双核)
指令流 1 条 2 条(各自独立)
局部存储 统一 16MB 每核约 8MB,独立编址
L2 共享 各自独立
核间通信 不需要(同一核内) 需要(通过片内总线)
编程模型 写一份代码,64 Lane 自动铺开 需要显式决定两个核各做什么

双核的好处:两个核可以独立跑不同的任务,灵活性更高;低功耗场景下可以只开一个核。

双核的代价:核间同步、数据交换、负载均衡都需要编译器处理,复杂度高。

统一例子:一个 4 层 CNN 模型

假设我们要在 BM1688 上跑一个简单的 CNN:

输入 x [1, 3, 224, 224]


Conv1 (3→64, 3×3, stride=2) → [1, 64, 112, 112] → ReLU


Conv2 (64→128, 3×3, stride=2) → [1, 128, 56, 56] → ReLU


Conv3 (128→256, 3×3, stride=2) → [1, 256, 28, 28] → ReLU


Conv4 (256→512, 3×3, stride=2) → [1, 512, 14, 14] → ReLU


输出

我们来看看四种策略分别怎么把工作分给两个核。

策略一:流水切分(Pipeline Split)

思路

核 0 跑前一半层,核 1 跑后一半层,两核之间传递中间结果。

核 0:Conv1 → ReLU → Conv2 → ReLU

▼ 中间结果(经过 DDR 或片上互连)
核 1: Conv3 → ReLU → Conv4 → ReLU

具体执行过程

时间线:
时刻 t0: 核 0 开始算 Conv1
时刻 t1: 核 0 算完 Conv1,开始算 Conv2
时刻 t2: 核 0 算完 Conv2,把中间结果 [1,128,56,56] 写到 DDR
时刻 t3: 核 1 从 DDR 读中间结果,开始算 Conv3
时刻 t4: 核 1 算完 Conv3,开始算 Conv4
时刻 t5: 核 1 算完 Conv4,输出结果

负载均衡问题

如果核 0 的工作量是 60%,核 1 是 40%:
在这里插入图片描述

核 0 先算完,等核 1 完成,加速比只有 1/(0.6) ≈ 1.67×,而不是 2×。

适合场景:层内计算量均衡的模型,两核工作量差不多。

策略二:数据切分(Data Split)

思路

两核各跑一半 batch。 适合批量推理(batch=2 或 4)。

假设 batch = 2:
核 0:处理样本 0 的完整前向
核 1:处理样本 1 的完整前向

具体执行过程

核 0:Conv1 → ReLU → Conv2 → ReLU → Conv3 → ReLU → Conv4 → ReLU (样本 0)
核 1:Conv1 → ReLU → Conv2 → ReLU → Conv3 → ReLU → Conv4 → ReLU (样本 1)

两个核完全独立,不需要交换数据,不需要同步。

优缺点

优点:

  • 实现最简单,两核完全独立。
  • 负载天然均衡(每个样本的计算量相同)。
  • 加速比接近 2×。

缺点:

  • 只适合 batch ≥ 2 的场景。batch=1 时无法用。
  • 如果 batch 是奇数(如 3),最后一个样本只能一个核跑,负载不均衡。

适合场景:批量推理,如视频解析(多帧同时处理)。

策略三:算子切分(Op Split)

思路

大算子内部按通道/空间分给两核,各算一半,最后合并。 需要跨核同步与部分和交换。

以 Conv2 为例(输出 128 个通道):

核 0:计算输出通道 0~63 的卷积
核 1:计算输出通道 64~127 的卷积

具体执行过程

Conv2 的输入:[1, 64, 56, 56](所有核都需要完整的输入)
Conv2 的权重:[128, 64, 3, 3](按输出通道分成两半)

核 0:
权重 [0:64, :, :, :]
计算输出 [1, 64, 56, 56](通道 0~63)

核 1:
权重 [64:128, :, :, :]
计算输出 [1, 64, 56, 56](通道 64~127)

合并:将两核的输出拼成 [1, 128, 56, 56]

同步与数据交换

时刻 t0: 两核各自从 DDR 读输入 [1, 64, 56, 56]
时刻 t1: 两核各自计算自己负责的 64 个输出通道
时刻 t2: 两核各自把输出写到 DDR 的不同区域
时刻 t3: 后续算子需要完整输入时,从 DDR 读合并后的结果

关键问题:两核都需要完整的输入(64 个通道),所以输入要读两遍。如果输入很大,这会增加访存量。

优缺点

优点

适合单个大算子,batch=1 也能用。

缺点:

实现最复杂(需要跨核同步、部分和交换)。

输入可能被重复读取,增加访存。

如果算子本身已经用了所有 Lane,切分后每个核算力减半,需要仔细设计。

适合场景:单个大算子(如大 GEMM、大卷积)需要并行时。

策略四:混合模式

思路

不同层用不同策略,由编译器的多核调度器决定。

Conv1:数据切分(batch=2,两核各一个样本)
Conv2:算子切分(输出通道分半)
Conv3:流水切分(核 0 算前半,核 1 算后半)
Conv4:数据切分

具体执行过程

时间线:
t0: Conv1(数据切分)→ 核 0 算样本 0,核 1 算样本 1
t1: Conv2(算子切分)→ 核 0 算通道 0~63,核 1 算通道 64~127
(两核需要交换部分和)
t2: Conv3(流水切分)→ 核 0 算前半层,核 1 算后半层
t3: Conv4(数据切分)→ 核 0 算样本 0,核 1 算样本 1

tpu-mlir 的多核调度

tpu-mlir 的 –multi_core 选项就是在做这件事:

# 启用双核调度
tpu-mlir –multi_core=2 model.mlir

编译器会分析模型结构,自动决定每层用哪种策略,生成两个核各自的指令流。

为什么多核加速不是线性的?

三座大山

问题说明对加速比的影响
核间同步 两核需要等待对方完成才能继续 同步开销直接吃掉加速比
负载均衡 两核工作量不相等时,一个核等另一个 加速比 = 1/max(核0时间, 核1时间)
数据交换 中间结果需要通过 DDR 或片内总线传递 增加访存和延迟

具体计算

假设理想情况是 2× 加速,但:

  • 同步开销:每次同步 5% 时间
  • 负载不均衡:核 0 占 55%,核 1 占 45%
  • 数据交换:中间结果传递占 10% 时间

实际加速比:
加速比=10.55+0.05+0.10≈1.43
加速比 = \\frac{1}{0.55 + 0.05 + 0.10} \\approx 1.43
加速比=0.55+0.05+0.1011.43

如果优化得更好(负载均衡、减少同步):
加速比=10.50+0.02+0.05≈1.75
加速比 = \\frac{1}{0.50 + 0.02 + 0.05} \\approx 1.75
加速比=0.50+0.02+0.0511.75

这就是为什么宣传 16 TOPS,实测吞吐可能只有 1.5~1.9× 的加速——编译器多核调度水平的差距。

总结

策略思路适合场景加速比
流水切分 核 0 跑前半层,核 1 跑后半层 层内计算量均衡 1.5~1.8×
数据切分 两核各跑一半 batch batch ≥ 2 接近 2×
算子切分 大算子按通道/空间分半 单个大算子,batch=1 1.3~1.7×
混合模式 不同层用不同策略 复杂模型 1.5~1.9×

一句话:BM1688 的双核架构给编译器提供了灵活性,但也带来了同步、负载均衡、数据交换三座大山。

编译器的多核调度水平,直接决定了实际加速比是接近 2× 还是只有 1.5×。这就是为什么同样 16 TOPS 的芯片,不同工具链跑同一模型性能能差 30%。

赞(0)
未经允许不得转载:171主机测评 » BM1688 双核架构
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址