对于几个锁的对比总结 Part1

4 篇文章 0 订阅
3 篇文章 0 订阅

本部分涉及锁

HCLH:A Hierarchical CLH Queue Lock

flatmcs:Flat-Combining NUMA Locks

CST:Scalable NUMA-aware Blocking Synchronization Primitives

MUTEXEE:Unlocking Energy

Smartlocks:Smartlocks: Lock Acquisition Scheduling for Self-Aware Synchronization

spinlock 神奇的自适应

经过各种测试,发现spinlock其实并不只是看上去的那么简单。

从本质上来说,spinlock并不是完全公平的,更有竞争力的候选者将更有可能获取锁。

更有竞争力的候选者往往可能以为着其离上一位持有者更近,更可能先看见锁的状态的更新。抑或是更有竞争力的候选者运行频率更高,更有可能先成功的运行CAS。

下面是利用thbench在模拟大小核环境下测试的结果:

$ ./thbench spinlock
Big core req 10583869.000000 Little core req 4595808.000000
intr 15179677.000000 time 5.000176
3035828.418

spinlock在高竞争程度时,自然而然地形成了一定的倾向性。其在大小核环境下高竞争程度模式下的性能甚至超越了理论上可扩展性更好的mcs。

而这种倾向性并没有人为设计,这种自适应比较神奇,可以考虑考虑。

MCS vs CLH vs K42

基本思路对比

将这三个传统本地锁放在一起,一个是他们都是队列锁,性能相近,却又有各自细微的差别。(严格的来说CLH实际上性能会稍微好一点)。细致地分,CLH可以分为一类,MCS与K42可以分为一类(本身K42就是从MCS衍生而来)。

  • CLH是在前驱的cache line上忙等,自己管自己,释放时只需要改变自己的状态,无需管理其他等待者。
  • MCS是在自己的cache line上忙等,前驱在释放时会将负责唤醒/设置下一位的状态。

主要区别

  • CLH释放时无CAS也没有自旋,整体CAS更少。因此在测试中拥有更好的性能表现。
  • MCS总是在自己的cache line上忙等,减少了无cache的NUMA结构上的远程内存访问(实际上现在NUMA一般都有L3 cache共享)。有两个CAS,而且释放的时候可能会有自旋等待。
  • K42较MCS的主要区别是通过巧妙的手段,使其结点保存在函数栈中,避免了不必要的内存占用,并调用时无需除了锁的其他参数。但是从外部调整队列基本就行不通了。(本来想手动调队列顺序,但是开销还是太大,最终也没实现)

对比公平性,这三种完全相同,使用FIFO队列达到了绝对公平。

HCLH vs flatmcs vs CST

基本思路对比

之所以将这三个锁放在一起,是因为他们背后的设计逻辑都是相同的。其皆为将全局的竞争进行划分,划分为每节点的竞争,从而减少对单一缓存行的竞争。此处不讨论CST的睡眠队列等相关特性,该特性将在与MUTEXEE进行对比分析时提及。

  • HCLH与flatmcs更为相似,其皆为想方设法将本地的队列收集一下,然后通过单个CAS操作将本地队列加入全局队列。然后依据全局队列顺序来决定获取锁的顺序。
  • 而CST则是通过两层锁,获取全局锁后将通过本地锁传给本地的线程执行。

主要区别

其实针对本地性上面做文章的最终都可以归为公平性与性能的trade off。而这两种不同的思路在这个trade off中的选择空间是不同的,这也是他们最大的不同。

  • 第一种思路能提供的本地性提升其实是十分有限的。其有较短的batch时间区间(指一段时间内的请求能batch到一起)上限(combiner等待的时间范围),固定的数目上限(最多只能batch结点上请求的数目,每个请求只能有一次)。但是由于加入到全局队列是一个FIFO的,其能保证一段时间范围内的公平性。
    而这两种锁之间的区别则在于本地队列的组成方式。HCLH直接通过CAS来加入本地队列,而flatmcs则使用flatcombining的方法避免了本地队列的竞争。不过本身本地队列的竞争并不在关键路径上,只在本地核数较多时,等待时间内能否将所有的本地核上的请求batch到一起上有影响。
  • 而第二种思路相较第一种思路,其选择空间比较大,可以通过最大batch size来进行调整(如设置最大batch size为一个节点上的硬件线程数,可以获得接近第一种思路的公平性)。其拥有更长的batch时间区间,从上次本节点的任意线程释放全局锁本次本节点的任意线程释放全局锁的时间区间内,都可以batch到一起。且batch数量上限可以人为根据对公平性或者tail latency的需求来设定,在一次batch处理过程中,一个线程可以多次获取锁。在高竞争程度时,设置更高的batch上限可以拥有更高的本地性,从而拥有更明显的性能提升。

实际性能

在NUMA环境下进行测试。性能上,这三者较传统本地锁更强。但整体性能不如迁移锁。

但是与迁移锁相比,其不用变接口与逻辑,与传统应用兼容更好。

MUTEXEE vs CST

这两种锁都详细讨论了等待者睡眠的问题。但是使等待者睡眠的出发点并不同,分别是从功耗层面与系统负载超过硬件线程数层面考虑的。这也反映了睡眠能够带来的两种好处:

  • 相较于忙等,睡眠(IDLE)能明显降低功耗(具体的细节可以回去再看一下unlocking enery
  • 在负载超过硬件线程数时,睡眠可以有效地利用有限的处理器资源,让给真正需要处理器的线程。

然而睡眠往往意味着巨大的唤醒开销。为了避免这种睡眠与唤醒开销,MUTEXEE与CST分别采用了以下方法。

  • MUTEXEE通过增长忙等时间,来避免出现竞争程度刚好导致出现大量刚睡眠又唤醒的线程。又通过释放锁后先check是否有忙等的线程,来避免高竞争程度时唤醒出现在关键路径上。公平性通过设置睡眠的TO来保证一部分。
  • CST通过等待一段时间后加入睡眠队列。唤醒前先将锁先释放,然后再统一唤醒一个节点上的线程来避免唤醒出现在关键路径上。

总的来说,就是通过各种手段来优先让给还在忙等的线程,避免关键路径上需要等待唤醒。

从 Smartlocks 到 ccstmcs

Smartlocks与ccstmcs都是针对大小核异构环境进行设计的,通过降低公平性来提升性能。大核优先的出发点是大核忙等的时间更加值钱,可以用于干更多的事情,最终都是在公平性与性能上进行trade off。

ccstmcs涉及正在working on的project,就不放上来了。

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值