首页   注册   登录
 hnes 最近的时间轴更新

hnes

V2EX 第 254596 号会员,加入于 2017-09-15 20:34:57 +08:00
hnes 最近回复了
@toilaj 十分感谢你的支持哈,遇到任何问题都可以提出来大家一起讨论 :D
@yulon 不客气哈,十分高兴上面的回复能够对你有用处 ;-)

也很感谢你的案例分享 :D
@yulon

> 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 的数学证明部分。

中更正:

Sys V ABI 规范中规定(E|R)FLAGS 中的 status flags {+(除了 DF 位)+}都是"not preserved across calls"
> 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.html
https://www.felixcloutier.com/x86/FSTCW:FNSTCW.html
https://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 只有微软说了算...哈哈。
你好 @Monad,Github 上腾讯 libco 的 issue 90 中有十分详细的复现过程以及标准规范的引述,另外我在知乎上的一个回答中还陈述了腾讯 libco C++ ABI 相关的问题,感兴趣的话可以看一下哈 :D

tencent libco issue 90: https://github.com/Tencent/libco/issues/90
zhihu 回答: https://www.zhihu.com/question/52193579/answer/447612082
@pynix 后续我会继续发布一个基于 libaco 的 Golang like C 实现,敬请继续关注哈 ;-)
@Ganing 十分感谢你的鼓励 :D

> 从 LT 到 ET 事件驱动,再加上多线程锁,真的写起来太麻烦了。正在学习 goroutine 的原理,协程还是很有启发的

是的,golang 中有很多很棒的思想可以在设计系统时让我们借鉴;但是,由于它的抽象层次过高,使得它不大适合某些对并发和资源消耗要求很高的领域,欢迎你继续关注 libaco 的后续开源项目哈 ;-)
> 很棒的工作,赞!!!牛逼!!!

十分感谢你的鼓励 :D

> 这么短时间内,有公司敢用,也是勇气可嘉。
> 数学证明很牛逼,在这里没多少人能看懂吧

这个我有些不赞同哈,libaco 核心只有 700 行代码,如果对 ABI 规范和汇编有一定了解的程序员,第一次几乎半个小时不到就能够读完了,就算是对 ABI 与汇编有些生疏,只要温习一下这方面的知识一样可以轻松读懂。另外,数学证明其实是非常简单的,有不少朋友向我反馈他们只是看了一下文档中的几张示意图就完全明白了 libaco 的设计思想和原理。

程序某种程度上说就是数学问题,证明当然永远是第一位的。

> 即使是写论文,最终也得拿个数据说话

数据,指的是?文档中有详细的 benchmark 方法和结果报告。如果是指用户量的话,任何软件产品都是先发布,然后才能有用户量,不是么?

> Q:问个小白问题,我理解底层是基于 epoll 类似的事件机制,libaco 中实现的类似 Go 语言中 goroutine 调度器的角色,libaco 其实是降低用户实现高并发的难度,以类同步编程实现异步,用户友好

赞,正是如此 ;-)
下一个将要发布的开源项目正是完成了你所陈述的所有事情,热烈欢迎继续关注哈 :D

> 如果有能力做到类似 Nginx 这种高效的使用,应该没必要使用协程的对吗?

是这样的,如果喜欢使用 callback 方式写网络应用并且愿意付出相应的开发代价,当然是没有任何问题的啦,但是,有时候,有能力和有时间有精力完全是不同的,哈哈。
最后插一句:其实 Nginx 的网络模型和事件模型是非常简单的( proxy ),只要对比一下 ngx lua 和 golang 两者的调度器和编程抽象就可以看出来了。
@hnes

勘误:

> 在 **libco** 的核心中只有不超过 700 行的代码,但是花了我一个多月的时间才编写完成它的第一个版本,还有完整的一个月时间来进行非常严格的代码审查(几乎每一行代码都被严格地证明和推理过,并且被审查证明过很多次),当然,还有全面的测试。libaco 是我们正在开发的产品中最重要的核心组件之一,因此我们对它投入了很大的精力和注意力。

**libco** -> libaco

十分抱歉...
@pkv 另外,关于 libaco 的速度问题,libaco 的 acosw 协程上下文切换汇编是在 Sys V ABI intel386 或 AMD64 的约束之下的最快且正确的实现,这是经过数学证明了的,具体可以阅读 libaco 文档中的数学证明部分。

感谢你的关注 ;-)
关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   鸣谢   ·   实用小工具   ·   616 人在线   最高记录 3762   ·  
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.1 · 9ms · UTC 20:48 · PVG 04:48 · LAX 13:48 · JFK 16:48
♥ Do have faith in what you're doing.
沪ICP备16043287号-1