片上多核处理器的并行功能仿真系统及其方法 【技术领域】
本发明属于信息处理系统的处理器的仿真领域,具体涉及一种片上多核处理器的并行功能仿真系统及其方法。
背景技术
计算机仿真用软件来仿真计算机系统的行为,研究者可以通过仿真软件分析新结构的性能和行为,而不需要建立原型系统,这大大减小了研究的周期和成本。近十年以来,工业界和学术界将仿真技术广泛地运用于计算机硬件和软件体系结构的研究以及开发过程中。随着多核时代的来临,仿真技术在多核处理器的设计过程中将变得越来越重要。
目前,绝大多数多核仿真器都是串行仿真器,这些仿真器仅仅运行于一个主线程上。随着目标系统核数的增加,仿真器的性能将会越来越差。在不久的将来,摩尔定律将由每18个月片上的晶体管数目翻一番转变为每18个月片上的硬件线程的数目翻一番。
然而,随着片上核数的增加,仿真过程中的状态量和代码空间将增加,这将导致仿真时间的增加。这也可能导致L2 Cache缺失的大幅度增加,从而导致仿真周期数的增加。因此,随着目标系统的核数的增加,如何在多核处理器上仿真多核目标系统将变得越来越重要。
功能仿真,又被称作为仿真内核,是计算机系统仿真过程中的一种重要的工具。它通常被设计成一个高度自治的库,为仿真器的其他部分提供接口。通常情况下,仿真内核具有创建和销毁软件上下文、加载程序、仿真当前存在的上下文、查询上下文状态、执行机器指令和处理预测行为的功能。在串行仿真内核中,只有一个线程在操作系统内核上运行。通常情况下,仿真内核从上下文配置文件中读取上下文的内容,然后将每个上下文分配给每个踪迹。操作系统内核中的主线程将执行这些上下文中的指令。但是串行仿真器有它与生俱来的缺陷,即随着目标系统上核数的增加,仿真器的整体性能将下降。
【发明内容】
本发明目的在于提供一种片上多核处理器的并行功能仿真系统,解决了现有技术中串行功能仿真技术中由于目标系统的核数的增加而形成的性能下降的问题。
为了解决现有技术中的这些问题,本发明提供的技术方案是:
一种片上多核处理器的并行功能仿真系统,包括系统输入模块和系统输出模块,其特征在于所述系统还包括仿真内核模块,所述仿真内核模块接受系统输入模块提供的目标系统上所运行的工作负载信息,所述仿真内核模块根据工作负载的类型动态创建多线程进行仿真工作负载的并行化处理,并通过系统输出模块输出。
优选的,所述仿真内核模块包括多道程序仿真负载处理模块和多线程程序仿真负载处理模块。
优选的,所述多道程序仿真负载处理模块根据配置文件为每个应用程序分配上下文,并将上下文组织成上下文链表后创建每个上下文的线程。
优选的,所述多线程程序仿真负载处理模块创建主线程运行于目标系统的顶层进行初始化后根据上下文链表中插入的上下文信息调用系统调用动态创建若干个子线程。
优选的,所述仿真系统还包括共享变量保护模块,当多个线程同时对共享变量进行并发访问时,所述共享变量保护模块使用操作系统级的互斥锁和障碍操作使并发访问过程序列化。
优选的,所述仿真系统还包括线程局部存储模块,所述线程局部存储模块提供在创建线程时每个线程中进行全局变量的拷贝。
优选的,所述仿真系统还包括数据填充模块,所述数据填充模块在不同的高速缓存行中填充分配不同宿主处理器核访问的数据。
本发明的另一目的在于提供一种片上多核处理器的并行功能仿真方法,其特征在于所述方法包括以下步骤:
(1)所述仿真内核模块接收系统输入模块提供的目标系统上所运行的工作负载信息,并从工作负载的上下文配置文件中加载上下文信息;
(2)所述仿真内核模块根据所加载的上下文信息,创建相应数目的线程;
(3)所述仿真内核模块动态创建的线程与主线程并行运行,执行相应的上下文中的指令,进行系统输出完成系统仿真。
优选的,所述方法中所述仿真内核模块动态创建的线程与主线程进行同步时,通过操作系统级的互斥锁和障碍操作实现同步访问共享变量。
优选的,所述方法中所述仿真内核模块创建的线程通过线程局部存储模块进行全局变量私有化和通过数据填充模块通过填充的方法来保证不同宿主处理器核上的数据在不同的Cache行中被分配。
本发明人经长期研究,在原串行仿真器的基础上进行开发,得到并行化处理的功能仿真器。本发明的并行功能仿真器基于串行功能仿真器的代码,利用并行编程技术进行相关代码的并行化。通过并行化技术实现直接而又有效的加速仿真的速度。
并行化功能仿真器的具体工作步骤如下:仿真内核从上下文配置文件中加载上下文信息;根据所加载的上下文信息,创建相应数目的线程;这些所创建的线程与主线程并行运行,执行相应的上下文中的指令,直至完成仿真。
然而,简单的直接将串行仿真器并行化并不能真正实现并行化功能仿真器;在并行化实现过程中本发明人遇到以下亟需解决的难题:
首先是仿真内核的并行化问题:在仿真器运行的过程中,创建线程的数目通常由目标系统上所运行的工作负载的类型决定。根据仿真负载的类型,有区别地进行仿真内核的并行化,包括多道程序仿真负载的并行化和多线程程序仿真负载的并行化。其次,共享变量的保护以及同步问题:在并行化的过程中需要线程间的同步,这些同步操作将引起性能下降,因此,需要实现共享资源的保护以及线程间的同步。另外全局变量的私有化问题:在串行仿真器中有些状态变量是全局的,但在并行仿真器中,这些全局变量可能为单个核所拥有,必须实现这些全局变量的私有化。另外假共享问题:在并行仿真内核的过程中,将会存在假共享现象,假共享将会大大影响并行仿真器的性能。
本发明人经长期研究,找出上述问题的解决方法,具体方案如下:
(1)仿真内核的并行化:
通常情况下,串行功能仿真内核通过从配置文件中加载上下文信息来配置多道程序的执行路径。在执行之前,内核通常为每个应用程序分配上下文,然后直接将这些上下文组织成上下文链表。因为在多道程序中,线程之间的同步操作很少,每个上下文通常对应一个线程,所以可以在上下文链表形成后再创建相应的线程。
在多线程工作负载中,仅有一个上下文(通常被称为主线程),在初始化的时候,该线程运行于目标系统的顶层,但是在运行的过程中,它会调用系统调用创建很多子线程。很显然,这些上下文必须动态地插入到上下文链表中。因此,不但需要在子线程创建的时候创建相应的线程,而且必须对内核进行扩展,让它能够支持动态创建线程的功能。
(2)共享变量的保护以及同步:
在并行化串行程序的过程中,对并发操作所访问的共享数据的保护非常重要。在这一过程中,通常用锁使得这些并发访问过程序列化。在并行功能仿真器的实现过程中,有许多种类的共享变量,例如哈希表、共享内存空间和上下文链表等等。当多个线程同时对共享变量进行并发访问的时候,通常用操作系统级的互斥锁来提供必要的保护。但是,在运用锁的时候要注意锁的运用粒度和数量,以避免死锁,从而达到比较理想的性能。
再者,同步操作常运用于多线程程序中的不同线程的不同下文之间。在串行仿真器中,执行同步操作的时候,仅需要将对应的上下文放到相应的挂起列表中。但是,在并行仿真器中,当同步操作发生的时候,必须同时挂起操作系统线程和它所对应的上下文。在此过程中,可以通过利用操作系统级的锁以及障碍操作来实现这样的操作。
(3)全局变量的私有化:
在串行仿真器中,仿真器的许多状态都是作为全局变量所共享的。但是在并行仿真器中,这些变量可能有许多拷贝版本以反映不同核的状态。假如简单地将这些变量修改成向量,将会增加整体的复杂性。并行化过程中,通常用线程局部存储来解决这个问题。
线程局部性存储实现如下:在gcc中,为了表明一个变量在线程创建的时候所有的线程都拥有它的拷贝,通常将__thread关键字放在全局或者静态变量声明之前。
(4)假共享问题的解决
在多核处理器的串行仿真器中,许多数据结构被转化成结构体数组的形式,假如每一个核拥有这个数组中的一个元素,在并行化的过程中,可能导致假共享。为了解决这个问题,可以用填充的方法来保证不同核上的数据在不同的Cache行中被分配。
相对于现有技术中的方案,本发明的优点是:
与串行仿真器相比,经仿真实验证实,本发明的并行功能仿真系统具有更高的加速比,所以本发明的并行功能仿真系统具有较高的整体性能。
【附图说明】
下面结合附图及实施例对本发明作进一步描述:
图1为并行功能仿真器的执行模型示意图;
图2为并行功能仿真器运行多道负载时获得的加速比;
图3为并行功能仿真器运行多道负载时获得的平均加速比;
图4为并行功能仿真器运行多线程负载时所获得的加速比;
图5为并行功能仿真器运行多线程负载时所获得的平均加速比。
【具体实施方式】
以下结合具体实施例对上述方案做进一步说明。应理解,这些实施例是用于说明本发明而不限于限制本发明的范围。实施例中采用的实施条件可以根据具体厂家的条件做进一步调整,未注明的实施条件通常为常规实验中的条件。
实施例并行功能仿真系统的实践及试验
本实施例在串行仿真器Multi2sim‑2.1的基础上,实现了并行功能仿真器。在整个实施过程中,所用的服务器是曙光天演EP850‑GF小型机,该小型机具体配置如下:8颗4核AMD Opteron 83461.8G HE CPU,32G DDR2ECC内存,4*146G SAS硬盘。该服务器运行的操作系统是LinuxDebain(X86‑64)。
实验表明,串行仿真器Multi2sim‑2.1在仿真8核的目标系统的时候,仿真减速达到18.24。当该仿真器仿真16核的目标系统的时候,仿真减速竟达到165.24。随着目标核数的增加,串行仿真器的仿真减速将会急剧增加。因此,必须用并行化来加速仿真器,来提高该仿真器的整体性能。
在本实施例中,串行仿真引擎首先加载多道负载或多线程负载,然后分别创建多个上下文。假如负载类型不同,创建上下文的方式也会有所不同。对于多道负载,上下文是在多道负载中每个应用程序加载到客户内存的同时创建的,而对于多线程负载,加载时只创建一个主上下文,而其余上下文则是在当主上下文执行到对应的线程创建原语时动态生成的。仿真引擎为所有创建的上下文共同维护了一系列状态链表(活动、挂起等),然后依次执行各个活动的上下文的指令,这一过程中可能会修改上下文的状态,当所有上下文所需要执行的指令都完成时则结束功能仿真。从这一过程的描述可以看出,多核功能仿真具有天然的对称性和隔离性,同时还应指出功能仿真中不会涉及对流水线、Cache等微体系结构的仿真,这些都极大的简化了并行功能仿真器的设计和实现。
在本实施例中,基本思想就是使用POSIX多线程编程模型来对Multi2sim‑2.1进行并行化,即分别用一个Pthread线程实现对每个上下文的仿真过程,针对功能仿真的实现过程,在确定并行功能仿真器结构时(其中主要是Pthread线程创建的位置)采取了分治的策略,即根据多道和多线程负载仿真过程的差别,分别制定不同的线程创建方案并予以实现,在调试和优化后最终将二者合并形成并行功能仿真器。对于多道负载,上下文是在多道负载所包含的各应用程序加载到客户内存时创建的,因此当加载完成后就可以同时创建与上下文数量相一致的多个线程,并统一开始仿真过程;而对于多线程负载,子上下文是在主上下文执行上下文创建原语时动态生成的,因此与之相绑定的线程也需等到这一时刻才能创建,为此在仿真器中实现上下文创建原语的系统调用处增加了线程创建过程。
面向多道负载的并行功能仿真器进行线程创建时可以按类似以下的代码来实现:
main()
{
//create POSIX threads according to ctx
for(current_ctx=ke‑>contx_list;current_ctx‑>contx_next;current_ctx=current_
ctx‑>contx_next)
{
pth read_create(&pid[i++],NULL,ke_execute,(void*)cu rrent_ctx);
}
ke_execute((void*)current_ctx);
for(context_number=0;context_number<ctxnum1;context_number++)
{
pthread_join(pid[context_number],NULL);
}
}
ke_execute(void*args)
{
struct ctx_t*ctx=(stru ct ctx_t*)args;
while(psim_cycle<max_cycles){
if(!ctx_get_status(ctx,ctx_running))
break;
/*Run an instruction from a dedicated context*/
ke_run((void*)ctx);
psim_cycle++;
}
}
面向多线程负载的并行功能仿真器进行线程创建时可以按类似以下的代码来实现:
void syscall_do()
{
case syscall_code_clone:
{
pid_array_index++;
if(pid_array_index==cores_num‑1)
{
struct ctx_t*current_ctx=NULL;
for(current_ctx=isa_ctx‑>contx_prev;current_ctx;
current_ctx=current_ctx‑>contx_prev){
pthread_t sub_pid;
memcpy(current_ctx‑>mem,isa_ctx‑>mem,sizeof(struct mem_t));
pthread_create(&sub_pid,NULL,ke_execute,(void*)current_ctx);
pid_array[pid_a rray_index ]=sub_pid;
}
}
}
}
当完成线程创建过程后,并行仿真器的执行模型如图1所示。此时系统中将包含与上下文数量相一致的多个线程,每个线程被操作系统调度到不同的宿主处理器核上,各线程并发执行完成对相应上下文的功能仿真。
下面综合在本实例的实现过程中具体涉及到了共享变量的保护与同步、实现线程局部变量存储和消除假共享机制。
保护对共享资源的并发访问是影响并行程序正确性和性能的重要因素,而锁则是将共享资源的访问串行化的常用技术之一。在Multi2sim‑2.1中,存在着大量诸如上下文状态链表,哈希表和客户内存等共享资源,在并行仿真器中,当核线程对这些资源进行访问的时候,使用操作系统级的互斥锁来对其进行保护,同时合理地安排锁的粒度和数量,以最大化并行仿真器的加速比。
另外,在多线程负载的多个上下文之间往往存在着大量的同步原语(如锁、路障等),当串行仿真器执行某个上下文的同步原语时,只需要在相应的系统调用中将该上下文插入到适当的上下文状态链表中,如当某个上下文不能获得所请求的锁时,则将其插入到挂起链表中。然而,对于并行仿真器,在将上下文插入到适当的状态链表的同时,还要将其所在的操作系统线程切换到合理的状态,为此在仿真器中实现同步原语的系统调用函数中增加了与其功能对应的操作系统级同步操作以达到上述目的。
和许多串行程序一样,串行多核仿真器Multi2sim‑2.1的一个显著特点就是使用全局变量来控制模拟器的执行状态。例如,为了使用统一的接口函数执行不同上下文的指令,Multi2sim‑2.1引入了isa_ctx,isa_regs,isa_mem等一系列全局变量。当实现并行仿真器时,大部分类似的变量在每个上下文都需要有一个单独的副本,然而这样做所面临的问题就是要准确地识别出这些变量,将之扩展成数组(向量)形式,并且通过上下文id来引用各自的变量。显然这种实现方式的工作量较大,并且给并行仿真器代码的书写和调试带来一定的麻烦,为此使用线程局部存储(Thread Local Storage:TLS)的语言结构来解决这类变量并行化过程中所面临的困境。
在gcc中,TLS可以通过在全局变量或者静态局部变量的声明前使用__thread关键字来实现,这意味着在线程创建时这些变量会自动生成一个复本。通过这种方式可以手工地将表示单个线程核属性的变量和被多个线程所共享的变量区分开来,并且提高并行仿真器的性能。
在串行多核仿真器中,许多数据结构都是以数组的方式组织的,每个处理器核对应一个数组元素。尽管从代码编写的角度看,这样做比较方便,并且不会引发任何问题,但是当开发并行仿真器时,多个线程对各自的数组元素进行引用会导致假共享问题。为了缓解这一问题,使用填充(Padding)的方法来确保被不同宿主处理器核访问的数据被分配到不同的高速缓存行中。
由于Multi2sim‑2.1完全是以串行程序的思维设计和实现的,因此存在着大量上述类型的变量,在并行化过程中这些变量对并行仿真器的性能影响很大,为此花费了大量时间来发掘这样的变量,最终使仿真器的速度达到令人满意的效果。
测试过程采用多道和多线程负载评测并行功能仿真器的性能,多道负载是由SPEC2006中的相关应用组合而成的。表1列出了测试过程中所使用的全部多道负载组合。多线程测试程序来自Splash2。在本测试过程中所用到的几个测试负载为FFT,LU(c),RADIX和LU(n)。
表1多道负载组合
![]()
图2、图3给出了该仿真器运行多道测试负载时所获得的加速比,从图中可以看出,目标系统拥有2核时,所能达到的最大的加速比可达到1.914,而获得的最小的加速比为1.478;目标系统拥有4核时,所能达到的最大加速比可达到3.814,而获得的最小加速比为3.366;目标系统拥有8核的时候,所能获得的最大加速比可达到7.618,而获得的最小加速比为7.143,目标系统拥有16核时,所能达到的最大加速比可达到15.827,而所获的最小加速比为15.321。从图3还可以看出,在2核、4核、8核以及16核的时候,平均加速比分别为1.748、3.644、7.372和15.628。
图4、图5中给出了该仿真器运行多线程测试负载时所获得的加速比,从图中可以看出,目标系统拥有2核时,所能达到的最大的加速比为1.819,而获得的最小的加速比只有1.378;目标系统拥有4核时,所能达到的最大加速比为3.131,而获得的最小加速比只有1.838;目标系统拥有8核的时候,所能获得的最大加速比为4.852,而获得的最小加速比只有2.434,目标系统拥有16核时,所能达到的最大加速比为6.372,而所获的最小加速比只有4.821。从图5还可以看出,在2核、4核、8核以及16核的时候,平均加速比分别为1.692、2.760、3.833和5.292。
在运行多线程负载时,并行功能仿真器所获得的加速比没有运行多道负载时所获得的加速比高,这种现象主要由线程间的通信所引起。在多道负载中,线程间几乎不通信,因此运行多道负载的时候可以获得较为理想的加速比。但是,在多线程负载的不同线程之间,存在大量的线程间通信。随着核数的增加,这样的开销将非常大,从而导致并行功能仿真器整体性能的下降。
上述实例只为说明本发明的技术构思及特点,其目的在于让熟悉此项技术的人是能够了解本发明的内容并据以实施,并不能以此限制本发明的保护范围。凡根据本发明精神实质所做的等效变换或修饰,都应涵盖在本发明的保护范围之内。