一种程序源码的编译优化方法及相关产品与流程

文档序号:33152737发布日期:2023-02-03 23:10阅读:27来源:国知局
1.本技术涉及缓存
技术领域
:,尤其涉及一种程序源码的编译优化方法及相关产品。
背景技术
::2.随着缓存技术的快速发展,中央处理器(centerprocessingunit,cpu)访存对象(包括数据和指令)的速度也越来越快。其中,影响cpu访存对象的速度的一个关键因素是:缓存中是否存储有即将被cpu访问的对象。为此,需要对缓存进行优化,使得cpu可以更多地从缓存中读取待访问的对象,减少cpu访问内存的次数,从而提高cpu访存对象的速度。3.但是,当前缓存优化方法均存在优化成本高、但准确性和及时性低的问题,即利用这些缓存优化方法需要耗费较高的成本才能实现对缓存的优化,并且优化后的缓存中还可能包括较多的冗余对象和访问频率低的对象,或者cpu访存对象之前,该对象并未及时从内存搬运至缓存。4.因此,如何在提高缓存优化效果的同时减少缓存优化的优化成本是当前缓存
技术领域
:中一个急需解决的问题。技术实现要素:5.本技术提供了一种程序源码的编译优化方法、装置、设备及计算机可读存储介质,能够提高缓存优化的准确性和及时性。6.第一方面,本技术提供了一种程序源码的编译优化方法,该方法包括:运行第一可执行文件,采集硬件缓存事件,其中,第一可执行文件包括可执行程序和调试信息,可执行程序是对程序源码进行编译得到的,调试信息包括程序源码和可执行程序中的可执行指令之间的对应关系。然后,根据硬件缓存事件和调试信息,获得第一配置信息,第一配置信息包括上述程序源码的标识和该标识对应的缓存缺失次数。最后,根据第一配置信息对上述程序源码进行编译,得到第二可执行文件。7.实施第一方面所描述的方法,可以得到第二可执行文件,当cpu执行第二可执行文件时,可以达到对缓存进行优化的目的。并且,该方法是通过采集硬件缓存事件来确定程序源码对应的缓存缺失次数,之后,再结合程序源码对应的缓存缺失次数来对程序源码进行编译,使得编译得到的第二可执行文件能够更准确且及时的告知cpu如何优化缓存,不仅能够提高缓存优化的准确性和及时性,还可以节省缓存优化的成本。8.在一种可能的实现方式中,上述根据硬件缓存事件和调试信息,获得第一配置信息,包括:解析硬件缓存事件,获得可执行指令对应的缓存缺失次数,然后根据可执行指令对应的缓存缺失次数和调试信息,确定可执行指令关联的源码对应的缓存缺失次数,从而得到第一配置信息。9.由于cpu能够执行的是可执行指令,因此,可以确定cpu在执行哪些可执行指令时出现缓存缺失,从而确定可执行指令对应的缓存缺失次数,又由于可执行指令是通过对程序源码进行编译得到的,因此,通过可执行指令对应的缓存缺失次数可以确定程序源码对应的缓存次数。也就是说,通过上述实现方式可以更加简便且准确地确定程序源码对应的缓存缺失次数,以此来指导程序源码的编译,使得程序源码的编译效果更好。10.在一种可能的实现方式中,上述根据第一配置信息对程序源码进行编译,得到第二可执行文件,包括:解析第一配置信息,确定程序源码中满足第一条件的源码,其中,第一条件包括:源码的缓存缺失次数大于第一阈值,且源码包括访存对象。然后,计算满足第一条件的源码的预取距离,预取距离表示将访存对象从内存搬运至缓存的提前量。最后,根据预取距离生成预取指令。11.上述实现方式中,通过选取满足第一条件的源码,并对满足第一条件的源码执行数据预取可以减轻cpu的工作量,并且在总体上还能够提高缓存的优化效果。12.在一种可能的实现方式中,上述计算满足第一条件的源码的预取距离,包括:获取第一循环的控制流图(controlflowgraph,cfg),第一循环是包括上述满足第一条件的源码的最内层循环,第一循环的cfg包括多个基本块(basicblock,bb)和多条有向边,多条有向边用于指示所述多个bb之间的执行顺序,然后,确定所述每条有向边的执行概率;根据每条有向边的执行概率计算第一循环的单次循环时间,然后,根据第一循环的单次循环时间计算上述满足第一条件的源码的预取距离。13.上述实现方式中,考虑到了cpu执行循环程序,尤其是循环中嵌套的最内层循环的程序时,最有可能出现缓存缺失事件。因此,通过计算最内层循环的单次循环时间可以更加准确地确定预取距离,从而提高缓存优化的及时性和通用性。而且,通过确定每条有向边的执行概率,从而计算第一循环的单次循环时间,可以减少第一循环中的执行概率低的bb对第一循环的单次循环时间的影响,从而提高计算出的第一循环的单次循环时间的准确性。14.在一种可能的实现方式中,上述获取第一循环的cfg,包括:解析第一配置信息,确定程序源码中满足第二条件的函数,其中,第二条件为函数的缓存缺失次数大于第二阈值,函数的缓存缺失次数为函数包括的源码的缓存缺失次数之和。然后,确定满足第二条件的函数中的第一循环,第一循环为满足第二条件的函数中的最内层循环,且第一循环迭代的执行概率大于第三阈值,之后,构建第一循环的cfg。15.上述实现方式中,通过确定满足第二条件的函数进一步确定第一循环,如此可以提高确定第一循环的效率,从而节省对程序源码进行编译的时间,减少对程序源码进行编译的成本。16.在一种可能的实现方式中,上述根据每条有向边的执行概率计算第一循环的单次循环时间,包括:确定与第一循环的循环层无关的bb和有向边,然后对上述无关的bb和有向边进行裁剪,得到第二循环。之后,根据每条有向边的执行概率计算第二循环中的各个bb的执行概率,得到第一循环的单次循环时间,第一循环的单次循环时间为各个bb的执行概率与各个bb的执行时间的乘积之和。17.上述实现方式中,通过对第一循环中与循环层无关的bb和有向边进行裁剪,得到第二循环,然后根据第二循环计算第一循环的单次循环时间,如此可以提高计算出的第一循环的单次循环时间的准确性。18.在一种可能的实现方式中,在上述根据第一配置信息对所述程序源码进行编译,得到第二可执行文件之前,上述方法还包括:获取程序源码中的多个结构体,以及多个结构体中的成员。上述根据第一配置信息对程序源码进行编译,得到第二可执行文件,包括:解析第一配置信息,确定多个结构体中满足第三条件的结构体,第三条件包括:结构体中的各个成员在使用上不存在顺序依赖,且结构体的缓存缺失次数大于第四阈值;对上述满足第三条件的结构体中的成员的排序进行调整,得到新的结构体。之后,利用新的结构体代替上述满足第三条件的结构体。19.实施上述实现方式,还能够对程序源码中的结构体进行优化,从而提高缓存的使用率。并且,该方式是通过采集硬件缓存事件来确定程序源码中结构体的缓存缺失次数,从而提高对结构体成员重排的准确性。20.在一种可能的实现方式中,上述每个结构体包括所述程序源码中的源码,上述解析所述第一配置信息,确定满足第三条件的结构体,包括:解析第一配置信息,确定程序源码的标识以及该标识对应的缓存缺失次数,然后根据程序源码的标识以及该标识对应的缓存缺失次数,获得每个结构体的缓存缺失次数,从而确定上述满足第三条件的结构体。如此,可以节省对程序源码进行结构体成员重排的时间,减少对程序源码进行结构体成员重排的成本。另外,通过第三条件进行结构体的筛选,还能够提高对程序源码进行结构体成员重排的准确性。21.在一种可能的实现方式中,上述对满足第三条件的结构体中的成员的排序进行调整,包括:获取满足第三条件的结构体中多个成员的缓存缺失次数,然后根据多个成员的缓存缺失次数的大小对上述多个成员的排序进行调整。如此,可以提供缓存的使用率。22.在一种可能的实现方式中,上述根据多个成员的缓存缺失次数的大小对多个成员的排序进行调整,包括:获取多个成员中每个成员的大小,然后根据每个成员的大小以及每个成员的缓存缺失次数,对上述多个成员的排序进行调整。如此,可以进一步提高缓存的使用率。23.第二方面,本技术提供了一种程序源码的编译优化装置,该装置包括运行单元、事件采集单元、解析单元以及编译单元。其中,运行单元用于运行第一可执行文件,其中,第一可执行文件包括可执行程序和调试信息,可执行程序是对程序源码进行编译得到的,调试信息包括程序源码和可执行程序中的可执行指令之间的对应关系。事件采集单元用于采集硬件缓存事件。解析单元用于根据硬件缓存事件和调试信息,获得第一配置信息,第一配置信息包括程序源码的标识和标识对应的缓存缺失次数;编译单元用于根据第一配置信息对程序源码进行编译,得到第二可执行文件。24.在一种可能的实现方式中,上述解析单元具体用于:解析硬件缓存事件,获得可执行指令对应的缓存缺失次数,然后根据可执行指令对应的缓存缺失次数和调试信息,确定可执行指令关联的源码对应的缓存缺失次数,从而得到第一配置信息。25.在一种可能的实现方式中,上述编译单元具体用于:解析第一配置信息,确定程序源码中满足第一条件的源码,其中,第一条件包括:源码的缓存缺失次数大于第一阈值,且源码包括访存对象。然后,计算满足第一条件的源码的预取距离,预取距离表示将访存对象从内存搬运至缓存的提前量。最后,根据预取距离生成预取指令。26.在一种可能的实现方式中,上述编译单元具体用于:获取第一循环的cfg,第一循环是包括上述满足第一条件的源码的最内层循环,第一循环的cfg包括多个bb和多条有向边,多条有向边用于指示所述多个bb之间的执行顺序,然后,确定所述每条有向边的执行概率;根据每条有向边的执行概率计算第一循环的单次循环时间,然后,根据第一循环的单次循环时间计算上述满足第一条件的源码的预取距离。27.在一种可能的实现方式中,上述编译单元具体用于:解析第一配置信息,确定程序源码中满足第二条件的函数,其中,第二条件为函数的缓存缺失次数大于第二阈值,函数的缓存缺失次数为函数包括的源码的缓存缺失次数之和。然后,确定满足第二条件的函数中的第一循环,第一循环为满足第二条件的函数中的最内层循环,且第一循环迭代的执行概率大于第三阈值,之后,构建第一循环的cfg。28.在一种可能的实现方式中,上述编译单元具体用于:确定与第一循环的循环层无关的bb和有向边,然后对上述无关的bb和有向边进行裁剪,得到第二循环。之后,根据每条有向边的执行概率计算第二循环中的各个bb的执行概率,得到第一循环的单次循环时间,第一循环的单次循环时间为各个bb的执行概率与各个bb的执行时间的乘积之和。29.在一种可能的实现方式中,上述编译单元还用于:获取程序源码中的多个结构体,以及多个结构体中的成员。上述编译单元还用于:解析第一配置信息,确定多个结构体中满足第三条件的结构体,第三条件包括:结构体中的各个成员在使用上不存在顺序依赖,且结构体的缓存缺失次数大于第四阈值;对上述满足第三条件的结构体中的成员的排序进行调整,得到新的结构体。之后,利用新的结构体代替上述满足第三条件的结构体。30.在一种可能的实现方式中,上述每个结构体包括所述程序源码中的源码,上述编译单元具体用于:解析第一配置信息,确定程序源码的标识以及该标识对应的缓存缺失次数,然后根据程序源码的标识以及该标识对应的缓存缺失次数,获得上述每个结构体的缓存缺失次数,从而确定上述满足第三条件的结构体。31.在一种可能的实现方式中,上述编译单元具体用于:获取满足第三条件的结构体中多个成员的缓存缺失次数,然后根据多个成员的缓存缺失次数的大小对上述多个成员的排序进行调整。32.在一种可能的实现方式中,上述编译单元具体用于:获取多个成员中每个成员的大小,然后根据每个成员的大小以及每个成员的缓存缺失次数,对上述多个成员的排序进行调整。33.第三方面,本技术提供了一种计算设备,该计算设备包括处理器和存储器,存储器存储计算机指令,处理器执行上述计算机指令,以使上述计算设备执行第一方面或第一方面任意可能的实现方式所提供的方法。34.第四方面,本技术提供了一种计算机可读存储介质,该计算机可读存储介质存储有计算机指令,当上述计算机指令被计算设备执行时,计算设备执行前述第一方面或第一方面任意可能的实现方式所提供的方法。附图说明35.图1是本技术涉及的一种内存访问过程的示意图;36.图2是本技术提供的一种编译优化装置的结构示意图;37.图3是本技术提供的一种程序源码的编译优化方法的流程示意图;38.图4是本技术提供的一种对程序源码执行数据预取的编译操作的流程示意图;39.图5是本技术提供的一种循环1的cfg;40.图6是本技术提供的一种对循环1进行裁剪后的循环的cfg;41.图7是本技术提供的一种对程序源码执行结构体成员重排的编译操作的流程示意图;42.图8是本技术提供的一种第二结构体的结构示意图;43.图9是本技术提供的一种第二结构体的存储排布示意图;44.图10是本技术提供的一种第三结构体的结构示意图;45.图11是本技术提供的一种第三结构体的存储排布示意图;46.图12是本技术提供的另一种第三结构体的结构示意图;47.图13是本技术提供的另一种第三结构体的存储排布示意图;48.图14是本技术提供的一种计算设备的结构示意图。具体实施方式49.为了便于理解本技术提供的技术方案,在具体描述本技术提供的技术方案之前,首先介绍本技术涉及的一些术语。50.缓存(cache)是位于cpu与内存之间进行高速数据交换的临时存储器,它的容量比内存小,但对象(包括数据和指令)存取的速度比内存快。cpu和内存之间通常会设置多级缓存,如图1所示的一级缓存(l1cache)、二级缓存(l2cache)和三级缓存(l3cache)。根据缓存的对象,一级缓存又可以分为数据缓存(datacache)和指令缓存(instructioncache),顾名思义,数据缓存用于缓存数据,指令缓存用于缓存指令。那么,cpu对内存的访问就需要经过上述多级缓存。以cpu访问的对象是数据为例,cpu先访问一级缓存(具体为数据缓存),如果待访问的数据在一级缓存中,则从一级缓存中读取该数据。如果待访问的数据未在一级缓存中,则访问二级缓存。如果待访问的数据在二级缓存中,则从二级缓存中读取该数据。如果待访问的数据未在二级缓存中,则访问三级缓存。如果待访问的数据在三级缓存中,则从三级缓存中读取该数据。如果待访问的数据未在三级缓存中,则cpu从内存中访问该数据。应理解,cpu访问指令的过程与上述数据访问的过程类似,因此这里不再展开叙述。51.上述过程存在两种情况:其一,cpu访问的对象在缓存中,即cpu可以从一级缓存、二级缓存或三级缓存中读取到待访问的对象,这一情况称为缓存命中(cachehit)。其二,如果cpu访问的对象未在缓存中,即cpu未能在一级缓存、二级缓存和三级缓存中读取到待访问的对象,这一情况称为缓存缺失(cachemiss)。52.由于内存的访问具有延迟性,因此,当cpu访问的对象未在缓存中时,cpu需要等待较长的时间才能访问到该数据或指令,从而导致程序在执行过程中出现瓶颈。为此,出现了多种缓存优化方法,包括但不限于以下几种:53.1、数据预取54.数据预取是指cpu在访问内存中的数据之前,提前将待访问的数据从内存传输至缓存中。数据预取的方式主要有硬件预取和软件预取。其中,硬件预取是指cpu根据内存访问的历史信息,将未来可能访问的数据提前传输至缓存中。软件预取是指编译器在编译程序源码的过程中,向程序中插入预取指令,那么在程序运行时就可以通过预取指令将可能访问到的数据提前传输至缓存中。55.值得注意的一点是,有效的数据预取机制是要在cpu使用内存数据之前刚好将其从内存传输至缓存中,使得cpu可以从缓存中访问到该数据,从而减少内存访问的延迟。也就是说,数据的预取不能过早也不能过晚,只有在特定的时间窗口中及时地进行将数据从内存搬运至缓存,才能最大限度的减少缓存移出和缓存污染,避免数据预取的开销大于数据预取的收益。56.2、结构体优化57.结构体(struct)是一种数据结构,例如,整型、浮点等。结构体包括一个或多个结构体成员(member),不同的结构体成员可以属于不同的类型。例如,结构体s包括整型数据a,字符型变量b和双精度变量c,其中,数据a、变量b和变量c均是结构体s中的结构体成员。58.结构体优化的方式主要有结构体成员重排和结构体拆分。其中,结构体成员重排是指通过调整结构体中成员的顺序,使得结构体中被频繁访问的成员尽可能位于同一个缓存块(cacheline)中,从而提高缓存块的利用率,达到缓存优化的目的。其中,缓存块是组成缓存的单元块,每个缓存块包括一个或多个连续的内存存储单元。结构体拆分是指根据结构体中成员的访问频率将一个结构体拆分为多个结构体,从而提高缓存块的利用率,达到缓存优化的目的。59.3、函数重排60.函数重排是指通过将函数内或不同函数之间的代码进行重排,使得调用关系紧密的函数相邻排列,从而提高缓存块的利用率,减少因指令的缓存缺失导致的指令搬运等待,提高程序的运行效率。61.不难看出,上述缓存优化方法都涉及到这样的问题:如何准确地确定内存中的哪些对象(数据或指令)可能是即将被cpu频繁访问的?在确定即将被cpu频繁访问的对象后,如何根据这些对象计算出合适的优化策略,以对缓存进行优化。目前,主要基于插桩技术来实现缓存的优化,即通过对cpu访存对象的操作指令(例如,load操作数、store操作数)进行插桩跟踪,确定cpu需要从内存中读取的对象,从而在编译阶段对这些对象进行相应的优化操作,例如,数据预取操作。但是,该方法需要通过软件插桩才能实现,这会增加缓存优化的开销,而且该方法还存在准确性和及时性较低的问题,即利用上述方法对缓存进行优化后,cpu访存对象之前,该对象并未及时从内存搬运至缓存。62.为了解决上述问题,本技术提供了一种程序源码的编译优化方法,利用该方法对程序源码进行编译后可以得到对应的可执行文件,当cpu执行该可执行文件时,不仅能够实现对缓存的优化,还能够减少缓存优化的开销,提高缓存优化的准确性和及时性。63.本技术提供的程序源码的编译方法可以由编译优化装置执行,图2示出了编译优化装置的结构示意图。如图2所示,编译优化装置100包括运行单元110、事件采集单元120、解析单元130以及编译单元140。下面对上述各个单元进行简要介绍。64.(1)运行单元11065.运行单元110用于获取第一可执行文件,并运行第一可执行文件。其中,第一可执行文件包括可执行程序和调试信息,可执行程序是对程序源码进行编译得到的,调试信息包括程序源码和可执行程序中的可执行指令之间的对应关系。66.(2)事件采集单元12067.事件采集单元120用于在运行第一可执行文件时采集硬件缓存事件。硬件缓存事件是指cpu访问缓存时的状态数据。应理解,由于cpu访问缓存时可能出现两种情况,一种是缓存命中,一种是缓存缺失,因此上述硬件缓存事件可以包括缓存命中事件和缓存缺失事件。其中,缓存命中事件是指cpu访问缓存时,从缓存中获取访问对象的事件;缓存缺失事件是指cpu访问缓存时,未从缓存中获取访问对象的事件。68.本技术实施例中,考虑到当前的cpu中普遍存在性能监视单元(performancemonitorunit,pmu),pmu用于对cpu中多种硬件的执行状态事件(即硬件事件)进行监控,并且,cpu上的硬件事件包括上述硬件缓存事件。因此,事件采集单元120可以包括pmu121和性能采集工具122。其中,pmu121用于对cpu上的硬件事件进行监控,性能采集工具122用于对pmu121进行硬件缓存事件的采样和记录。可选的,性能采集工具122可以采用linux提供的性能采集工具(例如:perf、oprofile)、或者windows提供的性能采集工具(例如:perfmon、vtune)等,此处不作具体限定。69.可选的,通过对pmu121进行配置,使得pmu121仅对cpu上的硬件缓存事件进行监控。这样,可以减少pmu121的工作。70.事件采集单元120还用于将采集到的硬件缓存事件发送至解析单元130。71.(3)解析单元13072.解析单元130用于获取第一可执行文件,以及接收事件采集模块120发送的硬件缓存事件。解析单元130还用于对第一可执行文件进行解析,获得调试信息,然后根据调试信息和硬件缓存事件,获得第一配置信息。其中,第一配置信息包括程序源码的标识和该标识对应的缓存缺失次数。解析单元130还用于将第一配置信息发送至编译单元140。73.(4)编译单元14074.编译单元140用于获取程序源码,以及接收解析单元130发送的第一配置信息,并根据第一配置信息对程序源码进行编译,得到第二可执行文件。75.在一具体的实施例中,编译单元140包括数据预取模块141。其中,数据预取模块141用于根据第一配置信息对程序源码进行数据预取的编译操作。具体地,数据预取模块141解析第一配置信息,确定程序源码中满足条件a的源码,其中,条件a包括:源码的缓存缺失次数大于阈值a,且源码包括cpu的访存对象。然后,数据预取模块141计算上述满足条件a的源码的预取距离,并根据该预取距离生成预取指令,以使得cpu在执行源码对应的可执行指令时能够从缓存中读取到所需的访存对象。76.在一具体的实施例中,编译单元140还包括结构体成员重排模块142。结构体成员重排模块142用于根据第一配置信息对程序源码执行结构体成员重排的编译操作。具体地,结构体成员重排模块142获取程序源码中的所有结构体,以及每个结构体中的成员,然后通过解析上述第一配置信息,确定满足条件b的结构体,其中,条件b包括:结构体中的各个成员在使用上不存在顺序依赖,且结构体的缓存缺失次数大于阈值b,结构体中的各个成员在使用上不存在顺序依赖是指:不通过结构体指针和偏移量来取结构体中的成员。之后,对上述满足条件b的结构体中的成员的排序进行调整,得到新的结构体,并利用新的结构体代替原结构体(即上述满足条件b的结构体)。77.可选的,编译单元140还可以包括结构体拆分模块143或函数重排模块144。其中,结构体拆分模块143用于根据第一配置信息对程序源码中的频繁出现缓存缺失事件的结构体进行拆分。函数重排模块144用于根据第一配置信息对程序源码中的频繁出现缓存缺失事件的函数进行函数重排的编译操作。78.下面结合图3,对上述编译优化装置100对程序源码进行编译优化的具体过程进行更加详细地描述。如图3所示,图3示出了本技术提供的一种程序源码的编译优化方法的流程示意图,该方法包括但不限于如下步骤:79.s101:获取第一可执行文件。80.其中,第一可执行文件是通过对程序源码进行编译后得到的、cpu可以加载并执行的文件。程序源码是指未编译的、按照一定的程序设计语言(例如,c语言、c++语言)规范书写的文本文件,是一系列人类可读的计算机语言指令。可选的,第一可执行文件可以是二进制可执行文件(binaryexecutable),可执行指令可以是汇编指令、机器指令等。81.本技术实施例中,第一可执行文件包括可执行程序和调试信息,可执行程序是指可以由cpu加载并执行的程序,可执行程序包括可执行指令,可执行指令是指可以由cpu加载并执行的指令。调试信息是上述编译器对程序源码进行编译的过程中生成的,用于表示程序源码与可执行程序之间的关系。调试信息包括程序源码和可执行程序中的可执行指令之间的对应关系。82.在实际应用中,考虑到人们书写程序源码的习惯,程序源码可以看作是由多行源码组成的,并且在编译后一条可执行指令通常会对应一行或多行源码,那么,上述调试信息包括的程序源码和可执行程序中的可执行指令之间的对应关系,具体可以是每行源码的标识与每条可执行指令的标识之间的对应关系。其中,每行源码的标识可以是该行源码的编号,每条可执行指令的标识可以是该条可执行指令的编号。可选的,每行源码的标识还可以是每行源码的存储地址,每条可执行指令的标识还可以是该条可执行指令的存储地址,83.s102:运行第一可执行文件,采集硬件缓存事件。84.在一些实施例中,编译优化装置100在运行第一可执行文件的过程中,对出现的硬件事件进行监控,并对硬件事件中的硬件缓存事件进行采样和记录。其中,硬件事件、硬件缓存事件的具体叙述请参见前述内容中关于事件采集单元120的相关介绍,为了简便此处不再进行叙述。85.应理解,由于硬件事件不仅包括硬件缓存事件,因此,在另一些实施例中,编译优化装置100在运行第一可执行文件的过程中,可以仅对cpu上的硬件缓存事件进行监控,并对监控到的硬件缓存事件进行采样和记录。86.s103:根据硬件缓存事件和调试信息,获得第一配置信息。87.其中,第一配置信息包括程序源码的标识和该标识对应的缓存缺失次数。程序源码的标识可以是程序源码中所有源码的标识(例如,程序源码中每行源码的标识),也可以是程序源码中部分源码的标识,此处不作具体限定。88.在一具体的实施例中,编译优化装置100根据硬件缓存事件和调试信息,获得第一配置信息,包括:对第一可执行文件进行解析,获得调试信息。然后,解析硬件缓存事件,获得可执行程序中的可执行指令对应的缓存缺失次数,其中,可执行指令对应的缓存缺失次数是指cpu执行该可执行指令时,出现缓存缺失事件的次数。之后,根据可执行指令对应的缓存缺失此处和上述调试信息,确定可执行指令关联的源码对应的缓存缺失次数,从而得到上述第一配置信息。89.需要说明的一点是,第一配置信息用于指示编译器对程序源码进行编译,因此,编译优化装置100在得到第一配置信息之后,还需将第一配置信息存储为编译器能够解析的格式的文件。例如,采用的编译器为gcc编译器,gcc编译器能够读取并解析.gcov格式的文件,那么,编译优化装置100得到第一配置信息后会将第一配置信息存储为.gcov格式的文件,以便于gcc编译器能够读取第一配置信息,并解析第一配置信息。90.s104:根据第一配置信息对程序源码进行编译,得到第二可执行文件。91.其中,与第一可执行文件类似的,第二可执行文件也是cpu可以加载并运行的文件,但第二可执行文件与第一可执行文件不同,相较于第一可执行文件,cpu在执行第二可执行文件时,缓存的优化效果更好,使得访问内存所消耗的时间更少,程序运行效率更高。92.本技术实施例中,编译优化装置100获得第一配置信息后,可以通过以下任意一种方式根据第一配置信息对程序源码进行编译:93.方式1、编译优化装置100根据第一配置信息对程序源码执行数据预取的编译操作。94.具体地,编译优化装置100解析第一配置信息,确定程序源码中满足条件a的源码。然后,计算上述满足条件a的源码的预取距离,预取距离表示将cpu的访存对象从内存搬运至缓存的提前量。最后,根据预取距离生成预取指令,使得cpu在执行上述满足条件a的源码对应的可执行指令时,能够从缓存中读取到对应的访存对象。95.在一具体的实施例中,编译优化装置100确定程序源码中满足条件a的源码的方式多种多样,例如:96.①、解析第一配置信息,获得程序源码的标识及标识对应的缓存缺失次数,从而得到程序源码中多个函数的缓存缺失次数,其中,每个函数的缓存缺失次数等于该函数包括的源码对应的缓存缺失次数之和。然后,按照缓存缺失次数的大小对上述多个函数进行降序排序,筛选出满足条件c的至少一个函数(为了简便,下文将上述满足条件c的函数简称为第一函数),其中,条件c包括以下至少一个:函数的缓存缺失次数大于阈值c、函数的排序小于阈值d。然后,确定每个第一函数中涉及cpu访存对象的源码,并根据上述程序源码的标识及标识对应的缓存缺失次数,获得上述涉及cpu访存对象的源码对应的缓存缺失次数,然后按照缓存缺失次数的大小对上述涉及cpu访存对象的源码进行降序排序,从而确定上述满足条件a的源码,此处的条件a包括:源码的缓存缺失次数大于阈值a、源码的排序小于阈值e以及源码包括cpu的访存对象。97.应理解,一个函数中可能包括:涉及cpu访存对象的源码,涉及算术运算的源码、涉及逻辑运算的源码、涉及判定和控制的源码等。而只有涉及访存对象的那一部分源码才会出现缓存缺失事件,因此,为了更加准确地执行数据预取操作,编译优化装置100筛选出第一函数后还确定了第一函数中涉及cpu访存对象的源码,从而筛选出满足条件a的源码。98.需要说明的一点是,在实际应用中,程序源码中的多个函数可能均不满足上述条件c,或者第一函数中的源码可能均不满足方式①中的条件a,在这种情况下,编译优化装置100将不对程序源码执行数据预取的编译优化操作。99.②、解析第一配置信息,获得程序源码的标识及标识对应的缓存缺失次数,然后确定程序源码中涉及cpu访存对象的源码,以及这些源码对应的缓存缺失次数。然后,按照缓存缺失次数的大小对上述涉及cpu访存对象的源码进行降序排序,从而确定上述满足条件a的至少一个源码,此处的条件a包括:源码的缓存缺失次数大于阈值a、源码的排序小于阈值f以及源码包括cpu访存对象。100.需要说明的一点是,在实际应用中,程序源码中的源码可能均不满足方式②中的条件a,在这种情况下,编译优化装置100将不对程序源码执行数据预取的编译优化操作。101.在一具体的实施例中,考虑到cpu执行循环程序,尤其是循环中嵌套的最内层循环的程序时,最有可能出现缓存缺失事件。那么,编译优化装置100计算上述满足条件a的源码的预取距离,包括以下步骤:获取第一循环的cfg,其中,第一循环是包括上述满足条件a的源码的最内层循环,第一循环的cfg表示cpu在执行第一循环的过程中会遍历到的所有路径,第一循环的cfg包括多个bb和多条有向边,多条有向边用于指示多个bb之间的执行顺序。然后,确定每条有向边的执行概率,并根据每条有向边的执行概率计算第一循环的单次循环时间。之后,根据第一循环的单次循环时间计算上述满足条件a的源码的预取距离。该步骤的具体过程请参见后文的s201-s206。102.方式2、编译优化装置100根据第一配置信息对程序源码执行结构体成员重排的编译操作。103.在一具体的实施例中,编译优化装置100对程序源码执行结构体成员重排的编译操作之前,还执行以下步骤:获取程序源码中的多个结构体,以及多个结构体中的成员,之后,记录上述多个结构体中每个结构体的类型、每个结构体的变量以及每个结构体中的成员。104.在一具体的实施例中,编译优化装置100根据第一配置信息对程序源码执行结构体成员重排的编译操作,包括:解析第一配置信息,确定程序源码的标识以及该标识对应的缓存缺失次数,并根据程序源码的标识以及该标识对应的缓存缺失次数,获得上述每个结构体的缓存缺失次数,从而确定满足条件b的结构体,其中,条件b包括:结构体中的各个成员在使用上不存在顺序依赖,且结构体的缓存缺失次数大于阈值b,结构体中的各个成员在使用上不存在顺序依赖是指:不通过结构体指针和偏移量来取结构体中的成员。之后,对上述满足条件b的结构体中的成员的排序进行调整,得到新的结构体,最后,利用新的结构体代替上述满足条件b的结构体。该步骤的具体过程请参见后文的s301-s306。105.应理解,编译优化装置100还可以根据第一配置信息对程序源码执行结构体拆分的编译操作、或函数重排的编译操作等,其具体构思与上述方式1和方式2的构思类似,为了简便,本技术不展开叙述。106.实施上述程序源码的编译方法,可以得到第二执行文件,当cpu执行第二可执行文件时,可以达到对缓存进行优化的目的。并且,根据前文的描述可知,该方法是通过采集硬件缓存事件来确定程序源码对应的缓存缺失次数,之后,再结合程序源码对应的缓存缺失次数来对程序源码进行编译,使得编译得到的第二可执行文件能够更准确且及时的告知cpu如何优化缓存。因此,本技术提供的程序源码的编译方法不仅能够提高缓存优化的准确性和及时性,还可以节省缓存优化的成本。107.下面结合图4对上述s104中编译优化装置100计算上述满足条件a的源码的预取距离的过程进行进一步地描述。108.本技术实施例中,考虑到上述至少一个第一函数是程序源码中出现缓存缺失事件较多的函数,因此上述满足条件a的源码最有可能是上述至少一个第一函数的最内层循环中的源码,也就是说,上述第一循环最有可能是至少一个第一函数中的最内层循环,因此,编译优化装置100会执行s201-s203来获取第一循环。为了简便,此处以一个第一函数为例进行说明。109.s201:获取第一函数中的至少一个最内层循环。110.应理解,在实际情况中,第一函数可能包括多个最内层循环,有些最内层循环迭代的执行概率较高,而有些最内层循环迭代的执行概率较低。相较于迭代执行概率低的最内层循环,上述满足条件a的源码更有可能是迭代执行概率高的最内层循环中的一部分,因此,编译优化装置100还可以执行s202。此处需要说明的一点是,最内层循环迭代的执行概率是指在该循环中迭代运行的概率,而不是在函数中执行该循环的概率。111.s202:确定上述至少一个最内层循环中满足条件d的最内层循环,得到第一循环以及第一循环的cfg。112.其中,条件d包括以下至少一个:循环迭代的执行概率大于阈值g、循环不迭代的执行概率小于阈值h。113.在一具体的实施例中,编译优化装置100可以通过以下方式计算第一函数中每个最内层循环的执行概率或不执行的概率,以第一函数中的一个最内层循环为例进行说明:114.首先,构建该循环的cfg,该循环的cfg表示cpu在执行该循环的过程中会遍历到的所有路径。该循环的cfg包括多个bb和多条有向边,每条有向边指示该循环中的两个bb之间的执行顺序,每个bb包括至少一个指令,需要说明的是,bb中的指令为源码。然后,遍历每个bb,记录每个bb、每个bb的执行次数以及每条有向边的执行概率。之后,可以参考以下公式计算出该循环的执行概率以及不执行该循环的概率:[0115][0116]y2=1-y1[0117]其中,y1表示不执行该循环的概率,exit_edge_prob表示退出该循环的有向边的概率,exit_bb_count表示引出上述有向边的bb的执行次数,header_bb_count表示该循环的入口bb的执行次数,y2表示该循环的执行概率。上述exit_edge_prob、exit_bb_count以及header_bb_count可以由编译优化装置100利用编译器自带的静态分析功能、fdo或autofdo等方法计算得到,为了简便,本技术不对其进行介绍。[0118]举例说明,假设第一函数中包括循环1,条件d中阈值g为0.9,阈值h为0.2。图5示出了循环1的cfg,其中,bb1、bb2、bb3、bb4以及bb5的执行次数依次为100、99、100、99、1,有向边bb1→bb2、有向边bb1→bb3、有向边bb2→bb3、有向边bb3→bb4、有向边bb3→bb5以及有向边bb4→bb1的执行概率分别是99%、1%、100%、99%、1%、100%,并且,bb1为循环1的入口bb,有向边bb3→bb5为退出循环1的有向边。因此,利用上述公式可以计算得到y1=(1%*100)/100=0.01,y2=1-0.01=0.99,也就是说不执行循环1的概率为0.01,执行循环1的概率为0.99,满足上述条件d,第一函数中的循环1为一个第一循环。[0119]s203:确定与第一循环的循环层无关的bb以及与第一循环的循环层无关的有向边,并对上述无关的bb以及上述无关的有向边进行裁剪,得到第二循环。[0120]具体地,编译优化装置100遍历第一循环中的所有bb,确定与第一循环无关的bb以及有向边,并对这些无关的bb以及有向边进行裁剪,得到第二循环。其中,与第一循环的循环层无关的bb可以是退出第一循环的有向边指向的bb,与第一循环的循环层无关的有向边可以是退出第一循环的有向边。以图5所示的循环1为例,bb5为与循环1的循环层无关的bb,有向边bb3→bb5为与循环1的循环层无关的有向边,裁剪bb5和有向边bb3→bb5后可以得到如图6所示的循环。[0121]s204:计算第二循环中每个bb的执行概率。[0122]具体地,编译优化装置100在执行上述s202时,会构建第一函数中每个最内层循环的cfg,并记录cfg包括的bb以及有向边的执行概率。因此,编译优化装置100可以得到第一循环的cfg包括的每个bb以及每条有向边的执行概率,然后根据第一循环的cfg包括的每条有向边的执行概率,计算得到第二循环中每个bb的执行概率。[0123]在一种可能的实现方式中,为了方便计算,可以假设第二循环的入口bb的执行概率为100%,然后根据第一循环的cfg包括的每条有向边的执行概率,计算出第二循环中每个bb的执行概率。以图6所示的循环为例,假设bb1的执行概率为100%,由于有向边bb1→bb2、有向边bb1→bb3、有向边bb2→bb3、有向边bb3→bb4、有向边bb4→bb1的执行概率依次为99%、1%、100%、99%、100%,因此bb2的执行概率为99%,bb3的执行概率为100%(1%+99%),bb4的执行概率为99%。[0124]此处需要说明的是,对于执行概率较高的循环来说,在裁剪掉该循环的出口分支(即与该循环的循环层无关的bb)后,仍能够较为准确地反应独立循环体中各个bb的执行概率。而对于执行概率较低的循环来说,在裁剪掉循环的出口分支后,由于出口分支的执行概率较高,而循环层中的bb的执行概率较低,因此,裁剪后的循环中各个bb的执行概率并不能代表其在整个循环中的执行概率。也就是说,编译优化装置100执行上述s102还可以提高数据预取的准确性。[0125]还需说明的是,本技术实施例中,通过对循环分支的执行概率(即有向边的执行概率)计算,可以计算出更合理的单次循环的执行时间。例如,假设图6中bb2的可能包含大量的指令,因此执行bb2所耗费的时间较长,如果不根据有向边bb1→bb2的执行概率计算bb2的执行时间,会导致计算出的单次循环的执行时间较长。但是,在实际应用中,cpu执行bb2的概率很低(1%),也就是说,大多数情况下循环执行会直接从bb1跳转到bb3,这样计算出的单次循环的执行时间就会缩短很多。因此,在计算单次循环的执行时间时结合循环分支的执行概率会计算出更合理的值。[0126]s205:根据第二循环中每个bb的执行概率和每个bb中指令的数量和类型,计算第二循环的单次循环时间,即第一循环的循环层的单次循环时间(以下简称为第一循环的单次循环时间)。[0127]具体地,获取第二循环的每个bb中的所有指令的数量和类型,由于同一类型的指令的执行时间相同,因此,第二循环的单次循环时间的计算可以参考以下公式:[0128]loop_time=sum(bb_prob*sum(inst_time))[0129]其中,loop_time表示第二循环的单次循环时间,bb_prob表示bb的执行概率,inst_time表示bb中一条指令的执行时间,sum(inst_time)表示bb中所有指令的执行时间之和。[0130]s206:根据第一循环的单次循环时间和cpu访问内存的延迟时间,计算第一循环中的满足条件a的源码的预取距离。[0131]具体地,编译优化装置100获得cpu访问内存的延迟时间,确定第二循环中存在的第一源码,然后根据第二循环的单次循环时间和cpu访问内存的延迟时间,计算第二循环中的第一源码的预取距离。[0132]在一具体的实施例中,第一循环中满足条件a的源码的预取距离的计算可以参考以下公式:[0133]prefetch_dis=latency/loop_time[0134]其中,prefetch_dis表示第一循环中满足条件a的源码的预取距离,latency表示cpu访问内存的延迟时间,loop_time表示第二循环的单次循环时间。[0135]下面结合图7对上述s104中编译优化装置100根据第一配置信息对程序源码执行结构体成员重排的编译操作的过程进行进一步地描述。[0136]s301:确定上述多个结构体中的至少一个第一结构体。其中,第一结构体中的成员在使用上不存在顺序依赖。[0137]具体地,检测上述每个结构体中的各个成员在使用上是否存在顺序依赖。如果结构体中的任意一个成员在使用上存在顺序依赖,则编译优化装置100不对该结构体执行结构体成员重排的操作。如果结构体中的各个成员在使用上不存在顺序依赖(即第一结构体),则编译优化装置100执行下述s302-s306。[0138]s302:解析第一配置文件,获得程序源码的标识以及该标识对应的缓存缺失次数,从而得到上述至少一个第一结构体的缓存缺失次数。[0139]s303:按照缓存缺失次数的大小对上述至少一个第一结构体进行排序,筛选出满足条件e的结构体(以下简称为第二结构体)。[0140]其中,如果按照缓存缺失次数的大小对上述至少一个第一结构体进行降序排序,则条件e包括以下至少一个:结构体的缓存缺失次数大于阈值i、结构体的排序小于阈值j。如果按照缓存缺失次数的大小对上述至少一个第一结构体进行升序排序,则条件e包括以下至少一个:结构体的缓存缺失次数大于阈值i、结构体的排序大于阈值k。应理解,上述条件b包括:条件e和结构体中的各个成员在使用上不存在顺序依赖。[0141]s304:根据程序源码的标识以及该标识对应的缓存缺失次数,确定第二结构体中的各个成员的缓存缺失次数。[0142]s305:根据第二结构体中各个成员的缓存缺失次数,对第二结构体中的成员的排序进行调整,得到对应的第三结构体。[0143]在一具体的实施例中,编译优化装置100根据第二结构体中的各个成员的缓存缺失次数的大小,对第二结构体中的成员的排序进行调整,得到对应的第三结构体,包括如下步骤:按照第二结构体中各个成员的缓存缺失次数的大小,将该结构体中缓存缺失次数大的成员放置在同一个缓存块中,如此,可以提高缓存的使用率。[0144]举例说明,如图8所示,第二结构体包括8个成员,分别是成员a、成员b、成员c、成员d、成员e、成员f、成员g、成员h,且这些成员在使用上不存在顺序依赖。图9示出了第二结构体的存储排布示意图,如图9所示,第二结构体在缓存中存储为两个缓存块。假设,cpu执行程序时,只需要从缓存中读取上述成员a和成员g,在这种情况下,cpu需要从缓存中读取2个缓存块才能得到上述成员a和成员g。但是,如果执行上述实施例提供的方法,即按照缓存缺失次数的大小(缓存缺失次数从大到小的成员依次是:成员a、成员g、成员b、成员c、成员d、成员e、成员f、成员h)对第二结构体中的各个成员的排序进行调整,可以得到图10示出的第三结构体以及图11示出的第三结构体的存储排布示意图。在这种情况下,cpu只需要从缓存中读取1个缓存块就可以得到上述成员a和成员g。因此,相较于图8示出的第二结构体,当缓存中存储图10示出的第三结构体时,可以提高缓存的使用率。[0145]进一步地,编译优化装置100还可以获取第二结构体中各个成员的大小,并根据第二结构体中各个成员的缓存缺失次数以及第二结构体中各个成员的大小,对第二结构体中各个成员的排序进行调整,得到对应的第三结构体。具体地,当第二结构体中成员的缓存缺失次数相近时,可以根据成员的大小对各个成员的排序进行调整,从而得到对应的第三结构体。[0146]举例说明,仍以图8示出的第二结构体为例,假设,该第二结构体中成员b、成员c、成员d、成员e、成员f、成员h的缓存缺失次数均相近,相较于第二结构体中的其他成员,成员b和成员e占用的内存空间较小,因此,在图10示出的第三结构体的基础上,进一步对成员b、成员c、成员d、成员e、成员f、成员h的排序进行调整,从而得到图12示出的另一种第三结构体以及图13示出的另一种第三结构体的存储排布示意图。可以看出,图8和图10示出的结构体的大小均为64字节,而图12所示的结构体的大小仅为56字节,因此,相较于图8和图10示出的结构体,图12所示的结构体占用的存储空间更小,也就是说,利用上述方法可以提高缓存的使用率。[0147]s306:利用上述第三结构体代替第二结构体。[0148]本技术还提供了一种编译优化装置,该编译优化装置用于执行或实现上述程序源码的编译优化方法,该编译优化装置的功能既可以由软件系统实现,也可以由硬件设备实现,还可以由软件系统和硬件设备结合实现。[0149]如前述图2所示,本技术提供的编译优化装置可以包括运行单元110、事件采集单元120、解析单元130以及编译单元140。其中,运行单元110用于执行前述s101以及s102中涉及到运行第一可执行文件的步骤。事件采集单元120用于执行前述s102中涉及采集硬件缓存事件的步骤。解析单元130用于执行前述s103。编译单元140用于执行前述s104、s201-s206以及s301-s306。为了简便,此处不再展开叙述。[0150]本技术还提供了一种计算设备,该计算设备用于执行上述程序源码的编译优化方法,并且当上述编译优化装置100为软件系统时,该计算设备上还可以部署有上述编译优化装置100,以实现上述编译优化装置100的功能。[0151]如图14所示,图14示出了本技术提供的一种计算设备的结构示意图。其中,计算设备200包括存储器210、处理器220、通信接口230以及总线240。其中,存储器210、处理器220、通信接口230通过总线240实现彼此之间的通信连接。[0152]存储器210可以是只读存储器(readonlymemory,rom),静态存储设备、动态存储设备或者随机存取存储器(randomaccessmemory,ram)。存储器210可以存储计算机指令,例如:运行单元110中的计算机指令、事件采集单元120中的计算机指令、解析单元130中的计算机指令、编译单元140中的计算机指令等。当存储器210中存储的计算机指令被处理器220执行时,处理器220和通信接口230用于执行上述步骤s101-s104、s201-206、s301-s306所述的部分或全部方法。存储器210还可以存储数据,例如:存储处理器220在执行过程中产生的中间数据或结果数据,例如,调试信息、预取距离、结构体成员、第二可执行文件等。[0153]处理器220可以采用cpu、微处理器、专用集成电路(applicationspecificintegratedcircuit,asic)、图形处理器(graphicsprocessingunit,gpu)或者一个或多个集成电路。[0154]处理器220还可以是一种集成电路芯片,具有信号的处理能力。在实现过程中,上述编译优化装置100的部分或全部功能可以通过处理器220中的硬件的集成逻辑电路或者软件形式的指令完成。处理器220还可以是通用处理器、数据信号处理器(digitalsignalprocess,dsp)、现场可编程逻辑门阵列(fieldprogrammablegatearray,fpga)或者其他可编程逻辑器件,分立门或者晶体管逻辑器件,分立硬件组件,从而实现或者执行本技术实施例中公开的方法、步骤及逻辑框图。通用处理器可以是微处理器或者该处理器也可以是任何常规的处理器等,结合本技术实施例所公开的方法的步骤可以直接体现为硬件译码处理器执行完成,或者用译码处理器中的硬件及软件模块组合执行完成。软件模块可以位于随机存储器、闪存、只读存储器,可编程只读存储器或者电可擦写可编程存储器、寄存器等本领域成熟的存储介质中。该存储介质位于存储器210,处理器220读取存储器210中的信息,结合其硬件完成上述编译优化装置100的部分或全部功能。[0155]通信接口230使用例如但不限于收发器一类的手法模块,来实现计算设备200与其他设备或通信网络之间的通信。例如,可以通过通信接口230获取第一可执行文件和程序源码,还可以通过通信接口230将编译后的第二可执行文件发送给其他设备。[0156]总线240可以包括在计算设备400中的各个部件(例如,存储器210、处理器220、通信接口230)之间传送信息的通路。[0157]上述各个附图对应的流程的描述各有侧重,某个流程中没有详细描述的部分,可以参见其他流程的相关描述。[0158]在上述实施例中,可以全部或部分地通过软件、硬件或者其组合来实现。当使用软件实现时,可以全部或部分地以计算机程序产品的形式实现。提供模型训练系统的计算机程序产品包括一个或多个由模型训练系统执行的计算指令,在计算机上加载和执行这些计算机程序指令时,全部或部分地产生按照本技术实施例图所述的流程或功能。[0159]上述计算机可以是通用计算机、专用计算机、计算机网络、或者其他可编程装置。上述计算机指令可以存储在计算机可读存储介质中,或者从一个计算机可读存储介质向另一个计算机可读存储介质传输,例如,上述计算机指令可以从一个网站站点、计算机、服务器或数据中心通过有线(例如,同轴电缆、光纤、双绞线或无线(例如,红外、无线、微波)等)方式向另一个网站站点、计算机、服务器或数据中心进行传输。上述计算机可读存储介质存储有提供模型训练系统的计算机程序指令。所述计算机可读存储介质可以是计算机能够存取的任何可用介质或者是包含一个或多个介质集成的服务器、数据中心等数据存储设备。上述可用介质可以是磁性介质(例如,软盘、硬盘、磁带)、光介质(例如,光盘)、或者半导体介质(例如,固态硬盘(solidstatedisk,ssd))。当前第1页12当前第1页12
当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1