CHAPTER 48 / Cerebras · 晶圆级计算
功能模型、simulator 与硬件:分别证明什么
测试全绿之后,哪些结论仍然不能写?
这一章要弄清楚
- 分开数学模型、SDK simulator和硬件证据
- 设计边界与变形测试
- 用事件记录定位未完成协议
先备知识:测试与调试:独立定位失败 / Reduction、scan 与数值正确性 / 多PE scan:消息里到底应该传什么
C++20 本机逻辑模型;不是设备仿真或性能测量。厂商语法片段未在设备或 SDK 执行,实际 API 以匹配版本的公开文档为准。
先写下测试正在证明的命题
“程序通过了”至少可能指三件不同的事:C++数学模型产生正确答案;真实CSL程序在SDK fabric simulator运行并符合预期;同一程序在目标硬件上运行正确。这三个层次都可能有价值,但不能互相替代。自写几个节点的C++循环不是厂商simulator,也不包含其指令、任务和路由语义。
本章只运行原创CPU模型。它能快速枚举小输入,帮助在接触复杂设备环境前发现数学和分区错误。将这类结果写成“设备模拟通过”会夸大检查范围;把真实SDK simulator的运行时间当硬件耗时,也会混淆模型与实际机器。
Oracle要足够独立
例一用简单顺序求和作oracle,再用分块求和作candidate。输入长度从零到四,每项从负1、0、2中选择,一共有121个小案例。穷举覆盖空输入、单项、零、负值和尾部分块,却仍不是对所有整数输入的证明。这里取值很小,避免signed overflow;真实大输入需要明确范围或更宽累积类型。
若oracle与candidate调用同一个分区函数,同一处漏项可能在两边都发生。尽量让reference简单、独立、容易手算。设备程序还应测试边缘PE数量、不能整除的长度、空分区、最大合法容量和连续多次调用;前一次状态残留经常不会在单次成功中显现。
变形测试把性质变成检查
当全部期望值难以手写时,可以检查数学性质。求和在无溢出的整数合同下,追加零不改变结果,复制序列使总和加倍;scan的最后一项应等于总和,但这只是必要条件,不能代替逐位置检查。浮点情况下这些关系可能受到舍入影响,必须说明容差与前提。
例二检查一段原创消息记录是否包含规定数量,并按序到达。三条正确消息通过,缺失一条被拒绝。记录检查并没有运行通信,也不能证明实际任务无死锁;它展示应记录哪些信息,才能从“卡住了”走向一个可定位的等待条件。
Debug输出和性能记录各有边界
Cerebras公开debug教程介绍把值与时间信息记录下来供host读取;simprint教程提供在simulator日志中输出信息的方式。日志可以帮助找出最后到达的节点、未更新的计数或未完成的阶段。不同工具有不同输出和完成要求,应按匹配版本使用。
不要把添加大量日志后的执行成本当最终性能,也不要删除所有日志后就宣称问题修复。保留最小复现、输入、版本、编译参数、运行命令及原始输出,才能让另一个人重复同一结论。模拟时间、host墙钟时间和硬件设备计时需要不同标签。
失败也是有价值的结果
超时可能表示死锁,也可能是配置、资源或运行时间预算问题;要看最后可观察事件,不先下结论。数值不匹配则先定位第一个错误坐标,再追溯其输入和消息。容量拒绝如果符合接口合同,应单独记为预期错误,而不是与正确数值案例混成一个成功率。
面试时可以说清当前通过了哪些输入、哪种执行环境、哪些性质,以及还缺什么验证。这比一个没有范围的“100%正确”更可信。以后具备SDK或硬件条件时,追加新证据层即可,不需要改写已有CPU模型的身份。
一条缺失消息如何被拒绝
预期三条有序消息。
第二条消息缺失。
数量不符先拒绝,不能宣告完成。
阅读完整推演文字
- 合同
expected:0 1 2;count:3
预期三条有序消息。
- 观察
observed:0 2;count:2
第二条消息缺失。
- 判断
complete:false;next:追查序号1
数量不符先拒绝,不能宣告完成。
跟着例子,走完一遍
121个小输入交叉验证
长度0–4,每项取-1、0、2;块大小3。
- 枚举每种短输入
- 顺序和作oracle
- 分块和作candidate并比较
// Original CPU teaching model; not a device simulator or benchmark.
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <stdexcept>
void require(bool ok) { if (!ok) throw std::runtime_error("model check failed"); }
int chunked(const std::vector<int>& a) {
int total=0;
for(std::size_t base=0;base<a.size();base+=3) {
int local=0;for(std::size_t i=base;i<std::min(base+3,a.size());++i) local+=a[i];total+=local;
}
return total;
}
int main() {
int cases=0;
for(int n=0;n<=4;++n) {
int combinations=1;for(int i=0;i<n;++i) combinations*=3;
for(int mask=0;mask<combinations;++mask) {
int code=mask;std::vector<int> a;const int values[3]={-1,0,2};
for(int i=0;i<n;++i){a.push_back(values[code%3]);code/=3;}
require(chunked(a)==std::accumulate(a.begin(),a.end(),0));++cases;
}
}
require(cases==121);std::cout<<"cases="<<cases<<" mismatch=0\n";
}
cases=121 mismatch=0。
只覆盖这套小输入,不证明任意输入或设备程序。
在本机运行这个例子
下载后,在文件所在目录执行。需要支持 C++20 的编译器;POSIX 示例还需要章节说明中的系统条件。
clang++ -std=c++20 -Wall -Wextra -Wpedantic -Werror -pthread 44-a.cpp -o example && ./example预期标准输出:
cases=121 mismatch=0
缺失消息必须被检测
预期序号0、1、2;比较完整和缺少1的记录。
- 先检查数量
- 再检查每项序号
- 缺失记录拒绝
// Original CPU teaching model; not a device simulator or benchmark.
#include <iostream>
#include <vector>
#include <stdexcept>
void require(bool ok) { if (!ok) throw std::runtime_error("model check failed"); }
bool complete(const std::vector<int>& sequence) {
if(sequence.size()!=3) return false;
for(std::size_t i=0;i<sequence.size();++i) if(sequence[i]!=static_cast<int>(i)) return false;
return true;
}
int main() {
const bool a=complete({0,1,2}),b=complete({0,2});
require(a && !b);std::cout<<"complete="<<a<<" missing="<<b<<'\n';
}
complete=1 missing=0。
这是日志合同检查,不是网络或SDK运行。
在本机运行这个例子
下载后,在文件所在目录执行。需要支持 C++20 的编译器;POSIX 示例还需要章节说明中的系统条件。
clang++ -std=c++20 -Wall -Wextra -Wpedantic -Werror -pthread 44-b.cpp -o example && ./example预期标准输出:
complete=1 missing=0
把不同证据层合并成成功数
CPU案例、simulator启动和硬件运行混写成设备测试通过。
修正思路:按执行环境与测试命题分开计数,保留限制及原始记录。
轮到你动手
先写预测或代码,再按需打开提示。完整答案用于对照自己的推理。
练习 1
为整数sum写两个变形测试,并写出前提。
给我一点提示
- 零是加法单位元
- 先排除溢出
查看答案与推理
在不会溢出的整数范围内,追加零结果不变;拼接自身结果是原和的两倍。第二条还需检查倍增后的范围;浮点不能无条件按精确相等验收。
练习 2
一轮成功、第二轮失败,测试应补什么?
给我一点提示
- 状态初始化
- 消息与输出残留
查看答案与推理
连续运行不同输入,包括小→大、大→小、空分区与相同输入重复;核对计数器、buffer和完成标记是否重置,并检查输出哨兵是否仍残留。逐轮保存输入和第一个错误位置。
把理解说出来
先用中文讲清因果,再用英文回答。问题依据技能主题编写,并非公司内部题库。
为什么CPU模型不能叫fabric simulator?
参考回答 / English answer
没有执行SDK设备语义,只实现自己选择的逻辑;必须标明范围。
Our model implements selected mathematical behavior. It does not execute the SDK's fabric or instruction semantics.121个案例全过能证明所有输入正确吗?
参考回答 / English answer
不能,只覆盖有限长度和取值;还需类型范围、边界、协议与环境检查。
Passing a finite test set is not a universal proof. Input ranges, protocol behavior, and execution environments remain relevant.scan最后一项正确,能通过所有检查吗?
参考回答 / English answer
不能,中间项可能错位;需逐项reference和性质检查。
A correct final value is only a necessary condition. Intermediate prefixes must also match.如何避免oracle与candidate一起错?
参考回答 / English answer
让oracle简单独立,不共享复杂分区或打包实现,加入手算诊断输入。
I keep the oracle simple and independent. Hand-checkable cases help expose shared preparation mistakes.simulator周期能当硬件性能吗?
参考回答 / English answer
不能,模拟语义与硬件执行环境不同;需明确指标来源和假设。
Simulator timing is not hardware timing. I label the source and assumptions of every metric.超时之后首先记录什么?
参考回答 / English answer
最后事件、等待条件、计数、输入、版本和命令;不能先将其一律判成死锁。
I capture the last observable events and outstanding waits. A timeout alone does not identify the root cause.继续查证
- Cerebras public SDK examples ↗
Simulator/hardware distinction and release compatibility
- Cerebras debug library tutorial ↗
Trace values and host inspection
- Cerebras simprint tutorial ↗
Simulator logging and incomplete-program diagnosis
公开资料用于查证;本章图解和例题是独立教学内容。CPU 逻辑模型不能证明设备性能。