博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
为什么SpinLock的实现中应该加上PAUSE指令?
阅读量:6655 次
发布时间:2019-06-25

本文共 2698 字,大约阅读时间需要 8 分钟。

当spinlock执行lock()获得锁失败后会进行busy loop(),不断检测锁状态,尝试获得锁。这么做有一个缺陷:频繁的检测会让流水线上充满了读操作。另外一个线程往流水线上丢入一个锁变量写操作的时候,必须对流水线进行重排,因为CPU必须保证所有读操作读到正确的值。流水线重排十分耗时,影响lock()的性能。

 

inline int rdlock()        {          int ret = common::OB_SUCCESS;          int64_t tmp = 0;          while (true)          {            tmp = ref_cnt_;            if (0 > tmp || 0 < wait_write_)            {              // 写优先              continue;            }            else            {              int64_t nv = tmp + 1;              if (tmp == (int64_t)atomic_compare_exchange((uint64_t*)&ref_cnt_, nv, tmp))              {                break;              }            }          }          return ret;        };

 

为了解决这个问题,intel发明了pause指令。这个指令的本质功能:让加锁失败时cpu睡眠30个(about)clock,从而使得读操作的频率低很多。流水线重排的代价也会小很多。

参考这位同学的博客,讲得很好很清晰:

 

4, Pause指令解释(from intel):

Description

Improves the performance of spin-wait loops. When executing a “spin-wait loop,” a Pentium 4 or Intel Xeon processor suffers a severe performance penalty when exiting the loop because it detects a possible memory order violation. The PAUSE instruction provides a hint to the processor that the code sequence is a spin-wait loop. The processor uses this hint to avoid the memory order violation in most situations, which greatly improves processor performance. For this reason, it is recommended that a PAUSE instruction be placed in all spin-wait loops.

提升spin-wait-loop的性能,当执行spin-wait循环的时候,笨死和小强处理器会因为在退出循环的时候检测到memory order violation而导致严重的性能损失,pause指令就相当于提示处理器哥目前处于spin-wait中。在绝大多数情况下,处理器根据这个提示来避免violation,藉此大幅提高性能,由于这个原因,我们建议在spin-wait中加上一个pause指令。

名词解释(以下为本人猜想):memory order violation,直译为-内存访问顺序冲突,当处理器在(out of order)乱序执行的流水线上去内存load某个内存地址的值(此处是lock)的时候,发现这个值正在被store,而且store本身就在load之前,对于处理器来说,这就是一个hazard,流水流不起来。

在本文中,具体是指当一个获得锁的工作线程W从临界区退出,在调用unlock释放锁的时候,有若干个等待线程S都在自旋检测锁是否可用,此时W线程会产生一个store指令,若干个S线程会产生很多load指令,在store之后的load指令要等待store在流水线上执行完毕才能执行,由于处理器是乱序执行,在没有store指令之前,处理器对多个没有依赖的load是可以随机乱序执行的,当有了store指令之后,需要reorder重新排序执行,此时会严重影响处理器性能,按照intel的说法,会带来25倍的性能损失。Pause指令的作用就是减少并行load的数量,从而减少reorder时所耗时间。

 

 

 

晓楚
(17:40:19):
这篇文章很好,基本解释清楚了spin_lock中为什么要加pause。中文的,大家都看得懂。
  (17:49:28):
对失败的加锁行为进行惩罚(failure penalty),让等待时间和失败次数成正比,即失败次数越多等待时间越长、执行的pause指令越多。
这个我们也可以用吗?
到底最大pause次数是多少需要试验来支撑,目前是4次;个人感觉pause的处理器实现粒度还是比较粗的,应该是intel的一个经验值,接下来的试验可以用nop来代替pause,这样得出来的数据应该会更为平滑一些,控制也更为细腻。
nop是什么指令?
晓楚 (17:51:21):
我觉得没必要,这个做法太复杂了。用pause就足够了。
nop是让cpu 空转1个clock的指令。什么都不做。
  (17:51:59):
其实可以测试。
临界区大小,我们一般是多少代码?
  (17:59:29):
看他的实验结果,提升并不明显,5%的样子,还是在冲突特别大的情况下,好像不值得。
要优化spin lock,主要还是避免大量的线程在同一个cache line里spin。我以前测过,要是以浪费内存为代价,可以很轻松提升40%的样子。同样的思路去优化spin_rwlock的读锁(以降低写锁性能为代价),让不同的读者修改自己线程局部的引用计数,读锁性能可以提升几倍。不过现在性能还不在这里。
  (18:02:28):
恩,支持。现在性能还不在这里。我们保持关注,先从收益大的地方入手。

 

 

 

转载地址:http://ndxto.baihongyu.com/

你可能感兴趣的文章
gitlab 2.2和更高版本升级到2.7
查看>>
我和linux的第十六天
查看>>
Openstack-Mitaka Ceilometer 部署心得
查看>>
OpenStack tokens id获取测试
查看>>
RHEL6 命令行界面安装图形套件
查看>>
kickstart无人值守安装——制作光盘文件
查看>>
Cookie欺騙與代碼隱患
查看>>
mysql master slave 1( 2015-11)
查看>>
AppDelegate生命周期回调顺序
查看>>
我的友情链接
查看>>
cacti源码分析-获取数据流程
查看>>
warning: rpmts_HdrFromFdno: Header V3 RSA/SHA256 Signature, key ID 0608b895: NOKEY
查看>>
asp.net mvc4 jquery validate 弹出框提示
查看>>
Context-Based Access Control (CBAC) 基于上下文的访问控制 实验
查看>>
BGP反射器实验
查看>>
Python 端口扫描(全连接扫描,多线程)
查看>>
Mysql授权root用户使用远程客户端连接
查看>>
网传Linux运维面试题解答
查看>>
SUSE下nx nomachine安装配置
查看>>
精通脚本***学习笔记(二)
查看>>