《Multicore Locks: The Case is not Closed Yet》阅读

Multicore Locks: The Case is not Closed Yet

 

abstract

NUMA多核机器非常普遍,许多多线程应用程序都受到锁争用的困扰。为了缓解这个问题,应用程序和库开发人员可以从过去25年设计的大量优化互斥锁算法中进行选择。不幸的是,目前还没有对这些优化锁算法在实际应用程序中的行为进行广泛的研究。在本文中,我们试图填补这一空白。我们在35个应用程序上对27种最先进的互斥锁算法进行了性能研究。我们的研究表明,在多核机器上锁定的情况还没有结束。实际上,我们的结论包括以下发现:(i)在其优化的争用级别上,单个锁对于超过52%的研究工作负载来说是最佳的;(ii)每个锁对多个应用程序都是有害的,即使应用程序并行性被适当地调优了;(iii)对于一些应用程序,最佳锁随着线程数的变化而变化。这些发现需要对锁的优化算法和争用管理的动态适应进行进一步的研究。
 

1 Introduction

 

2 Lock algorithms

2.1 Background

2.2 Studied algorithms

我们选择所研究的锁是因为我们决定专注于可移植锁算法。我们因此排除以下锁,需要强有力的假设应用程序/操作系统行为,代码修改,或破片 ile性能调优:HCLH, HBO, FC-MCS,基于锁(见骰子等。[14]de 跟踪参数)。我们的研究考虑了27种互斥锁算法,它们都是成熟的和最先进的方法的代表。我们使用Spin和STP后缀来区分同一算法的变体,这些变体只在它们的等待策略上有所不同。ls标签对应于从libslock借来的优化算法。我们的集合包括10个平面锁(Backoff, partitionatedticket, Phtread, Pthread adaptive, Spinlock, Spinlock- ls,7个基于队列的锁(Alock-LS, CLH- ls, CLH Spin, CLH STP, MCSLS, MCS Spin, MCS STP), 7个分层锁(CBO-MCS)。

3 Experimental setup and methodology

3.1 Testbed and studied applications

我们的实验测试平台由三个基于linux的服务器组成,它们的主要特性如表1所示。所有机器都运行Ubuntu 12.04操作系统,带有3.17.6 Linux内核(CFS调度程序)、glibc 2.15和gcc 4.6.3。锁性能的比较研究,我们认为从秒差距(i)应用程序基准套件(新兴工作负载),(2)从凤凰2 MapReduce应用程序基准套件,(3)SPLASH2高性能计算的应用程序基准suite4 (iv)运行Cloudstone的MySQL数据库工作负载,和(v) SSL代理,事件驱动的SSL端点处理小消息。为了评估工作负载变化对锁定性能的影响,我们还考虑上述四种工作负载的所谓长寿变体,这些变体用ll后缀表示。请注意,其中6个应用程序不能在两台48核机器上求值,因为按照设计,它们只接受相当于2的幂的线程数:facesim、fluidanimate(来自PARSEC)、fft、ocean cp、ocean ncp、基数(来自SPLASH2)。

除了以下三个应用程序:dedup(3个线程)、ferret(4个线程)和MySQL(数百个线程)之外,大多数应用程序使用的线程数量与内核数量相等。三分之二的应用程序使用Pthread条件变量。

3.2 Tuning and experimental methodology

对于依赖于静态阈值的锁算法,我们使用了来自原始论文和实现的推荐值。基于spin -park等待策略的算法(如Malth STP[12])依赖于一个固定阈值的spin时间,该阈值对应于双向上下文切换[22]的持续时间。在本例中,我们使用测试平台上的微基准对该持续时间进行校准。

为了避免NUMA内存瓶颈,所有应用程序都使用内存交错(通过numactl实用程序)运行。通常,在本文的实验中,我们研究了给定争用级别(即应用程序的线程数)的锁对性能的影响。我们在NUMA节点的粒度上改变争用级别(例如,a - 64机器有8个核,a -48机器有6个核,I-48机器有12个核)。对于本文中详细介绍的大多数实验,应用程序线程并没有固定到特定的核心上。尽管如此,固定的影响在§5.3中进行了讨论。

最后,每个实验至少运行5次,计算其平均值。总的来说,我们观察到大多数配置的差异很小。对于所有实验,考虑的应用程序级性能指标是吞吐量(每时间单位的操作)。

4 The LiTL lock interposition library

为了进行锁比较研究,我们开发了LiTL,这是一个用于Linux/x86的交互库,可以透明地替换Pthread互斥锁算法。我们描述它的设计、实现,并评估它的性能。
 

4.1 Design

LiTL的设计对嵌套锁定的级别没有任何限制,并且与任意的锁定规则兼容(例如,hand- on -hand locking[33])。图1描述了LiTL库的主包装器函数的伪代码。

图1:LiTL主要包装器函数的伪代码概述。

General principles LiTL的主要作用是维护标准Pthread锁的实例(Pthread互斥锁t)和所选优化锁类型的实例(例如,MCS Spin)之间的映射结构。这意味着LiTL必须通过对pthread互斥锁init()和pthread互斥锁destroy()的调用来跟踪所有应用程序锁的生命周期,并且每次对pthread互斥锁lock()的调用都必须触发对优化锁实例的查找。此外,静态初始化的锁实例只能在第一次调用pthread互斥锁()时被发现和跟踪(即,失败的查找将导致创建新的映射)。

除了锁指针之外,几种锁算法的锁/解锁API还需要一个额外的参数(下文称为struct)。例如,在MCS锁的情况下,这个参数对应于要插入(或从)锁等待队列中删除的记录。一般情况下,在相应的锁被释放之前,结构体不能被重用或释放。例如,一个应用程序可能依赖于嵌套的临界区(例如,一个线程T在持有另一个锁L1的同时必须获得一个锁L2)。在这种情况下,T必须为L2使用一个不同的结构,以保持L1结构的完整性。为了优雅地支持大多数通用情况,LiTL系统地为每个锁实例和每个线程分配一个结构体。

Supporting condition variables 在每个优化的锁算法中处理条件变量将是复杂而乏味的,因为大多数锁在设计时并没有考虑到条件变量。因此,我们使用以下策略:pthread cond wait()的包装器内部调用真正的pthread cond wait()函数。为了发出这个调用,我们需要持有一个真正的Pthread互斥锁(类型为Pthread t),这种策略(在图1的伪代码中描述)不会在内部Pthread锁上引入高争用。实际上,对于不使用条件变量的工作负载,Pthread锁仅由与临界区相关联的优化锁的持有者请求。而且,使用条件变量的工作负载不太可能有两个以上的线程竞争Pthread锁:优化锁的持有者和一个已通知的线程。注意,后者要求也适用于工作负载,依靠pthread电导率广播(),因为这个调用的Linux实现只唤醒一个线程从队列等待条件变量的直接转移剩余的线程等待队列的pthread锁。

Support for specific lock semantics 当底层锁算法提供相应的属性时,LiTL的设计与特定的锁语义是兼容的。例如,LiTL支持所有当前实现的锁的非阻塞锁请求(pthread互斥trylock()),除了基于clh的锁和Hticket-LS,它们与这种语义不兼容。尽管还没有实现,LiTL可以很容易地支持使用超时阻塞请求的所谓可中止锁(例如MCS-Try[34]和MCSTimePub[19])。此外,支持可选的Pthread互斥行为再进入和错误checks5可以很容易地集成到通用包装器代码由人老化油田当前所有者和锁获取计数器。

4.2 Implementation

该库依赖于一个可伸缩的并发散列表(CLHT[10]),以便为应用程序中使用的每个Pthread互斥锁实例存储相应的优化锁实例和相关的perthread结构。对于MCS这样成熟的锁定算法,LiTL的代码借鉴了其他库[9,1,26]。其他算法是在原始论文描述的基础上从头实现的。对于基于停车或旋转后停车等待策略的算法,我们的实现直接依赖于futex Linux系统调用。

最后,LiTL的源代码依赖于预处理器宏而不是函数指针。实际上,我们已经观察到在关键路径中使用函数指针会带来惊人的高开销。此外,所有数据结构都是缓存对齐的,以减轻错误共享的影响。

4.3 Experimental validation

在本节中,我们使用A-64机器评估LiTL的性能。为此,我们比较以两种不同配置运行的一组应用程序上每个锁的性能(吞吐量):手动修改的应用程序和使用插入LiTL的未修改的应用程序。显然,一个人不能指望获得相同的结果在这两个配置,设置在许多方面都有所不同,例如,关于交货埃尔吉希县代码路径,进程内存布局和艾尔锁的位置(例如,栈-比基于堆)。怎么,我们表明,两国配置:(i)实现性能接近和(2)的一般趋势不同的锁保持稳定。

我们选择了三个应用程序:pca ll, radiosity ll和s raytrace ll。这三个应用程序是锁密集型的,最后两个使用Pthread条件变量。因此,这三种情况对LiTL来说都是不利的。此外,我们将重点讨论最高争用级别下的结果(即,当应用程序使用目标机器的所有核心时),因为这再次代表了LiTL的不利情况。

图2:手动实现的锁(黑色条)与使用LiTL(白色条)透明插入的锁的性能(吞吐量)比较。吞吐量是根据给定应用程序(a -64机器)的最佳执行配置规范化的。

图2显示了每个(应用程序、锁)对的两种配置(手动/插入)的规范化性能(吞吐量):黑色条对应于手动实现的锁,而白色条对应于使用LiTL的透明插入的锁。此外,表2总结了每个应用程序的性能差异:每个版本性能更好的锁的数量,以及每种情况下的平均增益和相对标准偏差。

我们注意到,对于所有三个应用程序,同一个锁的两个版本所实现的结果非常接近:平均性能差异低于5%。此外,图2强调指出,手动版本观察到的一般趋势与插入版本保持一致。因此,我们得出结论,使用LiTL来研究应用程序中锁算法的行为,与手动修改版本的性能行为相比,只产生非常微小的差异。

表2:使用LiTL (A-64机器)手动实现的锁与透明插入的锁的性能比较的详细统计数据。

5 Performance study of lock algorithms

在本节中,我们使用LiTL比较不同锁算法在不同工作负载和不同争用级别上的行为。出于篇幅的考虑,我们没有系统地报告观测到的标准差。然而,为了减少变异性的影响,当比较两个锁的性能,我们认为5%的保证金:锁被认为是比锁B如果B s实现性能低于95%的年代。此外,为了使公平比较,Pthread锁得到的结果提出了使用相同的库插入机制与其他锁。

请注意,由于特定的限制,有些配置没有进行测试。首先,streamcluster、streamcluster ll和vip不能使用基于clh的锁或HticketLS,因为它们不支持trylocks语义。其次,我们忽略了大多数MySQL锁的结果:由于线程与核心的比率非常大,大多数锁产生的性能接近于零。第三,一些应用程序,如dedup和fluidanimate,会在某些配置中耗尽内存。

最后,为了节省篇幅,我们不报告所研究的三种机器的全部结果。我们更侧重于A-64机器,并提供A-48和I-48机器的结果摘要。尽管如此,整套结果可以在配套的技术报告[18]中找到。

本节的结构如下。5.1提供了驱动研究的初步观察。5.2回答了本研究中有关观察到的锁行为的主要问题。5.3讨论额外的观察结果。

5.1 Preliminary observations

在继续进行详细的研究之前,我们要强调应用程序的一些重要特征。

5.1.1 Selection of lock-sensitive applications

表3显示了两个指标对每个应用程序和不同数量的节点- 64机:每性能得到最好的锁在最坏的一个,以及相对标准偏差的性能不同的锁。目前,我们只关注第5列中给出的最大节点数(最大节点争用最高)时的相对标准偏差(来自该表的详细结果在5.2.1中讨论)。

我们认为,如果最大节点上不同锁性能的相对标准偏差大于10%(用粗体突出显示),那么应用程序就是锁敏感的。我们注意到,大约60%的应用程序受到锁的影响。我们在研究的三种机器上观察到了类似的趋势(见表4)。

在本研究的其余部分中,我们将重点关注锁敏感应用程序。

表3:对于每个应用程序,最佳锁与最差锁的性能增益和相对标准偏差(A-64机器)。

表4:测试应用程序的数量和锁敏感应用程序的数量(所有机器)。

5.1.2 Selection of the number of nodes

在多核应用程序中,由于各种各样的可伸缩性瓶颈,并非总能在最大可用节点数量(简称最大节点)处获得最佳性能。因此,对于每一个(应用程序、锁)对,我们根据经验确定优化配置(缩写为opt节点),即产生最佳性能的节点数量。对于A-64和A-48机器,我们考虑1、2、4、6和8个节点。对于I-48机器,我们考虑1、2、3和4个节点。注意,A-64和A-48上的6个节点对应于I-48上的3个节点,即占可用内核的75%。

A-64的测试结果如表5所示。对于每个(应用程序、锁)对,相应的单元格表示优化配置相对于最大节点配置的性能增益。单元格的背景颜色表示优化配置的节点数。此外,表6还根据所有机器的优化节点数提供了(应用程序、锁)对的细分。

我们注意到,对于许多应用程序,优化的节点数低于最大节点数。此外,我们观察到(表5),优化配置的性能增益通常非常大。这证实了调优并行度通常会对性能产生非常大的影响。我们还注意到,对于某些应用程序,优化的节点数量因所选择的锁而异。

表6:根据优化的节点数(所有机器)分解(应用程序、锁)对。

根据上述观察,研究(5.2)中研究的主要问题将从两个互补的角度来考虑:(i)比较固定节点数的锁,(ii)比较它们优化配置的锁(即,每个锁可能有不同的节点数)。第一个角度提供了无法调整并行度的情况,而第二个角度则适用于可能进行更高级应用程序调优的场景。

5.2 Main questions

5.2.1 How much do locks impact applications?

表3显示了对于每个应用程序,在A-64机器的1个节点、最大节点和最优节点上,最佳锁相对于最差锁的性能增益。下表还显示了不同锁性能的相对标准偏差。

我们注意到锁对应用程序性能的影响取决于节点的数量。在1个节点上,锁对锁敏感应用程序的影响不大。更准确地说,大多数应用程序显示出最佳锁比最差锁的增益小于30%。相反,在最大节点时,锁对所有锁敏感的应用程序的影响非常大。更准确地说,最好的锁比最差锁带来的收益范围在42%到3343%之间。最后,在节点数优化时,锁的影响很高,但明显低于最大节点时的影响。我们通过以下事实来解释这种差异:在最大节点时,一些锁会触发某些应用程序的性能崩溃(如表5所示),这大大增加了锁之间观察到的性能差距。我们在A-48和I-48机器上观察到同样的趋势(见配套的技术报告[18])。

5.2.2 Are some locks always among the best?

表7显示了每个锁的覆盖率,也就是说,在A-64机器的所有研究应用中,它作为最佳锁的频率(或在最佳锁的5%以内)。结果显示了三种配置:1节点、最大节点和最优节点。此外,表8显示了对于每台机器(在1个节点、max节点和opt节点上),以下度量在不同锁上的总和:最小和最大覆盖率、平均覆盖率和覆盖率的相对标准偏差。

我们做了以下观察(表8)。在1个节点上超过89%的应用程序和在最大节点和最优节点数量上超过52%的应用程序中,没有锁是最好的。我们还观察到,在1个节点上的平均覆盖率比在最大节点上的平均覆盖率高得多,在优化节点数上的平均覆盖率比在最大节点上的平均覆盖率略高。这直接可以从5.2.1的观察中得到解释。首先,在1个节点上,锁对应用程序的影响比在其他配置中要小得多,因此产生的结果更接近,这增加了它们成为最佳配置之一的可能性。其次,在最大节点时,所有不同的锁依次导致性能崩溃,这降低了它们成为最佳锁的可能性。后一种现象在优化节点数时没有观察到。我们在A-48和I-48机器上观察到同样的趋势(见配套的技术报告[18])。

5.2.3 Is there a clear hierarchy between locks?

表9显示了A-64机器上最大节点时所有锁的成对比较。在每个表中,细胞(rowA, colB)包含锁A与锁B的分数,也就是说,应用程序的锁定的比例至少5%比锁B .例如,表9显示,38%的应用程序,AHMCS执行至少5%比倒扣在优化的节点数量。类似地,该表显示,在29%的应用程序中,Backoff至少比ahmc好5%。从这两个值中,我们可以得出结论,上面提到的两个锁在33%的应用程序中执行得非常紧密。在每一行的末尾。表中还显示了使用锁更好的应用程序比例的平均值(补充说明)。比其他人更糟)。此外,表10中总结了三种机器的后两个指标。

我们注意到锁之间没有明确的全局性能层次结构。更准确地说,对于大多数锁对(A, B),在一些应用程序中,A优于B,反之亦然(表9)。唯一的边际例外是值为0%的单元格。这对应于双锁(A, B)不会产生更好的性能比B的结果最大节点(图中未显示由于缺乏空间)展览思米政治趋势的选择节点。此外,我们同样的观察(选择节点和马克斯节点)48和I-48机器(见同伴浇筑卡尔报告[18])。

5.2.4 Are all locks potentially harmful?

5.3 Additional observations

6 Related work

7 Conclusion and future work

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值