动态二进制翻译器中热路径的多核多线程构建方法

文档序号:6482257阅读:208来源:国知局
专利名称:动态二进制翻译器中热路径的多核多线程构建方法
技术领域
本发明涉及一种动态二进制翻译器中热路径的多核多线程构建方法,用于提高动态二进制翻译器的性能以及为未来的优化工作提供一种新的框架和新的思路。本发明属于二进制翻译技术领域。
背景技术
动态二进制翻译技术是虚拟机技术中非常重要的一种实现方法,其特点在于在没有任何高级语言源代码信息的条件下,可以通过直接加载源机器端的二进制可执行程序,并利用自身对不同机器指令集架构(ISA)的翻译功能,得到目标机器端的可执行二进制程序,从而达到跨平台执行程序的目的。但是,这种技术目前仍处于探索和研究的阶段,各种现有的翻译器存在的普遍缺点是
性能较差,特别体现在各种跨体系结构的动态二进制翻译器上,例如QEMU (afast machine emulator)翻译器的平均执行时间是本地执行时间的4-5倍左右,由上海交通大学动态二进制翻译小组自主开发的动态二进制翻译器CrossBit (引自文献Design and Implementation of CrossBit: Dynamic Binary Translation Infrastructure)的平均执行时间也在4倍左右。这个缺点严重阻碍了动态二进制翻译技术的普及和应用,因此,优化动态二进制翻译系统的性能是一项极具实践价值和研究意义的工作。
构建热路径(profiling and building hot trace)是目前动态二进制翻译器中最主要的优化方法之一。热路径是指执行次数较多的路径,通常是通过剖分(profiling)技术识别到的大于某一个阈值的路径。热路径的执行效率对总的目标代码的执行效率有很大的影响。构建热路径的方法就是针对检测到的各条热路径上的所有基本块,进行重新组织,把热点的最后一条跳转指令和它指向的最有可能跳转到的目的基本块拼凑在一起,从而有效地减少了大量跳转指令的开销,达到提高性能的目的。剖分是指通过对运行中的程序进行监测,对程序
3执行行为特征的数据信息进行收集的过程。常用的剖分方法有以下两种-
1、 采用instrumentation (插桩)的方式,这种方式通过在代码中插入探针指令或直接利用支持剖分技术的硬件来采集和程序执行行为、特性有关的数据信息。这种方法由于借助软件实现,成本较低。
2、 采用sampling (采样)的方式,这种方式以一定的时间间隔对程序运行的相关数据进行数据收集,而不需要对程序进行修改,但是要借助硬件实现,成本较高。
二进制翻译系统中构建热路径的正常流程是首先,在每一个执行基本块中
插入profiling模块,该模块的功能就在于记录每个基本块的执行次数。然后,一旦这段机器码检测到一个热点(当某个基本块执行次数大于特定的阈值时,该基本块就被称为一个热点),程序就需要保存现场,并执行上下文切换操作,返回到高级语言中去调用相应的构建热路径的模块,然后将调整后的热路径翻译为新的可执行代码,这段可执行代码组成的块被成为超级块(Super block)。最后,当该模块返回超级块后,系统将重新执行这个超级块。但是,构建热路径和翻译超级块的工作本身和二进制翻译的正常执行流程之间并没有必然的联系,而且使用这种线性的构建热路径方式是以多次保存程序现场和引入额外的上下文切换操作来实现的。这部分开销对于热路径较多的程序还是相当可观的。因此,可以尝试一种新的方法来更高效地完成热路径的构建和超级块的翻译,从而更进一步地提高整个动态二进制翻译系统的性能。

发明内容
本发明的目的在于针对现有技术的不足,提供一种动态二进制翻译器中热路径的多核多线程构建方法,防止因为构建热路径而引入的保存程序现场行为,减少额外的上下文切换开销,提高整个动态二进制翻译器系统的性能。
为实现上述目的,本发明首先将整个动态二进制翻译器的基本块翻译和目标代码的执行部分划分为主执行线程,然后将热路径的构建和翻译超级块的部分划分为子线程,并改变了通用的动态二进制翻译器中独立的代码缓存(Cache)结构为双代码缓存的设计方式,利用哈希函数统一管理这两个代码缓存,使主线程和子线程在数据查询和更新过程中可以并行进行,然后通过结合硬亲和力(hardaffinity)使动态二进制翻译器的主线程和子线程分别在两个不同的处理器(CPU)核上运行,最后,用连续的一段内存空间和两个计数器来模拟一段队列,
在机器语言级和高级语言级进行两线程间的通信。
本发明的动态二进制翻译器中热路径的多核多线程构建方法具体实现步骤
如下
1、 本发明将原有动态二进制翻译器的"翻译,优化,执行"的串行执行工作机制改变为"翻译,执行"的主程序流程与"构建热路径和翻译超级块优化"
的子程序流程并行的工作机制。具体为利用多线程编程的技术,将基本块翻
译和目标代码的执行部分作为主线程,将构建热路径和翻译超级块部分作为子线程,主线程和子线程并行工作,构成多线程的动态二进制翻译器系统优化架构。
2、 原有的动态二进制翻译器中采用了唯一的目标代码缓存(Target CodeCache)来存储翻译好的目标代码基本块和热路径组成的超级块。这种设计方式在并行工作机制中会造成主程序和子程序大量的内存访问冲突,严重影响系统的性能,本发明将该设计方式改变为双目标代码缓存架构, 一个缓存用于存放主线程翻译得到的目标代码基本块(Target Code Basic Block),另一个缓存用于存放由子线程构建热路径后得到的目标代码超级块(Target Code Super Block),然后通过全局的哈希表函数来控制主线程和子线程对这两个缓存的读和更新操作。
3、 使用硬亲和力将主线程分配在多核处理器的0号核上执行,将子线程分配在1号核上执行。
4、 主线程利用生产者计数器作为索引值,在机器语言级别对一段连续的内存空间不断地压入热点的入口地址,子线程利用消费者计数器作为索引值,在高级语言级别不停地从这段连续的内存空间去读取热点的入口地址,完成两线程间的通信。
本发明的优点在于利用多核多线程技术,在为动态二进制翻译器提供高质量的优化后目标代码的同时,能够尽量屏蔽掉构建热路径算法本身开销对系统总性能的影响。本发明的特点在于采用了双目标缓存的设计方式,使基本块翻译和目标代码执行的主线程与热路径的构造和超级块翻译的子线程之间互不干
扰,并发明了一种更适合于本发明例中线程间通信场景的机制,这些技术为多线程方式构建热路径的方法提供了高并行性和低同步开销的优良特质,从而有效地加强了程序执行的稳定性和效率。同时由于本发明提出的方法对于其他的各种二进制优化算法同样适用,因此也为今后动态二进制翻译器的优化工作提供了新的思路和新的框架。


图1为动态二进制翻译器中热路径的多核多线程构建方法的系统框架图。
具体实施例方式
为更好地理解本发明的技术方案,以下通过具体的实施例作进一步描述。以下实施例不构成对本发明的限定。1.设计新的系统架构
本发明是基于上海交通大学自主开发的动态二进制翻译器CrossBit之上研制的,正常的CrossBit的执行流程为(1)加载源可执行映像;(2)查找哈希表中是否存在翻译后的目标机器码对象;(3)若查找命中,执行对应的目标机器代码;若查找缺失,则执行"由源机器码组成的基本块->由中间指令组成的基本块->由目标机器代码组成的基本块"的基本块两次翻译的过程,并将结果存入目标代码缓存中并更新哈希表,然后执行翻译好后的目标机器代码;(4)在执行目标代码的过程中,不断的通过剖分技术获取程序执行信息, 一旦某个块的执行次数大于阈值3000,则执行上下文切换操作,回到CrossBit程序中调用构建热路径的函数,并翻译得到超级块,将该超级块存入目标代码缓存中并更新哈希表;(5)然后开始执行翻译好后的超级块,当执行完一个块后,通过块结束时的跳转指令的目的地址重复(2)至(5)的操作流程。
本发明将上述流程中的基本块翻译和目标代码的执行部分作为CrossBit的主线程,而将构建热路径和翻译超级块部分变为独立的子线程,从而构成多线程的动态二进制翻译器系统优化架构,线程的创建和相关操作用Linux的pthread库函数实现。如附图1所示,子线程通过获取主线程传递来的热点入口地址信息启动,构建完一条热路径后并翻译得到超级块,将该超级块放入超级块目标缓存中,并更新全局的哈希表。然后子线程阻塞等待下一个热点信息。子线程等待数据产生的方式采用轮询查找来实现,因为这种方式对某一事件发生具有最快的响应效率。
2. 设计新的目标缓存架构
为了防止上述流程(3)中产生的基本块插入目标缓存的操作与流程(4)中产生的超级块插入目标缓存的操作产生冲突,本发明采用了双目标代码缓存架构。所谓双目标缓存,就是指设置两个可以存放翻译好后的目标代码的容器,一个用来存放主线程翻译得到的目标代码基本块,另一个用于存放由子线程重构热路径后得到的目标代码超级块,然后通过全局的哈希表函数来控制主线程和子线程对这两个缓存的读和更新操作。本发明的哈希表函数的映射关系式为取各个块入口地址的十六进制表示的最后四位数字来获得关系映射的结果,如0x40005678在哈希表中的偏移值即为5678,通过该数值我们可以在内存中唯一的寻址数据。本发明的两个目标缓存均被声明为10MB的连续内存空间,这两部分空间通过Linux系统调用mmap ()和库函数malloc ()申请获得,该内存空间具有可读写、可执行的权限。
3. 指定明确的硬亲和力
所谓亲和力,即一个线程更倾向于执行的处理器核心的集合。例如,若存在一个四核处理器P,分别用0, 1, 2, 3来代表这四个核的名称,若某个线程的亲和力为{0, 1},就是指该线程会由操作系统随机的分配在P的0号核或1号核上。硬亲和力,就是明确指派线程执行在具体的哪一个处理器核上。本发明将主线程分配在多核处理器的0号核上执行,将子线程分配在1号核上执行。在Linux系统环境下,相关的系统调用为
int sched一setaffinity (pid_t pid, size_t len, cpu_set_t *mask);
其中,pid参数为是线程的id号,可以通过gettid ()系统调用获得;len变量为集合的大小,可通过sizeof (&mask)的操作获得;mask为指向可能分配的目标处理器核的集合的指针。
设置该集合需要两个宏调用
cpu—set—t mask; //mask为一个可以放置目标核的集合
CPU—ZERO(&mask); 〃该操作将mask集合清空
CPU—SET(0,&mask); 〃该操作将mask集合添加0号核
4.设计新的线程间通信的机制
根据附图1的模型可知,本发明的系统的主线程和子线程之间的通信手段属
于生产者和消费者的通信模型。常用的处理这种多线程模型的方式为采用二进
制信号量的方法来解决。大致过程为(1)设置初始信号量3=1, C=0,其中,S
为控制生产者写临界区的信号量,c为启动子线程读临界区的信号量。(2)当生产者产生了一个数据后,生产者对信号量s进行减l操作,然后进入临界区。每个线程中访问临界资源的那段程序称为临界区(Critical Section),临界资源是指一次仅允许一个线程使用的共享资源。(3)在临界区中,主线程完成对全局变量的写操作,然后对信号量s加一并同时对c加一,这时消费者子线程可以对信号量c减一进入它的临界区,在这部分临界区中完成相应的消费操作。
这种模型虽然对于之前提出的系统框架同样适用,但是并不高效。因为本发明并没有必要在剖分过程中检测到一个热点时就切换上下文回到高级语言中进行信号量的操作,这部分上下文切换的开销是可以避免的。为此,本发明采用主线程利用生产者计数器作为索引值,在机器语言级别对一段连续的内存空间不断地压入热点的入口地址的同时,子线程利用消费者计数器作为索引值,在高级语言级别不停地从这段连续的内存空间读取热点的入口地址的方式,来完成两线程间的通信。
具体的实现方法为
1) 首先,本发明需要在内存中开辟一段可读写操作的连续的内存空间M。这段连续的空间M用于存放所有热点的入口地址。
2) 设置生产者计数器producerCount和消费者计数器consumerCount,分别作为主线程和子线程对内存空间M做读写操作的索引值,均初始化为0。
3) 将CrossBit插桩(instrumentation)做剖分部分的代码扩充,实现如下的功能
I. 当一个基本块执行的次数超过阈值3000之后,首先判断该热点的入口地址是否已经被保存在内存空间M中,这个可以通过对每个基本块增加一个写入内存空间M与否的标志位来实现。
II. 如果该热点入口地址没有被保存在内存空间M中,则首先得到producerCount变量的内存地址,通过访存指令将producerCount的值移入一个固定的运算寄存器RA和一个固定的备份寄存器RB中。然后将运算寄存器RA左移2位,相当于乘以4,因为移位操作比乘法操作更加高效,所以这里选择移位操作。乘以4是因为每一个热点入口地址是一个无符号整型的变量,如果要保存到内存中是需要4个字节空间的。将运算得到的寄存器RA中的值与M的首地址相加,就得到了写入这段内存空间M的具体的内存位置,然后执行mov操作,把这个热点的入口地址保存到该位置。
III. 最后,取出备份寄存器RB中的值,把RB加1后将其值写回到生产者计数器producerCount的内存地址中去,完成对producerCount的加1操作,以便再次写入时,写入地址对应着内存空间M的下一个存放入口地址的位置。
4) 在构建超级块的子线程中,该线程首先读取生产者计数器producerCount的值,然后和消费者计数器consumerCcmnt做比较,如果两个值不相等的话,就说明主线程已经修改了 producerCount的值。由于子线程在高级语言中实现,可以直接通过高级语言的寻址操作,首先得到该连续内存的首地址并赋给一个指针变量pM,然后通过气pM+consumerCount)的操作即可获得一个热点的地址值。通过这个输入来启动子线程开始工作,构建热路径并翻译超级块,接着完成更新哈希表操作。最后对consumerCount进行加1操作,并与producerCount再次比较,如果仍然小于它,则继续读内存M中下一个入口地址的值并再次构建新的超级块。如果相等,则采取轮询等待的方式继续等待生产者计数器的改变。
权利要求
1、一种动态二进制翻译器中热路径的多核多线程构建方法,其特征在于包括如下步骤1)将基本块翻译和目标代码的执行部分作为主线程,将构建热路径和翻译超级块部分作为子线程,主线程和子线程并行工作,构成多线程的动态二进制翻译器系统优化架构;2)采用双目标代码缓存架构,一个缓存用于存放主线程翻译得到的目标代码基本块,另一个缓存用于存放由子线程重构热路径后得到的目标代码超级块,然后通过全局的哈希表函数来控制主线程和子线程对这两个缓存的读和更新操作;3)使用硬亲和力将主线程分配在多核处理器的0号核上执行,将子线程分配在1号核上执行;4)主线程利用生产者计数器作为索引值,在机器语言级别对一段连续的内存空间不断地压入热点的入口地址,子线程利用消费者计数器作为索引值,在高级语言级别不停地从这段连续的内存空间去读取热点的入口地址,完成两线程间的通信。
全文摘要
本发明提出了一种动态二进制翻译器中热路径的多核多线程构建方法。本发明首先将基本块翻译和目标代码的执行部分作为主线程,将构建热路径和翻译超级块部分作为子线程,变通用的动态二进制翻译器中独立的代码缓存结构为双代码缓存的设计方式,利用哈希表函数统一管理这两个代码缓存,使主线程和子线程在数据查询和更新过程中可以并行进行,然后结合硬亲和力指定主线程和子线程工作在多核处理器的不同核上,并用连续的一段内存空间和两个计数器来模拟一段队列,在机器语言级和高级语言级进行两线程间的通信。本发明具有高并行性和低同步开销的优良特质,为今后动态二进制翻译器的优化工作提供了新的思路和新的框架。
文档编号G06F9/45GK101477472SQ200910045058
公开日2009年7月8日 申请日期2009年1月8日 优先权日2009年1月8日
发明者李晓龙, 梁阿磊, 管海兵, 郑德恩, 顾静辉 申请人:上海交通大学
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1