思维的串行化要求
本文简单思考一下硬件设计如何突破思维的限制。
有一种说法:现实是并行化的,思维是串行化的。花朵从枝头掉落在泥淖中,组成花朵的 每个分子都在运动,我们只看到“花朵”这个单一的对象(名,抽象)在运动,而且我们要 思考它第一步掉落到哪里,第二步又掉落在哪里……如果我们不这样思考,就没有思考。没 有思考就没有“观察”和“控制”,只剩下恍惚。
思考是用名构造的“因果”来组成的,我们总是要对一个状态进行抽象,然后思考在这个状 态下,下一个状态(的名)是什么。这一点无论对软件还是硬件都是一样的。
所以,为什么硬件可以对软件的要求并行化呢?看一个例子:::
1:
2: a1 = b1 + c1
3:
4: a2 = b2 + c2
5:
硬件可以同时执行这两条指令,核心是“人”在3这个位置没有观察要求,而在5这个位置上 的观察者,在2和4上的顺序,无法观察出不一样。
当然,显而易见地,在我们的算法中,4对2也没有观察的要求,如果4修改成a2=a1+c1。在 我们的算法中,程序员在4的位置上要求观察a1,而且认为这个a1是2的一个“果”。
这一点和执行者是软件还是硬件没有关系,这是个语义问题。所以我们现在开始,抛开软 件硬件这样的概念,用“要求者”和“执行者”这两个抽象的概念来考虑这个问题。
如前所述,上面2和4可以同时执行,条件是5上的观察者看不到区别,这是语义决定的,因 为我们的语义是个观察上的抽象,如果我们增加一种观察,让这个系统的赋值有"退火"效 应,a1和a2被赋值后,会随着时间慢慢降低为0,执行的先后顺序会影响在5上观察到两者 谁先完成退火,这个同步执行也不能实施。
抛开要求者的“观察”的因果,就没有执行者的自由度。所以提高执行者的自由度的唯一方 式是优化要求者下达要求的边缘要素。比如弱内存顺序模型,不要求2和4有先后关系,如 果你要强制先后关系,你必须主动提出要求,比如在3上加一个fence指令,区分两者的先 后关系。
这一点在遇到观察点之前,也是可以优化的。因为观察者的观察点在内存读写上,执行者 在有fence的情况下也可以同步执行2和4,到写入cache同步点的时候再排队,只要观察者 分不出区别就可以了。
你设计一个算法,必然有一组观察及其因果落实在其中的,你要并行,就要提高你的命令 的灵活性,尽量减少下命令的语义的边界效应,不要下达了额外的限制。此外你就只剩下 猜了(比如cache prefetch或者分支预测)。
我想说的是,失去了“要求者”的配合,执行者在并行上能实施的优化是很有限的。要改变
你这个问题,就要改变要求者提要求的方法,也就是改变他的逻辑链。我们今天的编程语
言很多都是直接针对数学逻辑直接定义行为的,比如OpenMP和支持Loop unrolling的语法
,都是在算法上提供描述一组的“共同”行为的“同时”语义(比如这个:
:doc:从C的for和Python的for聊起
)。所以这个方向不是那么容易的,没有算法语义本
身的进步,工程人员是很难取得进展的。这个努力方向只能放到具体的算法设计上来做,
你可以看看现在的算法实现,哪里还有描述的边缘效应导致你无法同步做某些事情,破坏
掉这个以来约束,就可以取得进步了。
现在最有可能取得进展的,我觉得可能都是特定的算法下,找到写得不好的程序某个 Pattern进行某种强行语义修改,由于其他模式确实几乎不存在,这种优化可能会很有效, 但这种优化很难说能控制得了架构方向的,甚至会让架构更加不可预期,要求者的意志无 法从系统取得确切反馈,这会让系统提早进入混沌状态的。
补充1:(20200807)
本文的结论即使面对“无逻辑”部分也是成立的。有一个例子是这样的,有一种编程语言, 提供了一套语义逻辑,让要求者描述了一个算法,但编译器在编译后,经过一个可能很复 杂的算法,比如通过形式化验证的方法证明某些步骤不是必须的,自动删除了一些步骤, 最终也可以得到要求者的结果。这种情况下,看起来好像违背了要求者的观察。但其实是 看到要求者真正的观察目标,从而让某些观察目标变得不重要而已。这个行为和原文提到 的策略并没有任何冲突之处。