17  增益与延迟

章节 1 里留了一个问题:两堵墙的形状是一样的,但没说那个形状叫什么。 这一章给它一个名字,然后用这个名字预测下一堵墙会在哪 —— 后半句才是这一章存在的理由,因为一个只能解释过去的框架不值得学。

17.1 两个变量

先做两个翻译。

Agent 的吞吐是回路增益。 增益的定义是每单位测得的误差, 你施加多少修正;更多的 Agent 并行,意味着单位时间里施加的修正更多。 流水线的延迟是回路延迟,也就是从改动产生到判定回到 Agent 手里 中间隔了多久。这个仓库里的实测值是:结构检查中位 5.2 分钟, UI 与端到端测试中位 14.9 分钟,而从红灯到最终转绿的中位时间是 1.4 小时, 长尾接近二十小时。

有了这两个变量,控制论里最基本的一条结论就能用上了: 在有延迟的系统里提高增益,会导致失稳; 延迟带来的问题,不能靠加大增益来解决。

这句话在工程上的直觉版本是:一个反应很快但要等很久才知道结果的控制器, 会不停地过冲、反向过冲、再过冲 —— 它越努力,抖得越厉害。 洗澡时调水温是每个人都有的体感:管道有延迟, 而一个不耐烦的人拧得越猛,水温摆得越厉害。

17.2 两堵墙的重新表述

现在把两堵墙翻译一遍。

墙一是增益上去了,反馈路径的带宽没变。 人审是一个极低带宽的 传感器兼控制器 —— 一天能处理的 diff 数是个位数, 而且这个数不随投入线性增长,因为第二个审查者不会让审查速度翻倍, 他们要看的是同一批代码。往这样一个回路里灌几十个 Agent,结果只能是排队。

墙二是反馈路径的带宽扩了,但测量的对象没有缩小。 买机器等价于把传感器的采样率提上去,但如果每次采样都要测量整个状态空间 —— 每条改动都跑全量检查 —— 那么采样率的提升会被测量成本的增长吃掉。

真正的解法不是继续扩带宽,是缩小测量。 查反向依赖图、只测本次真正变化的那部分,在控制里的名字是稀疏测量: 你不需要观测全部状态,只需要观测那些实际发生了变化的维度。 第二次买机器不管用而查依赖图管用,原因就在这里 —— 这两者不是程度差异,是性质差异,一个在扩大分子,一个在缩小分母。

17.3 为什么测试金字塔其实是串级控制

小节 12.1 里说,金字塔的形状是被成本逼出来的:越往上一层, 一次判定越贵,而覆盖的路径反而最少,所以要把判定尽量下沉到便宜的那一层。 成本是对的,但它不是主要理由。主要理由是稳定性。

一个快内环(结构检查,5.2 分钟)加一个慢外环(端到端,14.9 分钟) 是一个标准的串级控制结构:

flowchart LR
  D["改动"] --> IN
  subgraph IN["内环 · 5.2 分钟"]
    G["结构检查<br/>格式 · 依赖方向 · 危险配置"]
  end
  IN -->|"抑制掉大部分扰动"| OUT
  subgraph OUT["外环 · 14.9 分钟"]
    E["端到端<br/>真正需要跑起来的行为"]
  end
  OUT --> M["合入"]
  IN -.->|"5 分钟内返回"| D
  OUT -.->|"15 分钟后返回"| D

内环快速抑制大部分扰动 —— 格式、依赖方向、危险配置, 这些在五分钟内就被打掉了,根本传不到外环; 外环只处理内环漏过来的那一小部分,也就是真正需要把程序跑起来 才能发现的行为问题。

串级控制有一个前提,而且这个前提是定量的:内环必须显著快于外环。 如果两个环的时间常数接近,串级不会带来任何好处, 反而会因为多了一层而增加复杂度。这给出一个可以直接用的判据 —— 如果你的静态检查和你的端到端测试耗时在同一个量级, 那你没有串级,你只有两个并联的慢环。

这个仓库里的比值是 5.2 : 14.9,接近 1:3,这是一个能工作的串级。 在很多团队里,静态检查和单元测试都要跑十几分钟 —— 那里没有内环, 而没有内环意味着每一个格式问题都要花和一次端到端失败同样长的时间才被发现。

17.4 采样周期:另一个被撞对的结论

小节 8.7.2 讲过,周期任务的节奏由外部系统的反馈延迟决定 —— 投放报表按日结算就日级采样,商店审核加重新索引要一周就周级采样。 这条在控制里叫采样周期匹配对象时间常数, 而它的理由比”看不到效果”更硬。

一个被控对象有它自己的响应速度。你以远快于这个速度的频率去采样, 采到的不是它的状态,是它的噪声 —— 因为在两次采样之间, 对象根本还没有对上一次的输入做出反应,你看到的变化全部来自别的东西。

这还不是最坏的。最坏的是你会依据这些噪声动作。 于是回路开始追噪声:报表今天跌了 3%,调低出价;明天涨回来了,调高; 后天又跌,再调低。每一次调整都在给系统注入一个新的扰动, 而这些扰动的效果会在一天后到达、和当时的调整完全对不上号 —— 一个本来会自己稳定下来的系统,被采样过快的控制器搅成了振荡。

大部分人会为了”响应快”把这类回路设成小时级。这个直觉在 延迟很小的系统里是对的(比如一个 5 分钟就能看到效果的 A/B 实验), 在延迟以天计的系统里是灾难性的。判据很简单: 采样周期不应短于对象的响应时间。如果你不知道对象的响应时间, 那么第一件该做的事是测量它,而不是先定一个”感觉合理”的频率。

17.5 稳定裕度正在缩

现在用这个框架做一个预测。

增益在涨:Agent 数量在涨,单日合入次数从个位数涨到峰值五十二次。 延迟基本不动:流水线的中位耗时由测试本身的性质决定, 它不会随仓库变大而变快,只会变慢。 增益上升、延迟不变,意味着相位裕度在缩 —— 这个系统正在被自己的成功推向稳定边界。

失稳在这里会长成什么样?不是崩溃,是返工振荡: 一个改动红了,“修好”之后又红了,再修再红。 现有数据里已经有这个形状的影子 —— 平均每个改动跑 1.7 条流水线, 而被拦得最狠的两个各红了四次,其中一个跨了将近二十个小时。

⚠️ 这里有一条对源系统的具体建议:把振荡次数做成时间序列。 这个仓库测量了大量关于代码的东西,但没有测量回路本身。 控制工程师会仪表化上升时间、超调量、振荡次数、稳态误差, 而”红→绿→红”的次数是这套系统最直接的稳定性指标, 也是增益与延迟失配的先行指标 —— 它会在系统真正出问题之前先涨起来。原始数据都在流水线记录里, 缺的只是把它当成一条曲线看。

17.6 延迟的四个组成部分

在讨论怎么降延迟之前,先把它拆开,因为四个部分的可压缩性差别很大:

组成 这套系统的实测 可压缩性
排队 取决于负载 —— 加机器或缩小测量
测量本身 结构检查 5.2 分 / 端到端 14.9 分 中 —— 有物理下界
人的介入 这套系统里近乎为零 ———
Agent 的理解与重试 未测量 未知

第一行是这套系统压缩得最成功的部分 —— 从”每条改动跑全量”到”只跑受影响的”,压缩的正是排队。 第四行是完全没有被测量的部分,而它可能是现在最大的那一块。

算一下就知道。从红灯到转绿的中位时间是 1.4 小时, 而流水线本身的中位耗时远小于这个数(结构检查 5.2 分钟, 端到端 14.9 分钟)。平均每个改动跑 1.7 条流水线, 所以流水线时间大概是半小时上下 —— 剩下的那一个多小时,是 Agent 在读失败、理解、修改、重新提交。

这意味着回路延迟里最大的一块,可能不在基础设施上, 而在”失败信息的质量”上。如果这个推测成立, 那么改善失败信息的收益可能高于再买一批机器, 而前者的成本低几个数量级。这也就是为什么 小节 13.4.4 那条纪律(失败时把 owner、证据和下一步一起给出去) 不是用户体验问题,是延迟问题。

17.7 立刻可以做的测量

我对这套系统的第一条建议,在这里给出具体形态。 需要采集的三个数,全都已经存在于流水线记录里:

每个改动:
  ① 提交时间 → 第一次判定返回的时间     = 测量延迟
  ② 第一次红灯 → 最终转绿的时间          = 完整回路延迟
  ③ 跑了几条流水线                       = 振荡次数

画三条按周的曲线。要看的不是绝对值,是趋势和它们之间的关系

观察 意味着
① 平,② 涨,③ 涨 增益超前于延迟,稳定裕度在缩
① 涨,② 涨,③ 平 测量变慢了,但回路还稳
① 平,② 平,③ 涨 失败信息的质量在下降
全平 系统稳态

第三行是最容易被忽略的一种:基础设施没有变慢, 但 Agent 需要更多轮才能修好 —— 这通常意味着新加的规则给出的信息不够, 或者失败被归到了错误的类别。三条曲线,一张图,而数据已经在那儿了。

17.8 三条出路

控制论对”增益必须涨、但延迟降不下来”这个局面,给出三条路。

第一条是继续降延迟,也就是这个仓库已经在走的路 —— 稀疏测量、缓存复用、分片并行。但这条路有下界: 某些判定就是需要把程序跑起来,而那个时间压不掉。

第二条是加微分作用,也就是对误差的变化率动作, 而不是只对误差动作。翻译成工程语言就是: 在跑完整流水线之前,预判哪些改动会红,并分流处理。 现在所有改动走的是同一条路径、同样的判定强度,这是定增益; 而路径清单里已经有风险等级了,只是那个等级调的是”检查什么”, 不是”回路压多紧”。风险分级的增益调度是这个框架直接给出、 而经验推不出来的下一步。

第三条是降增益,也就是少开一些 Agent。这条路在这里不太可能被选, 但它必须被列出来 —— 因为如果前两条走不通,这就是唯一剩下的选项, 而且它比失稳好。 一个能持续产出的低增益系统, 胜过一个把大部分算力花在返工上的高增益系统。

17.9 增益调度具体长什么样

上一节把”增益调度”列成了下一步,但只给了名字。这一节给形态, 因为一个只有名字的建议和没有建议是一回事。

增益调度在控制里的定义是:控制器的参数随工作点变化, 而不是一组参数用到底。一架飞机在低速和高速下的动力学完全不同, 所以自动驾驶仪的参数按空速切换 —— 用一组参数覆盖全包线, 结果是在两端都不好。

翻到这里,“工作点”是这次改动的风险, “控制器参数”是这条回路压多紧。现在的状态是定增益: 所有改动走同一条路径、同样的判定强度、同样的合入门槛。

具体的形态可以是这样的。一次低风险改动 —— 改一个界面文案、加一条日志、改一份文档 —— 只跑内环,判定在五分钟内返回,允许直接合入。 一次中风险改动跑内环加相关的外环分片,判定在十五分钟内返回。 一次命中最高风险路径的改动,跑全部外环, 并且额外要求一次人的确认(小节 14.23)。

三档的差别不在”检查什么”—— 那个路径清单已经在做了 —— 在”回路的紧度”:判定的完整程度、允许的返工轮数、 以及要不要把人放进这一环。

这个设计有一个不明显的收益。定增益系统里, 低风险改动和高风险改动互相排队 —— 一个改文案的提交要等在一个改迁移的提交后面, 而它们对系统的威胁差着几个数量级。分档之后, 低风险的那条队列几乎不排队, 于是整体的中位延迟会下降,而这个下降不需要任何新机器。

需要说清楚它的代价:风险分档本身会成为一个可以被绕过的东西。 一个想快点合入的人(或 Agent)会倾向于把改动归到低风险档。 所以分档不能由提交者声明,只能由路径推出来 —— 而这恰恰是路径清单已经提供的能力。这条建议之所以可行, 是因为它需要的那个输入已经存在了。

17.10 稀疏测量在代码里长什么样

“只测本次真正变化的子空间”这句话,落到实现上是一万两千多行代码。 值得看它在处理什么,因为它处理的大部分不是”怎么查依赖”, 而是”查不到的时候怎么办”。

有一组测试专门在验证这件事,它构造了四种查询结果: 成功且返回空的,接受(空就是空);失败但产出了完整输出的, 接受输出;失败且没有输出的,报错;输出不是合法编码的,报错

第二种是这组测试的核心:一次退出码非零、但产出了完整结果的查询, 它的结果是被接受的。这看起来很奇怪, 直到你意识到构建图查询在部分目标不可解析时会返回非零退出码, 但它对可解析的那部分给出的答案是正确的。

下一个测试的名字把这条纪律说清楚了 —— “批量查询只接受完整的回退结果”:部分结果在批量场景下是不可接受的, 因为你无法区分”这个目标没有依赖者”和”这个目标没被查到”。 同一种失败,在两个场景下有两个不同的正确处理, 而把它们区分开的是”这次测量的完整性能不能被验证”。 这就是 章节 18 讲的那个判别,出现在了测量的最底层。

17.11 比较基线必须是确定的

稀疏测量有一个前提,它比测量本身更基础: “这次改了什么”必须有一个稳定的答案。 基线一旦浮动,后面所有判定都跟着不稳 —— 同一份代码, 两次运行可能得出不同的影响面,于是跑不同的测试,得出不同的结论。

实现上,基线的确定有一条明确的回退链:新分支推送时 先尝试合并基点,再回退到默认分支。回退链的存在本身就是一个设计决定—— 它意味着”我算不出基线”不是一个可接受的终态, 系统必须给出一个确定的答案,哪怕是一个次优的答案。

这条回退链在代码里是一个枚举加一次分派,而它的第一条分支值得单独看:

pub fn comparison_revision_plan(inputs: &ComparisonInputs) -> Result<RevisionPlan> {
    if let Some(candidate) = nonempty(inputs.merge_request_base.as_deref()) {
        return Ok(RevisionPlan::Exact { candidate, source: MergeRequest });
    }
    if inputs.pipeline_source.as_deref() == Some("merge_request_event") {
        bail!("merge-request diff base is not set");
    }
    // …显式指定的基点,再不行才落到本地候选
}

第二个 if 是这段代码里最要紧的三行:如果当前明确处在一次合并请求里, 而基点却拿不到,它直接失败,不往下走回退链。 换句话说,回退链只在”没有权威答案”的场景下生效, 而在”应该有权威答案却没拿到”的场景下它拒绝猜。

这个区分很容易被写错,而写错的版本看起来更健壮 —— 它在任何情况下都能给出一个基线,于是永远不会因为基线问题而失败。 那正是问题所在:一次合并请求里算错了基线, 意味着”这次改了什么”算错了,于是跑的检查集合是错的, 而输出仍然是绿的。一个总能给出答案的函数, 掩盖了它不该有答案的那些时刻。

这和 小节 11.3 那条纪律并不矛盾, 区别在于基线是可以有合理默认值的,而判定不可以: 算不出基线时退回默认分支,最坏的结果是测多了; 判不了却假装通过,最坏的结果是坏代码进了主干。 能安全回退的地方回退,不能的地方明确报”我判不了”—— 这个区分需要逐个场景做,而它是这套系统里做得最细的地方之一。

17.12 零协调是增益能堆起来的前提

小节 7.10.1 讲过并行的 Agent 之间没有非正式协调, 以及那些原本由沟通维护的边界必须被显式化。 那一节看的是代价,这一节看的是它换来了什么—— 因为这笔交换正是”增益”这个量能堆到现在这个水平的原因。

人的团队规模一大,沟通成本会超线性增长:n 个人之间有 n(n-1)/2 条 需要维护的信息通路,而每一条都要占用真实的时间。 这条曲线是团队规模有上限的根本原因之一 —— 到某个点之后,增加一个人带来的产出,抵不过他给所有人增加的沟通成本。

几十个 Agent 并行的沟通成本是零。 它们不开会、不同步、 不需要知道彼此存在。于是那条超线性的曲线不存在了, 增益可以线性地往上加 —— 加机器、加并发、加工作区, 产出就跟着涨,直到撞上判定这一侧的墙(小节 17.2)。

两堵墙撞得那么快,就是这个缘故。 在人的团队里, 产出速率会先被沟通成本自己限制住, 判定这一侧根本来不及成为瓶颈;而把沟通成本抹掉之后, 产出速率第一次可以自由地涨,于是它在很短的时间里 就顶到了下一个约束 —— 那个一直存在、但从来没被顶到过的约束。

这个观察有一个实际推论:如果你正在考虑”要不要多开几个 Agent”, 真正该问的不是”我们的机器够不够”, 是”判定这一侧还有多少余量”(小节 17.7)。 因为增益这一侧几乎没有阻力, 所以它会非常快地把系统推到裕度的边界上, 而那个过程中不会有任何一个环节先叫。

17.13 为什么控制论的语言值得借

这一章借了一整套别的领域的词汇,它换来了三样具体的东西。

17.13.1 一、它给了”同一个形状”一个名字

两堵墙”形状相同”这个观察,在第一章就有了, 但没有名字的观察无法被推演。 有了”增益与延迟”这个名字之后, 可以直接问下一个问题:增益还在涨,延迟没变,那么下一堵墙在哪? —— 而这个问题在没有名字的时候问不出来。

17.13.2 二、它带来了一批现成的解

串级控制、死区、抗积分饱和、增益调度、观测器 —— 这些都是别人花了几十年验证过的模式, 而这套系统独立撞出了其中的四个(小节 18.6)。 撞出来的和借来的效果一样,但撞出来要付事故的代价。 剩下那些还没被撞出来的,可以直接拿过来用 —— 小节 17.8 里的增益调度、小节 19.3 里的观测器, 都属于这一类。

17.13.3 三、它划出了这套方法的理论边界

小节 20.2 那条”闭环系统不能生成自己的设定点”, 不是一个经验观察,是一个定理。定理和经验的差别在于: 定理告诉你不用再试了。 一个团队如果不知道这条, 可能会花很久去建一个”能自己判断需求对不对”的系统 —— 而那是不可能的,不是因为技术不够,是因为范畴不对。

17.14 借来的语言也有它的局限

三条这个类比不成立的地方,说清楚它们比多借几个词更重要。

这里的”被控对象”会学习。 经典控制论里,被控对象的动力学是固定的, 而模型会更新、提示词会变、Agent 会积累上下文 —— 这是一个时变系统,而时变系统的理论要复杂得多。

这里的”误差”不是标量。 控制论里误差是一个可以做减法的量, 而”这次产出和我想要的差多少”不是一个数, 它是一个结构化的、多维的、部分不可比较的东西。

这里没有传递函数。 你没法写出”提示词变化 → 输出变化”的数学关系, 所以所有定量的控制设计方法在这里都用不上 —— PID 参数整定、根轨迹、频域分析,这些过不来。

能借的只有定性的结论:增益与延迟的关系、前馈与反馈的分工、 可观测性(小节 19.1)的必要条件、设定点必须在环外。这四条都不需要传递函数就成立, 所以它们能过来。知道哪些能借、哪些不能借,比借得多重要—— 一个把 PID 参数整定硬套到提示词调优上的类比, 会比不用这套语言更糟,因为它会让人以为自己在做工程。

这也顺带回答了一个自然的疑问:既然只有定性结论能借, 这一章还有什么实用价值?答案是它给出的三个动作 —— 量三个数、画一张图、判断自己在哪个稳态 —— 全都不需要定量的模型。它们需要的只是知道该看哪三个数, 而这正是一个定性模型能提供的全部,也是它足够提供的。

17.15 三个可能的稳态

一个增益和延迟匹配的系统,会稳定在三种状态之一, 而认出自己在哪一种,决定了下一步该做什么。

17.15.1 稳态一:判定受限

特征是流水线排队、Agent 在等结果,瓶颈在判定这一侧的带宽, 该做的是缩小测量范围、下沉判定、降延迟。 这是第一、二堵墙的状态,也是我大部分篇幅针对的状态。

17.15.2 稳态二:修正受限

特征是判定很快返回,但改动要跑很多轮才能合入, 瓶颈在 Agent 理解失败并修正的能力, 该做的是改善失败信息的质量(小节 17.6)。 这是第三堵墙,而它的特征是加机器完全没用—— 这一点值得记住,因为”加机器”是遇到瓶颈时最自然的第一反应, 而在这个稳态里它是纯浪费。

17.15.3 稳态三:参考输入受限

特征是产出又快又好,但”做什么”成了瓶颈, 瓶颈在 章节 20 那一章讲的东西, 而我帮不上忙 —— 这不是谦虚,是 小节 20.2 那条定理的直接推论。

17.15.4 怎么判断自己在哪一种

小节 17.7 那三个数:

测量延迟 回路延迟 振荡次数 你在
稳态一
稳态二
稳态三(或者一切正常)

第二行和第三行的区别是振荡次数,而那个数之所以 值得被单独采集 —— 它是区分”判定慢”和”信息差”的唯一指标。 少了它,稳态一和稳态二在数据上长得几乎一样, 而它们需要的投入方向完全相反。

17.16 可执行的部分

不管你的规模多大,下面三个数今天就能量出来: 你的内环延迟(不需要跑程序的检查,从提交到出结论)、 你的外环延迟(需要跑程序的检查)、 你的振荡次数(一个改动平均跑几次流水线才合入)。

前两个的比值告诉你有没有串级(小节 17.3), 第三个的趋势告诉你增益和延迟的匹配还剩多少余量。 如果第三个数在涨,那么加 Agent 不会提高产出,只会提高返工—— 这是这一章唯一一条可以直接拿去做决策的结论。

一处需要说明的

本章用控制论的语言重新表述了一套已经存在的实践。 需要说清楚的是:这套实践是先建成的,控制论的解释是后加的。

它的价值恰恰在于预测那些还没撞过的墙: 振荡次数、增益调度、稳定裕度,这三样都是经验撞不出来的, 因为它们要求你在故障发生之前就推理系统的动态。

17.17 词汇表

为了方便回查,把这一章引入的控制论概念列一遍, 每个配一句”在这里它是什么”:

概念 在这里是什么
增益 Agent 的吞吐 —— 单位时间施加多少修正
回路延迟 从改动产生到判定回到手里的时间
稀疏测量 只测本次真正变化的那个子空间
串级控制 快内环(结构检查)+ 慢外环(端到端)
相位裕度 距离”返工振荡”还剩多少余量
微分作用 对误差的变化率动作 —— 这里是”预判哪些会红”
增益调度 按风险等级调整回路的压紧程度
采样周期 周期任务多久跑一轮

八个概念里,五个已经在这套系统里有对应的实现, 三个 —— 微分作用、增益调度、稳定裕度的测量 —— 还没有。 这个比例本身说明了一件事:一个认真做闭环的人会撞出大部分标准解, 但撞不出那些需要”在故障发生前推理动态”的。 小节 17.13 讲过这就是借这套语言的第三个理由。

17.18 还没被撞过的那堵墙

小节 1.8 预测了第三堵墙(失败信息的质量)。 这里再往前推一步,因为这个框架允许推。

假设第三堵墙也被解决了:失败信息足够好,Agent 平均一轮就能修好。 那时候的瓶颈在哪?按增益和延迟的框架, 延迟已经压到了测量本身的物理下界(有些判定就是需要把程序跑起来), 而增益还能涨。于是会出现一个新的状态: 修正速率超过了”最快可能的判定速率”。

这时候唯一剩下的路是 小节 17.8 的第三条,也就是降增益。 它的具体形态不是”少开 Agent”,更可能是让 Agent 在提交之前 自己做更多的判定 —— 把一部分判定从”提交后”移到”提交前”, 也就是把反馈变成 Agent 自己回路里的一环,而不是外部系统的一环。

这在控制里叫内模控制:控制器内部包含一个被控对象的模型, 用它来预测输出,从而减少对外部反馈的依赖。 它的工程形态已经存在了 —— 让 Agent 在本地跑同一套检查小节 14.19),只不过现在它是”可选的”, 而在那个未来它会变成”必须的”。

这个预测的价值不在于它对不对,在于它说明了这个框架 能生成可检验的预测—— 而这正是 小节 21.3 里那句 “一个能预测的模型比一个能解释的模型值钱”的意思。 如果三年后瓶颈落在了别的地方,这个框架就该被修正, 而一个不能被证伪的框架连修正的机会都没有。

17.19 压成三句话

一、增益是 Agent 的吞吐,延迟是判定回到手里的时间, 而在有延迟的系统里提高增益会失稳。这就是两堵墙的统一解释 (小节 17.2),而它还预测了第三堵墙(小节 1.8)。

二、测试金字塔是一个串级控制结构,而它有一个定量前提。 内环必须显著快于外环 —— 如果你的静态检查和端到端测试耗时 在同一个量级,那你没有串级,只有两个并联的慢环(小节 17.3)。

三、回路里最大的一块延迟,可能不在基础设施上。 1.4 小时的中位转绿时间,减去约半小时的流水线时间, 剩下的一个多小时是 Agent 在读失败、理解、修改(小节 17.6)。 这意味着改善失败信息的收益,可能高于再买一批机器。

17.20 立刻可以画的那张图

这一章的动作项只有一个:横轴是周,三条线分别是 测量延迟(提交 → 第一次判定返回)、 回路延迟(第一次红灯 → 最终转绿)、 振荡次数(每个改动跑了几条流水线)。

三条线,一张图,数据全在流水线记录里。看的不是绝对值, 是三条线之间的关系(小节 17.7 那张表)—— 它会告诉你现在的瓶颈在哪一侧,而那决定了你下一笔投入该往哪放。 成本是一天。