> LZ 你好,我问你个可能很 safufu 的问题🤣,我看有些协程的实现中会用 pushfq/popfq 和 fnstenv/fldenv,这和单用 fnstcw/fldcw 有什么区别呢,因为加上 pushfq/popfq 后性能甚至不如 Windows Fiber 就有感而问。
朋友客气了哈 :D
1. 关于 pushfq/popfq
> The direction flag DF in the %rFLAGS register must be clear (set to “ forward ” direction) on function entry and return. Other user flags have no specified role in the standard calling sequence and are not preserved across calls.
> Sys V ABI AMD64 Version 1.0
> The direction flag DF in the %EFLAGS register must be clear (set to “ forward ” direction) on function entry and return. Other user flags have no specified role in the standard calling sequence and are not preserved across calls.
> Intel386-psABI-1.1
Sys V ABI 规范中规定(E|R)FLAGS 中的 status flags 都是"not preserved across calls",所以当我们进行遵从 Sys V ABI 规范的协程上下文切换时,根本不需要 save/restore 它们(比如 libaco 的 acosw 实现);另外,尽管 ABI 对(E|R)FLAGS 中的 DF 位有约束,但是我们可以证明在我们的协程上下文切换汇编中,它也是可以省掉的,证明很巧妙,具体可以阅读 libaco 的数学证明部分。
2. 关于 fnstenv/fldenv
> The control bits of the MXCSR register are callee-saved (preserved across calls), while the status bits are caller-saved (not preserved). The x87 status word register is caller-saved, whereas the x87 control word is callee-saved.
> Intel386-psABI-1.1
> The control bits of the MXCSR register are callee-saved (preserved across calls), while the status bits are caller-saved (not preserved). The x87 status word register is caller-saved, whereas the x87 control word is callee-saved.
> Sys V ABI AMD64 Version 1.0
Sys V ABI 规范中规定对于 x87 与 MXCSR 只有 control words 是“ callee-saved (preserved across calls)”的,它们的 status 位全都是“ not preserved across calls ”,所以在 libaco 的协程上下文切换中,我们只需要 save/restore 它们的控制字就可以了( fnstcw/fldcw & stmxcsr/ldmxcsr ),当然使用 fnstenv/fldenv 也是正确的,但是:
fnstcw/fldcw 只需要 save/restore 两个字节,而 fnstenv/fldenv 却需要 save/restore 28 个字节,这个 28 个字节中有 26 个字节是毫无必要的无用功。
(对于上述两部分的 call convention,Sys V ABI 与 Miscrosoft ABI 是基本相同的,故上面只引述了 Sys V ABI 的规范描述)
Reference:
https://www.felixcloutier.com/x86/FSTENV:FNSTENV.htmlhttps://www.felixcloutier.com/x86/FSTCW:FNSTCW.htmlhttps://github.com/hnes/libaco/blob/master/README_zh.md#proof-of-correctness> 加上 pushfq/popfq 后性能甚至不如 Windows Fiber
你是指如果没有 pushfq/popfq 的话,性能比 Windows Fiber 好很多,加上之后反而会比 Windows Fiber 慢很多么?
如果是上述陈述的话,我认为是很奇怪的,可以具体再确认一下,毕竟 pushfq/popfq 还是很快的( RFLAGS 8 个字节,但是还有可能是因为 pushfq/popfq 破坏了流水线而带来的性能损耗)。
但是如果本来性能与 Fiber 相等,加上它们之后更慢了,这就很正常的,毕竟这样就多了来回 16 个字节读写的无端损耗。
当然,我认为是不需要加的,除非还有其他的目的。
对于 windows 的协程,建议只用它提供的 API,比如 Fiber,原因是 windows 的 ABI 只有微软说了算...哈哈。