不是,这个“理应”是谁给你的理由啊?怎么就这么理直气壮的?

还有下面的回答,一片片的,真就莫名其妙的“理应”起来了?


首先告诉你一点:别说 CPU 内部、机箱内部了;就最垃圾的、刚刚能支持 1000Base-T 的 cat5e 双绞线传输电磁信号——这玩意儿没有屏蔽、全程被外界复杂的电磁波环境干扰、还要把电信号传输 100 米——最终的误码率都小于 10^-10!

没错,10^-10,10000000000bit 数据只允许 1bit 出错!

一百亿分之一的出错概率!

低于这个概率就不符合 IEEE802.3 标准,做出这种破烂的企业就只能倒闭。

事实上,使用正规设备、正常设计、布线的网络,跑 10 年一个 bit 都没错过,这才是正常的。

这可是远程通讯!

机箱内通讯,误码率会小的多得多——正常情况下,CPU 内几乎完全不会产生错误:有任何错误,都是设计事故(这种需要发布固件修复或者召回),或者那台电脑已经是寿命到期、应该当电子垃圾扔掉的报废品!

神特么的“理应产生错误”。

对不起,业界没那么拉胯。


事实上,早年业界也担心——啊,家用机错点无所谓;服务器错了可不行……

所以服务器内存是特制的,专门带个 ECC 校验芯片——其实就是每个字节都多存几位用于校验;每次数据读写都先校验,出错了能立即报告……

但后来芯片稳定性实在太高,好多年前开始,很多低端服务器内存就不需要 ECC 了——因为跑几年甚至几十年都一个错误没有,要它干嘛?

要知道,做 ECC 校验可不是免费的。

第一,你得在内存条上加芯片,同时增加一些存储芯片(用来存储校验位,视恢复能力需要不同的额外容量),这样的内存条显然会贵很多。

第二,每次读写都要等 ECC 芯片完成校验;哪怕硬逻辑计算,这个校验起码也得耗费一个时钟周期吧——最最起码也是内存频率提升困难。这就严重拖慢了 ECC 内存的读写速度。

因此当年有个常识,就是服务器内存比家用 PC 机内存要慢。

又贵又慢,就为了预防十年都未必出现一次的错误?

你看,这买卖不划算,对吧。

因此,到了 0x 年代左右(甚至更早),很多服务器内存就不再有 ECC 校验了。

还是那句话:内存到 CPU,这是需要经过主板线路、走上 3~5cm 甚至 10cm 的、弯弯曲曲的蛇行铜线的:

距离这么远、电磁环境复杂、还是如此不靠谱的接插件安装——就这,内存都不需要 ECC,都不担心 CPU- 内存传输出错……你去担心 CPU?

还“理应”?


当然,CPU 的确可能损坏;过度超频、散热太不讲究造成过热、供电垃圾、电离射线(宇宙射线)干扰……这些的确可能使得 CPU 在运算时产生错误。

但,这是极其极其偶然的特殊情况。别超频、检测温度确保散热合格、买正规厂商的主板/电源、别把民用设备发射到外太空……那么,整个计算机系统几乎就不可能出现任何错误。

一台正常的电脑,连续跑十年不出错是基本要求。

没有“理应”,谢谢。


那么,如果我们就是遇到了这种十年不遇的故障呢?

一台电脑跑十年不出错;但我一个集群 100 万台电脑,也能不出错?

比如,评论区/另一个回答提到的 SDC(silent data corruption):

Mitigating the effects of silent data corruption at scale

就是大规模集群里、个别服务器/CPU 核心出错导致的。

其实,更早的时候,大约是 06 或者 08 年前后,google 也给出过一个报告(现在没有中文版了);报告声称,平均每多少次电压波动,会造成 1 次服务下线;每多少次机箱晃动(比如楼下开过辆汽车),会造成 1 次计算错误……

此外,空调失效、风扇失效、灰尘、空气湿度等等,都可能影响服务器的稳定性,使得它们出现各种各样的问题。

对于普通用户来说,我们会发现“硬件不稳定了”“经常蓝屏”“花屏”“软件莫名其妙报错”等等;然后要么打开机箱一番清理恢复正常,要么机器报废。

但对服务器厂商来说,情况是完全不一样的。因为机器太多、也不可能派人蹲着观察每一台机器;严重到“花屏”程度的错误也是没有任何硬件识别/警告的——这其实就是 SDC(Silent Data Corruption)。

注意了,并不是每个人都有实践经验,更不是每个人都会读论文——SDC 是机房里某些锈了的插槽、没插紧的内存条、热稳定性不好的 CPU/GPU 造成的,并不是正常 CPU/GPU 的普遍现象

这个时候,应该怎么办呢?究竟会发生什么?

首先,纠正一点:

现代常规计算机里面,不存在什么纠错/校验一说

没这种东西。

原因前面说过了,拖慢计算速度,增加成本——又贵又慢又没用。

只有中高端的、稳定性极其重要的服务器才有 ECC 内存;但这个东西只能检测内存数据有效性,并不能检测 CPU 运算错误

后面会讲到,仅仅“检查内存数据有效性”是不可能发现所有错误的;因此 ECC 出错是一个类似硬盘 S.M.A.R.T 信息的警告信息,并不是“常规恢复手段”——根据 Intel 手册,一台机器的一个内存模块,如果 24 小时内出现 10 次可恢复的 ECC 错误或者任何不可恢复的 ECC 错误,都是需要停机开箱检修的。

类似的,评论区我点了某些人一句。奈何榆木疙瘩点不醒

那算了。点不醒就继续睡着。在下的时间也不是大风刮过来的,不对个别人脑壳里的错误负责。

你可以自己试一试,在两块硬盘之间拷贝 1T 的数据;拷完,用软件计算和比较一下原始数据/新增数据的检验和(如果你用 Linux 的话,可以用 cat 命令配合 md5sum 之类命令完成计算)。

我的经验告诉我,正常的服务器、正常的用户家用电脑,你就是拷贝 1P 的数据,这些数据经过磁盘 A、DMA 芯片、内存缓冲区、CPU 核心、内存缓冲区 2、DMA 芯片、磁盘 B 这样一条漫长曲折、速度不一机制复杂协议多变的路径,它仍然是连一个 bit 都不可能错的。

经常用 cat /data | tar -cvzf backup.tar.gz 命令备份数据的、有经验的管理员都知道这一点——哪怕这个备份超过 1T,它也是一次就正确完成:如果真出错了,那么这台服务器(里面的某些硬件)差不多也该报废了。

什么每拷贝 512M 字节就出错的烂电脑……那破玩意儿能用?还不赶紧借点钱买台能用的

那么,如果真出错了,怎么办呢?

首先要知道一点:程序也是数据;指令代码也是二进制数字。

什么意思呢?

如果真搞错了,数据传输出错、跳转地址算错,那么:

  • 机器码指令本身会改变,出现非法指令

  • 并不是每个二进制值都是有效指令

发现非法指令当然就应该立即报错、退出

  • 访问地址出错,比如:

  • 访问了不存在的地址

现代计算机每个内存页面都会有一些访问标记

  • 比如 code 页面只读、比如特权页面必须有权限才能访问

如果错误访问了这些页面,就会报告“xx 处的内存只能为读”“xx 地址不可访问”之类提示

  • 这是微软式中文,正确说法应该是 xx 地址处的内存访问权限限制为只读

  • 当然,单片机或者早期的 PC CPU 可能不区分指令和数据、也没有内存页面权限

  • 这种系统跳转到错误地址,就可能若无其事的继续执行

  • 术语叫“跑飞”

  • CPU 内部会设计一些计数器,好像定时炸弹一样倒计时

  • 这叫看门狗

操作系统/单片机系统的设计者有责任定时重置这些计数器

  • 这些计数器应该在每个操作完成后重置

如果出现了故障、使得程序跳转到其它地方执行,那么重置计数器这个工作就会被延误

如果计数器走到 0 还没有重置,那么 CPU 就会立即报错、重启

  • 这个设计可以发现程序“跑飞”并给出错误

  • 数据出错没有很好的办法,可能只能通过“除 0 错”之类数学/逻辑错误识别

以上,就是硬件能给你的全部。再往上就是软件的事情了。

比如,网络传来的数据报文,在互联网上传输了几千甚至上万公里才到你手里;这些数据甚至可能被黑客窥伺、篡改……这该怎么办呢?

这时候,就要走软件协议了。

软件协议

比如,TCP/UDP 协议都包含了一个“报文校验和”字段:

当数据传输出错时,按照一定的算法计算,和这个校验和比较,就会知道了。然后丢掉这个封包,要求对端重传即可。

这个东西因为用的太多、而且早就成了固定标准,因此它虽然是一个软件协议,但实践上往往是用硬件直接计算的。这样速度更快、消耗更低。

不过这个东西并不能抵抗篡改:

tcp的传输过程是可靠的,那为什么许多较大的下载最终还要校验文件完整性?2860 赞同 · 150 评论回答

所以,很多软件在设计时,会在 TCP/UDP 等协议之上,再增加一层验证,甚至是增加一层“签名”——熟悉密码学的朋友都知道,签名是无法伪造的,一旦数据被篡改,签名就一定会被破坏。

比如,著名的 bitTorrent 协议这个允许大量用户 PC 共同参与的、分布式文件传输项目,它就会检查每个 trunk 数据的校验和——而常用的 ftp 或者 http 协议完全不管这些,是有可能下载到错误的数据的。

再比如,Linux 的软件仓库经常是有签名的。这可以确保你从镜像站下载的组件没有被人篡改,给你植入点什么。

不过这扯得有点远了,不再多谈。

类似的,比如我们程序员设计一个软件时,也会考虑到硬件出错的可能。尤其是涉财、涉密、涉人身安全的领域,更是一点差错不能有。那怎么办呢?

简单说,就是在一些要害位置设置校验,比如检查参数合法性、用另外的算法复核计算结果,等等。

甚至,对一些要害项目,我们还可以把一个工作交给两台以上的服务器同时执行,然后各自独立给出计算结果、交给“仲裁节点”仲裁——如果两台以上服务器计算结果相同,就接受;否则给出报警、回滚(或少数服从多数:毕竟机器出现硬件错误已经近乎不可能了,两台机器同时出现一样的错误更加罕见)。

当然,如果仲裁节点本身出了问题也是个麻烦事(这叫单点失效),也是在系统设计时就要想办法预防、识别和解决的。

不过,还是那句话,任何校验都是有代价的;ECC 的恢复能力也有其极限

当一个系统误码率高到一定程度时,纠错的代价就会越来越大、乃至完全侵吞掉频率提升带来的好处。

因此,虽然前些年向稳定度开刀,降低 CPU/内存的电压以提升频率(从早年的 5v、3.3v 一路下降到现在的 1.3v 甚至 1.1v,数字电路的稳定度其实就来自于它是“开关”电路,通断之间的电压差太大太好区分了;供电电压低了,电压差自然降低,稳定性就受影响);但这个提升除非能“大跃进”,否则反而是得不偿失的——快了 0.5%,却需要付出额外 5% 的性能去识别和恢复数据、还要冒错误数据识别不出来、恢复不了的风险,这显然就亏太多了。

比如,识别 1bit 错误和 2bit 错误的 ECC 码长度是不一样的;纠正 1bit 错误和 2bit 错误的 ECC 码要求会更高一些——而3bit 错误是可能在“能够识别 2bit 错误”的 ECC 码眼前蒙混过关的:想想这有多可怕!

因此,起码迄今为止,人类的 CPU/内存仍然靠的是自身的稳定性而不是“恢复能力”——当然,因为它挖了稳定性的墙角,所以现在 ECC 之类需求的确比过去强劲了。

但无论如何,除非卫星通讯这样干扰严重、误码率超高的场合,信息业的基础是不可能坐在 polar 码(一种类似二维码的、可以容忍大量传输错误的通讯编码方法)基础上的。尤其是的 CPU 计算,你想校验它的每一步计算结果正确与否,那么 CPU 性能恐怕得打个对折。

投入产出比太差了。

除了这些,CPU 本身还可能存在一些隐藏的 bug;这些 CPU 经常出货量非常大、或者是专门设计的所以成本非常高,那么“带病运行”可能就成了唯一选择。

怎么应对“CPU 本身有错”这种状况呢?

这个就比较复杂了,需要针对每个 CPU 型号的每个错误具体分析。

比如,如果 CPU 在计算特定浮点数时出现了故障,那么可以在固件里识别这种问题,发现相应指令就用软件算法替代,别丢给 CPU 浮点数单元了——当然,此时性能肯定没法看了。

而且,有时候这种 bug 是无法修复的,因为它的发生条件不确定或者不是那么容易检测。比如奔腾四浮点数 bug,可能就只能禁用它的 fpu、全部用软件替代了。这个代价显然无法接受,只能召回。

再比如,时序 bug:一条指令本来预计两个时钟周期出结果,结果造出来寄生电容有点大、五个时钟周期电路状态才能稳定……

怎么办?

遇到这种指令,就在后面补 NOP,连续补 3 个 NOP 就没事了——4 个更稳定,但性能代价更大。

诸如此类。

当然,如你所见,这类状况往往需要付出比较大的性能代价。但跑的慢点总比不能用好……

话说当初 intel 的熔断(Meltdown)/幽灵(Spectre)bug,后来提交给 Linux 的补丁就导致性能损失 15%,所以就被 Linus 喷了满头满脸的 F-words。

https://www.bilibili.com/video/BV1eW411i7ZM/

不是,这个“理应”是谁给你的理由啊?怎么就这么理直气壮的?

还有下面的回答,一片片的,真就莫名其妙的“理应”起来了?


首先告诉你一点:别说 CPU 内部、机箱内部了;就最垃圾的、刚刚能支持 1000Base-T 的 cat5e 双绞线传输电磁信号——这玩意儿没有屏蔽、全程被外界复杂的电磁波环境干扰、还要把电信号传输 100 米——最终的误码率都小于 10^-10!

没错,10^-10,10000000000bit 数据只允许 1bit 出错!

一百亿分之一的出错概率!

低于这个概率就不符合 IEEE802.3 标准,做出这种破烂的企业就只能倒闭。

事实上,使用正规设备、正常设计、布线的网络,跑 10 年一个 bit 都没错过,这才是正常的。

这可是远程通讯!

机箱内通讯,误码率会小的多得多——正常情况下,CPU 内几乎完全不会产生错误:有任何错误,都是设计事故(这种需要发布固件修复或者召回),或者那台电脑已经是寿命到期、应该当电子垃圾扔掉的报废品!

神特么的“理应产生错误”。

对不起,业界没那么拉胯。


事实上,早年业界也担心——啊,家用机错点无所谓;服务器错了可不行……

所以服务器内存是特制的,专门带个 ECC 校验芯片——其实就是每个字节都多存几位用于校验;每次数据读写都先校验,出错了能立即报告……

但后来芯片稳定性实在太高,好多年前开始,很多低端服务器内存就不需要 ECC 了——因为跑几年甚至几十年都一个错误没有,要它干嘛?

要知道,做 ECC 校验可不是免费的。

第一,你得在内存条上加芯片,同时增加一些存储芯片(用来存储校验位,视恢复能力需要不同的额外容量),这样的内存条显然会贵很多。

第二,每次读写都要等 ECC 芯片完成校验;哪怕硬逻辑计算,这个校验起码也得耗费一个时钟周期吧——最最起码也是内存频率提升困难。这就严重拖慢了 ECC 内存的读写速度。

因此当年有个常识,就是服务器内存比家用 PC 机内存要慢。

又贵又慢,就为了预防十年都未必出现一次的错误?

你看,这买卖不划算,对吧。

因此,到了 0x 年代左右(甚至更早),很多服务器内存就不再有 ECC 校验了。

还是那句话:内存到 CPU,这是需要经过主板线路、走上 3~5cm 甚至 10cm 的、弯弯曲曲的蛇行铜线的:

距离这么远、电磁环境复杂、还是如此不靠谱的接插件安装——就这,内存都不需要 ECC,都不担心 CPU- 内存传输出错……你去担心 CPU?

还“理应”?


当然,CPU 的确可能损坏;过度超频、散热太不讲究造成过热、供电垃圾、电离射线(宇宙射线)干扰……这些的确可能使得 CPU 在运算时产生错误。

但,这是极其极其偶然的特殊情况。别超频、检测温度确保散热合格、买正规厂商的主板/电源、别把民用设备发射到外太空……那么,整个计算机系统几乎就不可能出现任何错误。

一台正常的电脑,连续跑十年不出错是基本要求。

没有“理应”,谢谢。


那么,如果我们就是遇到了这种十年不遇的故障呢?

一台电脑跑十年不出错;但我一个集群 100 万台电脑,也能不出错?

比如,评论区/另一个回答提到的 SDC(silent data corruption):

Mitigating the effects of silent data corruption at scale

就是大规模集群里、个别服务器/CPU 核心出错导致的。

其实,更早的时候,大约是 06 或者 08 年前后,google 也给出过一个报告(现在没有中文版了);报告声称,平均每多少次电压波动,会造成 1 次服务下线;每多少次机箱晃动(比如楼下开过辆汽车),会造成 1 次计算错误……

此外,空调失效、风扇失效、灰尘、空气湿度等等,都可能影响服务器的稳定性,使得它们出现各种各样的问题。

对于普通用户来说,我们会发现“硬件不稳定了”“经常蓝屏”“花屏”“软件莫名其妙报错”等等;然后要么打开机箱一番清理恢复正常,要么机器报废。

但对服务器厂商来说,情况是完全不一样的。因为机器太多、也不可能派人蹲着观察每一台机器;严重到“花屏”程度的错误也是没有任何硬件识别/警告的——这其实就是 SDC(Silent Data Corruption)。

注意了,并不是每个人都有实践经验,更不是每个人都会读论文——SDC 是机房里某些锈了的插槽、没插紧的内存条、热稳定性不好的 CPU/GPU 造成的,并不是正常 CPU/GPU 的普遍现象

这个时候,应该怎么办呢?究竟会发生什么?

首先,纠正一点:

现代常规计算机里面,不存在什么纠错/校验一说

没这种东西。

原因前面说过了,拖慢计算速度,增加成本——又贵又慢又没用。

只有中高端的、稳定性极其重要的服务器才有 ECC 内存;但这个东西只能检测内存数据有效性,并不能检测 CPU 运算错误

后面会讲到,仅仅“检查内存数据有效性”是不可能发现所有错误的;因此 ECC 出错是一个类似硬盘 S.M.A.R.T 信息的警告信息,并不是“常规恢复手段”——根据 Intel 手册,一台机器的一个内存模块,如果 24 小时内出现 10 次可恢复的 ECC 错误或者任何不可恢复的 ECC 错误,都是需要停机开箱检修的。

类似的,评论区我点了某些人一句。奈何榆木疙瘩点不醒

那算了。点不醒就继续睡着。在下的时间也不是大风刮过来的,不对个别人脑壳里的错误负责。

你可以自己试一试,在两块硬盘之间拷贝 1T 的数据;拷完,用软件计算和比较一下原始数据/新增数据的检验和(如果你用 Linux 的话,可以用 cat 命令配合 md5sum 之类命令完成计算)。

我的经验告诉我,正常的服务器、正常的用户家用电脑,你就是拷贝 1P 的数据,这些数据经过磁盘 A、DMA 芯片、内存缓冲区、CPU 核心、内存缓冲区 2、DMA 芯片、磁盘 B 这样一条漫长曲折、速度不一机制复杂协议多变的路径,它仍然是连一个 bit 都不可能错的。

经常用 cat /data | tar -cvzf backup.tar.gz 命令备份数据的、有经验的管理员都知道这一点——哪怕这个备份超过 1T,它也是一次就正确完成:如果真出错了,那么这台服务器(里面的某些硬件)差不多也该报废了。

什么每拷贝 512M 字节就出错的烂电脑……那破玩意儿能用?还不赶紧借点钱买台能用的

那么,如果真出错了,怎么办呢?

首先要知道一点:程序也是数据;指令代码也是二进制数字。

什么意思呢?

如果真搞错了,数据传输出错、跳转地址算错,那么:

  • 机器码指令本身会改变,出现非法指令

  • 并不是每个二进制值都是有效指令

发现非法指令当然就应该立即报错、退出

  • 访问地址出错,比如:

  • 访问了不存在的地址

现代计算机每个内存页面都会有一些访问标记

  • 比如 code 页面只读、比如特权页面必须有权限才能访问

如果错误访问了这些页面,就会报告“xx 处的内存只能为读”“xx 地址不可访问”之类提示

  • 这是微软式中文,正确说法应该是 xx 地址处的内存访问权限限制为只读

  • 当然,单片机或者早期的 PC CPU 可能不区分指令和数据、也没有内存页面权限

  • 这种系统跳转到错误地址,就可能若无其事的继续执行

  • 术语叫“跑飞”

  • CPU 内部会设计一些计数器,好像定时炸弹一样倒计时

  • 这叫看门狗

操作系统/单片机系统的设计者有责任定时重置这些计数器

  • 这些计数器应该在每个操作完成后重置

如果出现了故障、使得程序跳转到其它地方执行,那么重置计数器这个工作就会被延误

如果计数器走到 0 还没有重置,那么 CPU 就会立即报错、重启

  • 这个设计可以发现程序“跑飞”并给出错误

  • 数据出错没有很好的办法,可能只能通过“除 0 错”之类数学/逻辑错误识别

以上,就是硬件能给你的全部。再往上就是软件的事情了。

比如,网络传来的数据报文,在互联网上传输了几千甚至上万公里才到你手里;这些数据甚至可能被黑客窥伺、篡改……这该怎么办呢?

这时候,就要走软件协议了。

软件协议

比如,TCP/UDP 协议都包含了一个“报文校验和”字段:

当数据传输出错时,按照一定的算法计算,和这个校验和比较,就会知道了。然后丢掉这个封包,要求对端重传即可。

这个东西因为用的太多、而且早就成了固定标准,因此它虽然是一个软件协议,但实践上往往是用硬件直接计算的。这样速度更快、消耗更低。

不过这个东西并不能抵抗篡改:

tcp的传输过程是可靠的,那为什么许多较大的下载最终还要校验文件完整性?2860 赞同 · 150 评论回答

所以,很多软件在设计时,会在 TCP/UDP 等协议之上,再增加一层验证,甚至是增加一层“签名”——熟悉密码学的朋友都知道,签名是无法伪造的,一旦数据被篡改,签名就一定会被破坏。

比如,著名的 bitTorrent 协议这个允许大量用户 PC 共同参与的、分布式文件传输项目,它就会检查每个 trunk 数据的校验和——而常用的 ftp 或者 http 协议完全不管这些,是有可能下载到错误的数据的。

再比如,Linux 的软件仓库经常是有签名的。这可以确保你从镜像站下载的组件没有被人篡改,给你植入点什么。

不过这扯得有点远了,不再多谈。

类似的,比如我们程序员设计一个软件时,也会考虑到硬件出错的可能。尤其是涉财、涉密、涉人身安全的领域,更是一点差错不能有。那怎么办呢?

简单说,就是在一些要害位置设置校验,比如检查参数合法性、用另外的算法复核计算结果,等等。

甚至,对一些要害项目,我们还可以把一个工作交给两台以上的服务器同时执行,然后各自独立给出计算结果、交给“仲裁节点”仲裁——如果两台以上服务器计算结果相同,就接受;否则给出报警、回滚(或少数服从多数:毕竟机器出现硬件错误已经近乎不可能了,两台机器同时出现一样的错误更加罕见)。

当然,如果仲裁节点本身出了问题也是个麻烦事(这叫单点失效),也是在系统设计时就要想办法预防、识别和解决的。

不过,还是那句话,任何校验都是有代价的;ECC 的恢复能力也有其极限

当一个系统误码率高到一定程度时,纠错的代价就会越来越大、乃至完全侵吞掉频率提升带来的好处。

因此,虽然前些年向稳定度开刀,降低 CPU/内存的电压以提升频率(从早年的 5v、3.3v 一路下降到现在的 1.3v 甚至 1.1v,数字电路的稳定度其实就来自于它是“开关”电路,通断之间的电压差太大太好区分了;供电电压低了,电压差自然降低,稳定性就受影响);但这个提升除非能“大跃进”,否则反而是得不偿失的——快了 0.5%,却需要付出额外 5% 的性能去识别和恢复数据、还要冒错误数据识别不出来、恢复不了的风险,这显然就亏太多了。

比如,识别 1bit 错误和 2bit 错误的 ECC 码长度是不一样的;纠正 1bit 错误和 2bit 错误的 ECC 码要求会更高一些——而3bit 错误是可能在“能够识别 2bit 错误”的 ECC 码眼前蒙混过关的:想想这有多可怕!

因此,起码迄今为止,人类的 CPU/内存仍然靠的是自身的稳定性而不是“恢复能力”——当然,因为它挖了稳定性的墙角,所以现在 ECC 之类需求的确比过去强劲了。

但无论如何,除非卫星通讯这样干扰严重、误码率超高的场合,信息业的基础是不可能坐在 polar 码(一种类似二维码的、可以容忍大量传输错误的通讯编码方法)基础上的。尤其是的 CPU 计算,你想校验它的每一步计算结果正确与否,那么 CPU 性能恐怕得打个对折。

投入产出比太差了。

除了这些,CPU 本身还可能存在一些隐藏的 bug;这些 CPU 经常出货量非常大、或者是专门设计的所以成本非常高,那么“带病运行”可能就成了唯一选择。

怎么应对“CPU 本身有错”这种状况呢?

这个就比较复杂了,需要针对每个 CPU 型号的每个错误具体分析。

比如,如果 CPU 在计算特定浮点数时出现了故障,那么可以在固件里识别这种问题,发现相应指令就用软件算法替代,别丢给 CPU 浮点数单元了——当然,此时性能肯定没法看了。

而且,有时候这种 bug 是无法修复的,因为它的发生条件不确定或者不是那么容易检测。比如奔腾四浮点数 bug,可能就只能禁用它的 fpu、全部用软件替代了。这个代价显然无法接受,只能召回。

再比如,时序 bug:一条指令本来预计两个时钟周期出结果,结果造出来寄生电容有点大、五个时钟周期电路状态才能稳定……

怎么办?

遇到这种指令,就在后面补 NOP,连续补 3 个 NOP 就没事了——4 个更稳定,但性能代价更大。

诸如此类。

当然,如你所见,这类状况往往需要付出比较大的性能代价。但跑的慢点总比不能用好……

话说当初 intel 的熔断(Meltdown)/幽灵(Spectre)bug,后来提交给 Linux 的补丁就导致性能损失 15%,所以就被 Linus 喷了满头满脸的 F-words。

https://www.bilibili.com/video/BV1eW411i7ZM/