C.8 谬误与陷阱
陷阱:意料之外的执行序列,可能导致意料之外的冒险
乍看之下,WAW 冒险似乎不应出现:编译器不会生成两次写同一寄存器、而中间完全没有读取的代码。但意料之外的执行序列仍可能产生它。例如,一条运行时间很长的浮点除法触发陷阱;如果陷阱处理例程很早就写入与除法相同的目的寄存器,并且写入发生在除法完成之前,就可能出现 WAW 冒险。硬件或软件必须防止这种情况。
陷阱:过度流水线化会影响设计的其他方面,使整体性价比反而下降
最好的例子来自 VAX 的两种实现:8600 和 8700。8600 最初上市时,时钟周期为 80 ns,随后重新设计的 8650 把周期缩短为 55 ns。8700 的流水线简单得多,在微指令层面工作,处理器更小,时钟周期也更短,只有 45 ns。最终,8650 的 CPI 约有 20% 优势,而 8700 的时钟频率约高 20%。因此,8700 用少得多的硬件达到了相同性能。
陷阱:用未经优化的代码评估动态或静态调度
未经优化的代码包含可由优化器消除的冗余加载、存储及其他操作,比经过优化的紧凑代码容易调度得多。不论是利用延迟分支调度控制延迟,还是调度 RAW 冒险引起的延迟,都是如此。例如,在流水线与 C.1 节几乎相同的 R3000 上运行 gcc,比较“未优化但已调度”与“已优化且已调度”的代码,后者的空闲时钟周期频率增加了 18%。
当然,优化后的程序快得多,因为它的指令更少。公平评估编译时调度器或运行时动态调度,必须使用优化后的代码;真实系统的良好性能不仅来自调度,也来自其他优化。