掌桥专利:专业的专利平台
掌桥专利
首页

基于锁语义实现应用透明的动态处理器缓存分区调度方法和系统

文献发布时间:2024-04-18 20:02:18


基于锁语义实现应用透明的动态处理器缓存分区调度方法和系统

技术领域

本发明涉及数据调度技术领域,具体地,涉及一种基于锁语义实现应用透明的动态处理器缓存分区调度方法和系统。

背景技术

随着大数据的兴起,数据密集型应用的需求不断发展,例如Spark、Flink、Pregel等。数据密集型应用对多核系统算力的要求提出了进一步的要求,因此现代多核机器的核心不断增长。

具有大量核心数的机器的内存架构也进一步演化出了多层级的内存缓存系统。首先大量核心的系统由多个Socket拼接而成,Socket是指CPU插槽的数量。每个CPU插槽通常可以安装一个CPU。服务器通常会使用多个CPU插槽,每个CPU插槽可以插入一个独立的CPU,以提高系统的处理能力。然后单个CPU插槽内部有多个NUMA结点。NUMA代表"Non-UniformMemory Access",意思是非一致性内存访问,是一种计算机架构设计方法。NUMA构架下,不同CPU核心拥有自己的私有内存和公共内存,而不是所有的CPU核心共享同一块内存。NUMA设计旨在解决高性能计算中多处理器系统通过内存总线通信的瓶颈问题,提高系统的性能和可扩展性。最后单个NUMA内部具有多个处理器缓存分区。处理器缓存分区时最后一级缓存的拓扑特性。最后一级缓存被划分为多个分区,每个分区由一组处理器共享。同一处理器缓存分区的处理器对于高速缓存中数据的修改不会导致数据跨越多个内存层次架构进行传递,减少了数据线路上的通信开销,提升访存性能。

然而应用程序希望利用处理器缓存分区特性,优化程序性能并不容易。由于现有调度器的架构不支持处理器缓存分区,以及现有应用程序难以获取共享缓存线程组的语义,应用难以直接利用处理器缓存分区优化性能。

调度域由多重层次结构构成。最外层为全局调度域,包含单机结点上的所有cpu核心,例如在现有Kunpeng 920机器上,cpu核心总数为128个。现有多核机器往往有多个NUMA结点,因此NUMA调度域往往作为全局调度域的下层区域。NUMA调度域将总cpu核心数分为多个区块,例如在Kupeng 920机器上,共有4个NUMA结点,每个结点32个CPU核心。因此每个NUMA调度域包含同一个NUMA结点上的32个CPU。由于同一个NUMA结点上的CPU结点与内存结点物理距离更近,因此该CPU对于该内存结点的访问的延迟更低,吞吐量更高。若机器上存在超线程,调度域初始化时会为两个位于同一个物理核心上的超线程分配到同一个超线程调度域中。调度时利用超线程共享部分物理硬件的特性提升程序性能。但是现有调度域并没有将处理器缓存分区的拓扑结构考虑在内,因此需要对调度域进行完善,将物理机器的处理器缓存分区特性考虑在内。

现有数据密集型应用有许多的线程会在同一片共享内存区域处理数据。利用处理器缓存分区特性,将这些线程运行在同一个处理器缓存分区上可以减少访存时延,提高吞吐量。然而,现有数据密集型应用无法直接告知内核哪些线程访问共享内存变量。因此内核无法得知应该将哪些线程调度到同一个处理器缓存分区中。除此之外,即使应用开发者利用系统调用将访问共享内存变量的线程静态告知给内核,由于应用负载的多样性随着程序运行,可能原本访问同一个共享内存的线程将不再访问共享内存。也就是说,访问共享内存的线程组会动态变化。此时,应用开发者也难以利用系统调用告知内核哪些线程访问共享内存。

但现有内核提供了多种锁的语义,例如futex锁,semaphore锁,rwsem锁。类似地,其他操作系统也有相对应的锁的实现。由于线程组访问同一块共享内存需要获取同一把锁进行保护,因此可以在内核中利用应用对于锁获取的语义,获取访问同一块共享内存的线程组。而且即使这些线程组会动态变化,内核可以利用线程获取锁的线程动态信息实时更新访问共享内存的线程组信息。

CPS提出了虚拟化场景下的利用处理器缓存分区加速系统性能的方法。该方法通过将物理机器上的vCPU与处理器缓存分区之间的映射关系暴露给客户机,客户机利用动态变化的映射关系优化客户机调度器。但CPS需要修改应用,让应用利用syscall告知底层调度器访问共享变量的线程组信息。因此CPS无法做到对应用透明,加剧了应用开发者的负担。除此之外,当共享变量的线程组信息会随着应用语义动态变化时,应用开发者需要不断地用syscall通知调度器共享变量线程组的变化。一方面,这对于有大量共享变量线程组变动的应用来说,应用开发者需要巨大的工程量修改应用,使得这种方法不切实际。另外,大量的syscall也会对系统性能产生影响。

缩略语和关键术语定义

NUMA系统:Non-Uniform Memory Access,非一致性内存访问架构,在这种架构中多核计算机处理器访问内存的延迟取决于处理器与内存之间的距离。与处理器距离最近的内存被称为本地内存,服务器内其他内存子系统被称为该处理器的非本地内存。

CG:cache group,处理器缓存分区,指的是可以共享一个LLC缓存的单元,一般包含2到6个核心。

futex锁:futex(fast userspace mutex)锁是一种用于线程同步的机制,常用于Linux操作系统中。它旨在提高用户空间的线程锁的效率。futex锁的特点是它可以在用户空间内进行解锁和等待过程。当进程需要修改同一变量时,通过futex锁可以保证只有一个线程能够访问该变量,从而避免竞争条件(race condition)和死锁(deadlock)等问题。

Linux semaphore:Linux信号量(Semaphore)是一种用于多进程或多线程间同步访问共享资源的机制。Linux信号量常常作为进程间通信的一种手段,由于这种机制实现了对资源的独立性控制,因此它往往被用作进程同步和互斥机制。

Linux rwsem:rwsem(read-write semaphore)是Linux内核中的一种读写锁机制,也可称为读写信号。用于多线程或多进程间对共享资源的读写访问。当访问者为读者时,它允许多个读者进入临界区,以实现读者之间的并发读取,同时避免读者之间的数据竞争;当访问者为写者时,一次只允许一个写者进入临界区,并且会阻塞读者。

发明内容

针对现有技术中的缺陷,本发明的目的是提供一种基于锁语义实现应用透明的动态处理器缓存分区调度方法和系统。

根据本发明提供的基于锁语义实现应用透明的动态处理器缓存分区调度方法,包括:

步骤1:系统初始化时,内核检测硬件缓存分区特性,将位于同一组缓存分区的CPU核心标记为同一缓存分区核心组;

步骤2:多个用户线程获取同一把锁时,内核检测到获取同一把锁的用户态线程信息,将这些线程标记为同一交互线程组;

步骤3:在调度过程中,利用定时调度器与定时负载均衡器,将同一交互线程组调度到同一缓存分区核心组。

优选地,设计基于锁语义透明识别共享变量的线程组,对企图拿同一把锁的线程组进行标记,利用内核中的锁接口,包括futex锁、semaphore、读写semaphore锁,透明地将拿取锁的线程组标记为访问共享变量的线程组;

在运行时,利用内核中的锁接口对共享变量的线程组进行动态调整;

在线程选核时,利用最新的访问共享内存的线程组信息进行调度,当线程组信息发生变化时,调度器将线程进行迁移,仍保证访问共享变量的线程组位于同一处理器缓存分区中。

优选地,系统的核心组件为CG感知的调度器,包括4个CPU核心:CPU0、CPU1、CPU2和CPU3,其中,CPU0、CPU1位于同一个CG组,CPU2、CPU3位于同一个CG组,每个CG组对应一个CG负载均衡器,其中CG负载均衡器0监控CPU0和CPU1,CG负载均衡器1监控CPU2和CPU3;

系统启动时内核初始化获取硬件拓扑结构信息,将其中的硬件CG拓扑结构传入CG感知调度器,应用启动四个线程t0、t1、t2和t3,其中,t0与t1获取同一把锁A,t2与t3获取同一把锁B;交互线程识别器将t0与t1标记为同一组交互线程,将t2与t3标记为同一组交互线程,当CG感知调度器调度线程t3时,CG感知调度器发现t2,t3为同一组交互线程,且t2运行在CPU2,此时CG感知调度器将t3调度到CPU3,使得t2与t3位于同一个CG组;CG负载均衡器定时以CG为粒度检测系统负载信息,若发生负载不均,则将该CG上的一组交互线程迁移到空闲的CG上。

优选地,利用线程被唤醒后主动选核与负载均衡器的周期性选核,及时利用共享变量线程组信息进行调度;

负载均衡器将周期性地被时钟中断触发,产生负载均衡软中断,软中断处理函数中将对系统负载进行检查,当发生负载不均时,迁移线程使整个系统达到均衡状态;

在负载均衡器中增加共享变量线程组检查与迁移,当某个处理器缓存分区上运行多个线程组时,负载均衡器将对线程进行迁移。

优选地,用户直接使用现有的pthread库中的pthread_mutex_lock或者pthread_mutex_unlock,以及使用跨平台的C++的mutex库,用来保护临界区域,对于多种语言多种现有库的代码,均无需任何修改,直接部署。

根据本发明提供的基于锁语义实现应用透明的动态处理器缓存分区调度系统,包括:

模块M1:系统初始化时,内核检测硬件缓存分区特性,将位于同一组缓存分区的CPU核心标记为同一缓存分区核心组;

模块M2:多个用户线程获取同一把锁时,内核检测到获取同一把锁的用户态线程信息,将这些线程标记为同一交互线程组;

模块M3:在调度过程中,利用定时调度器与定时负载均衡器,将同一交互线程组调度到同一缓存分区核心组。

优选地,设计基于锁语义透明识别共享变量的线程组,对企图拿同一把锁的线程组进行标记,利用内核中的锁接口,包括futex锁、semaphore、读写semaphore锁,透明地将拿取锁的线程组标记为访问共享变量的线程组;

在运行时,利用内核中的锁接口对共享变量的线程组进行动态调整;

在线程选核时,利用最新的访问共享内存的线程组信息进行调度,当线程组信息发生变化时,调度器将线程进行迁移,仍保证访问共享变量的线程组位于同一处理器缓存分区中。

优选地,系统的核心组件为CG感知的调度器,包括4个CPU核心:CPU0、CPU1、CPU2和CPU3,其中,CPU0、CPU1位于同一个CG组,CPU2、CPU3位于同一个CG组,每个CG组对应一个CG负载均衡器,其中CG负载均衡器0监控CPU0和CPU1,CG负载均衡器1监控CPU2和CPU3;

系统启动时内核初始化获取硬件拓扑结构信息,将其中的硬件CG拓扑结构传入CG感知调度器,应用启动四个线程t0、t1、t2和t3,其中,t0与t1获取同一把锁A,t2与t3获取同一把锁B;交互线程识别器将t0与t1标记为同一组交互线程,将t2与t3标记为同一组交互线程,当CG感知调度器调度线程t3时,CG感知调度器发现t2,t3为同一组交互线程,且t2运行在CPU2,此时CG感知调度器将t3调度到CPU3,使得t2与t3位于同一个CG组;CG负载均衡器定时以CG为粒度检测系统负载信息,若发生负载不均,则将该CG上的一组交互线程迁移到空闲的CG上。

优选地,利用线程被唤醒后主动选核与负载均衡器的周期性选核,及时利用共享变量线程组信息进行调度;

负载均衡器将周期性地被时钟中断触发,产生负载均衡软中断,软中断处理函数中将对系统负载进行检查,当发生负载不均时,迁移线程使整个系统达到均衡状态;

在负载均衡器中增加共享变量线程组检查与迁移,当某个处理器缓存分区上运行多个线程组时,负载均衡器将对线程进行迁移。

优选地,用户直接使用现有的pthread库中的pthread_mutex_lock或者pthread_mutex_unlock,以及使用跨平台的C++的mutex库,用来保护临界区域,对于多种语言多种现有库的代码,均无需任何修改,直接部署。

与现有技术相比,本发明具有如下的有益效果:

(1)本发明利用锁的语义透明地识别用户态程序的共享变量的线程组,并且利用共享变量线程组信息优化调度器,将线程组调度到同一个处理器缓存分区,从而提升系统性能;

(2)本发明提出的基于锁语义实现应用透明的动态处理器缓存分区调度算法,可以无需修改用户程序,利用锁的接口获取访问共享变量线程组的语义信息,同时本发明提出了动态线程组调度算法,保证了在共享变量线程组动态变化的情况下,调度器可以动态调整,保证变化后的线程组可运行在同一个处理器缓存分区。

(3)本发明提出的基于锁语义实现应用透明的动态处理器缓存分区调度算法不仅适用于Linux操作系统,也适用于其他多种操作系统,只要该操作系统具备锁接口和多核调度功能,本发明的技术方案都可以在其中实施,这种广泛适用性使得本发明的应用范围更加广泛,并且能够满足不同操作系统下的需求。

附图说明

通过阅读参照以下附图对非限制性实施例所作的详细描述,本发明的其它特征、目的和优点将会变得更明显:

图1为本发明调度的总体架构图,分为CG拓扑结构、CG负载均衡器、交互线程识别器、CG感知调度器四个组件;

图2为交互线程识别器的工作原理;

图3为CG负载均衡器的工作原理;

图4为以Linux futex锁的底层实现为例,展示如何利用锁识别交互线程的原理;

图5为用户接口使用pthread锁示例;

图6为用户接口使用C++mutex锁示例。

具体实施方式

下面结合具体实施例对本发明进行详细说明。以下实施例将有助于本领域的技术人员进一步理解本发明,但不以任何形式限制本发明。应当指出的是,对本领域的普通技术人员来说,在不脱离本发明构思的前提下,还可以做出若干变化和改进。这些都属于本发明的保护范围。

实施例1

本发明提供了一种基于锁语义实现应用透明的动态处理器缓存分区调度方法,包括:系统初始化时,内核检测硬件缓存分区特性,并且将位于同一组缓存分区的CPU核心标记为同一缓存分区核心组;多个用户线程获取同一把锁时,内核检测到获取同一把锁的用户态线程信息,将这些线程标记为同一交互线程组;随后在调度过程中,利用定时调度器与定时负载均衡器将同一交互线程组调度到同一缓存分区核心组。

本发明的技术点:

1、设计基于锁语义透明识别共享内存变量的线程组。由于访问共享内存变量的线程组往往需要拿同一把锁,因此可以对企图拿同一把锁的线程组进行标记。这些线程组属于访问共享变量的线程组。本发明利用内核中的多种锁接口,例如futex锁、semaphore、读写semaphore锁,透明地将拿取锁的线程组标记为访问共享变量的线程组。因此无需修改上层应用,本发明可透明地识别访问共享内存变量的线程组,将信息提供给调度器从而优化性能。

2、基于锁语义在运行时动态地对访问同一共享变量的线程组标记进行调整。本发明在运行时会利用内核锁接口对共享内存变量的线程组进行动态调整。原本访问同一共享内存的线程组,由于程序语义的修改会访问不同的共享内存。本发明会在运行时获取这些内核锁语义,并且进行动态修改。

3、提出运行时动态线程组处理器缓存分区感知调度算法。本发明会在线程选核时,利用最新的访问共享内存的线程组信息进行调度。处理器缓存分区感知的调度算法会利用第1点和第2点中得到的线程组信息,尽可能地将这些线程组调度于同一个处理器缓存分区。当线程组信息发生变化时,调度器会将线程进行迁移,仍保证访问共享变量的线程组位于同一处理器缓存分区中。

以下是对上述技术点的补充说明:

如图1所示,系统的核心组件为CG感知的调度器。其中展示了4个CPU核心:CPU0,CPU1,CPU2,CPU3。且CPU0,CPU1位于同一个CG组,CPU2,CPU3位于同一个CG组。每个CG组对应一个CG负载均衡器。其中CG负载均衡器0监控CPU0,CPU1。CG负载均衡器1监控CPU2,CPU3。系统启动时内核初始化获取硬件拓扑结构信息,将其中的硬件CG拓扑结构传入CG感知调度器。应用启动了四个线程t0,t1,t2,t3。这些线程中,t0与t1获取了同一把锁A,t2与t3获取了同一把锁B。因此交互线程识别器将t0与t1标记为同一组交互线程;将t2与t3标记为同一组交互线程。当CG感知调度器调度线程t3时,CG发现t2,t3为同一组交互线程,且t2运行在CPU2,因此CG感知调度器将t3调度到CPU3,使得t2与t3位于同一个CG组。除此之外,CG负载均衡器会定时以CG为粒度检测系统负载信息,一旦发生负载不均,会将该CG上的一组交互线程迁移到空闲的CG上。

如图2所示,本发明定义了一个内核组件交互线程组识别器。交互线程组识别器可以透明地动态地解决如何识别共享变量任务组地问题。图中显示了四个线程t0、t1、t2、t3,其中前两者获取深色锁,后两个线程获取浅色锁。交互线程识别器将t0、t1标记为访问共享内存的线程组,将t2、t3标记为另一组。随着程序运行,线程运行访问共享内存的特性发生了变化,此时t1、t2获取深色锁,t0、t3获取浅色锁。因此交互线程识别器将t1、t2标记为访问共享内存的线程组,将t0、t3标记为另一组。当t0、t1、t2、t3均获取红色锁后,交互线程识别器将这些线程均标记为同一组。

本发明可以在不修改用户态程序代码的前提下,识别访问共享变量线程组的问题。当访问共享变量线程组的共享关系发生变化时,交互线程识别器可以获取上层应用语义信息,并且进行动态调整。

由于共享变量的线程组会动态变化,因此调度器需要及时利用最新的共享变量线程组信息进行调度。本发明利用线程被唤醒后主动选核与负载均衡器的周期性选核及时利用共享变量线程组信息进行调度。如图3所示,起初t1和线程t2属于同一个共享线程组,由于线程执行过程中的变化,t1和t2属于不同两个线程组,因此需要进行线程的迁移。首先负载均衡器将周期性地被时钟中断触发,产生负载均衡软中断,软中断处理函数中将会对系统负载进行检查。当发生负载不均时,会迁移线程使整个系统达到均衡状态。本发明在负载均衡器中增加了共享变量线程组检查与迁移。当某个处理器缓存分区上运行了多个线程组时,负载均衡器将对线程进行迁移。如图2所示,线程t1此时与线程t3同属一个共享变量组,此时处理器缓存分区负载均衡1发现t1并没有运行在处理器缓存分区1,因此进行了线程迁移,将t1迁移到了处理器缓存分区1。线程t0和线程t2同属于一个共享线程组,线程t2此时因为等待拿锁而入睡,当t2允许拿锁时,内核会唤醒t2,并且为t2选择合适的核心。由于t0与t2的线程属于访问共享变量的线程组,因此t2会被调度到处理器缓存分区0的空闲CPU上,即CPU1。从而实现了所有访问共享变量的线程组运行在同一个处理器缓存分区的要求。

具体来说,以futex锁为例,如图4所示,A1、A2、B、C1、C2方框为交互线程组识别器示意图,其他方框为现有futex锁设计。现有futex设计中对于锁会在用户态地址进行区分。其中futex设计利用哈希表存储所有的锁结构。具体来说,首先对用户态地址计算哈希值,每个哈希值会对应某个哈希表的桶,例如uAddr c计算哈希后对应Key 2桶。桶中利用链表串联起属于该桶的线程,其中线程C1、C2均属于该桶。本发明增加了桶内额外一条链表,用于储存交互线程识别器信息。其中线程C1和线程C2内会有指针指向uAddr c锁识别器。当调度器为C1、C2选核时会利用uAddr c锁识别器的信息进行决策。由于多个用户态地址可能映射到同一个桶,例如uAddr a和uAddr b的哈希相同,因此这些线程会被串联在同一个链表上。此时,uAddr a锁识别器和uAddr b锁识别器会被挂载在同一个桶的链表中。此时线程A1、A2会检查uAddr a锁识别器中存储的用户态地址与uAddr a是否相同,若相同则会存在将uAddr a锁识别器的地址记录在线程A1、A2的数据结构中。由于线程B的uAddr b与uAddra不相同,因此线程B内的指针不会指向uAddr a锁识别器,而是会指向uAddr b锁识别器。

如图5和图6所示,用户可直接使用现有的pthread库中的pthread_mutex_lock或者pthread_mutex_unlock,以及使用跨平台的C++的mutex库,用来保护临界区域。对于多种语言,多种现有库的代码,均无需任何修改,直接部署便可利用处理器缓存分区特性获得性能提升。应用透明的动态处理器缓存分区调度算法会识别缓存特性,自动优化程序性能。

实施例2

本发明还提供一种基于锁语义实现应用透明的动态处理器缓存分区调度系统,所述基于锁语义实现应用透明的动态处理器缓存分区调度系统可以通过执行所述基于锁语义实现应用透明的动态处理器缓存分区调度方法的流程步骤予以实现,即本领域技术人员可以将所述基于锁语义实现应用透明的动态处理器缓存分区调度方法理解为所述基于锁语义实现应用透明的动态处理器缓存分区调度系统的优选实施方式。

根据本发明提供的基于锁语义实现应用透明的动态处理器缓存分区调度系统,包括:模块M1:系统初始化时,内核检测硬件缓存分区特性,将位于同一组缓存分区的CPU核心标记为同一缓存分区核心组;模块M2:多个用户线程获取同一把锁时,内核检测到获取同一把锁的用户态线程信息,将这些线程标记为同一交互线程组;模块M3:在调度过程中,利用定时调度器与定时负载均衡器,将同一交互线程组调度到同一缓存分区核心组。

设计基于锁语义透明识别共享变量的线程组,对企图拿同一把锁的线程组进行标记,利用内核中的锁接口,包括futex锁、semaphore、读写semaphore锁,透明地将拿取锁的线程组标记为访问共享变量的线程组;

在运行时,利用内核中的锁接口对共享变量的线程组进行动态调整;

在线程选核时,利用最新的访问共享内存的线程组信息进行调度,当线程组信息发生变化时,调度器将线程进行迁移,仍保证访问共享变量的线程组位于同一处理器缓存分区中。

系统的核心组件为CG感知的调度器,包括4个CPU核心:CPU0、CPU1、CPU2和CPU3,其中,CPU0、CPU1位于同一个CG组,CPU2、CPU3位于同一个CG组,每个CG组对应一个CG负载均衡器,其中CG负载均衡器0监控CPU0和CPU1,CG负载均衡器1监控CPU2和CPU3;

系统启动时内核初始化获取硬件拓扑结构信息,将其中的硬件CG拓扑结构传入CG感知调度器,应用启动四个线程t0、t1、t2和t3,其中,t0与t1获取同一把锁A,t2与t3获取同一把锁B;交互线程识别器将t0与t1标记为同一组交互线程,将t2与t3标记为同一组交互线程,当CG感知调度器调度线程t3时,CG感知调度器发现t2,t3为同一组交互线程,且t2运行在CPU2,此时CG感知调度器将t3调度到CPU3,使得t2与t3位于同一个CG组;CG负载均衡器定时以CG为粒度检测系统负载信息,若发生负载不均,则将该CG上的一组交互线程迁移到空闲的CG上。

利用线程被唤醒后主动选核与负载均衡器的周期性选核,及时利用共享变量线程组信息进行调度;

负载均衡器将周期性地被时钟中断触发,产生负载均衡软中断,软中断处理函数中将对系统负载进行检查,当发生负载不均时,迁移线程使整个系统达到均衡状态;

在负载均衡器中增加共享变量线程组检查与迁移,当某个处理器缓存分区上运行多个线程组时,负载均衡器将对线程进行迁移。

用户直接使用现有的pthread库中的pthread_mutex_lock或者pthread_mutex_unlock,以及使用跨平台的C++的mutex库,用来保护临界区域,对于多种语言多种现有库的代码,均无需任何修改,直接部署。

本领域技术人员知道,除了以纯计算机可读程序代码方式实现本发明提供的系统、装置及其各个模块以外,完全可以通过将方法步骤进行逻辑编程来使得本发明提供的系统、装置及其各个模块以逻辑门、开关、专用集成电路、可编程逻辑控制器以及嵌入式微控制器等的形式来实现相同程序。所以,本发明提供的系统、装置及其各个模块可以被认为是一种硬件部件,而对其内包括的用于实现各种程序的模块也可以视为硬件部件内的结构;也可以将用于实现各种功能的模块视为既可以是实现方法的软件程序又可以是硬件部件内的结构。

以上对本发明的具体实施例进行了描述。需要理解的是,本发明并不局限于上述特定实施方式,本领域技术人员可以在权利要求的范围内做出各种变化或修改,这并不影响本发明的实质内容。在不冲突的情况下,本申请的实施例和实施例中的特征可以任意相互组合。

技术分类

06120116576343