发明内容
为了解决以上问题,本公开实施例提供了一种用于处理器的多个执行模式的代码生成/执行方法、装置、设备、存储介质,用于对处理器的多个执行模式有针对性地生成可执行代码,在实现支持处理器的多个执行模式的基础上,保证多执行模式情形中的执行效率以及执行效果。
根据本公开的一方面,提供了一种用于处理器的多个执行模式的代码生成方法,包括:获取用户代码,其中,用户代码包括多个代码部分;基于多个执行模式之间的执行模式差异,在多个代码部分中确定需要差异执行的至少一个差异执行代码部分;根据所述多个代码部分之间的调用关系,针对差异执行代码部分生成分别对应于多个执行模式的多份差异可执行代码;以及,根据所述多个代码部分之间的调用关系,针对多个代码部分中除差异执行代码部分之外的至少一个代码部分生成对应于多个执行模式的一份共用可执行代码。
根据本公开的一些实施例,基于多个执行模式之间的执行模式差异,在多个代码部分中确定需要差异执行的至少一个差异执行代码部分包括:基于多个执行模式之间的执行模式差异,确定在多个代码部分中的具有执行模式差异的种子代码部分;基于多个代码部分之间的调用关系,确定调用种子代码部分的可达代码部分;将种子代码部分和可达代码部分一起确定作为差异执行代码部分。
根据本公开的一些实施例,针对多个代码部分中除差异执行代码部分之外的至少一个代码部分生成对应于多个执行模式的一份共用可执行代码包括:针对多个代码部分中除种子代码部分和可达代码部分之外的代码部分生成对应于多个执行模式的一份共用可执行代码。
根据本公开的一些实施例,对于生成的多份差异可执行代码和一份共用可执行代码,针对多个执行模式之一来执行多份差异可执行代码中的对应的其中一份差异可执行代码以及一份共用可执行代码。
根据本公开的一些实施例,基于多个执行模式之间的执行模式差异,在多个代码部分中确定需要差异执行的至少一个差异执行代码部分包括:基于多个执行模式之间的执行模式差异,确定在多个代码部分中的具有执行模式差异的种子代码部分;以及将种子代码部分确定作为差异执行代码部分。
根据本公开的一些实施例,针对多个代码部分中除差异执行代码部分之外的至少一个代码部分生成对应于多个执行模式的一份共用可执行代码的步骤包括:基于多个代码部分之间的调用关系,确定调用种子代码部分的至少一个可达代码部分;针对至少一个可达代码部分生成关于种子代码部分的调用逻辑作为可达代码部分的共用可执行代码,其中,调用逻辑包括:基于当前执行模式来从多份差异可执行代码中选择性地执行种子代码部分的对应于当前执行模式的差异可执行代码,其中,当前执行模式是选自多个执行模式之一的模式。
根据本公开的一些实施例,对于多个执行模式的多份差异可执行代码和一份共用可执行代码,判断当前执行模式,并基于当前执行模式以及多个代码部分的调用关系,通过调用逻辑针对当前执行模式来对应地执行多份差异可执行代码中的其中一份差异可执行代码、以及执行一份共用可执行代码。
根据本公开的一些实施例,判断当前执行模式的步骤包括:由执行状态寄存器指示当前执行模式;或者由执行模式差异程序判断当前执行模式。
根据本公开的一些实施例,基于多个执行模式之间的执行模式差异,确定在多个代码部分中的具有执行模式差异的种子代码部分的步骤包括:基于多个执行模式之间的执行模式差异,得到具有执行模式差异的所有种子代码部分;标记在多个代码部分中的与判定的具有执行模式差异的所有种子代码部分相同的代码部分作为具有执行模式差异的种子代码部分。
根据本公开的一些实施例,多个代码部分之间的调用关系为多个代码部分的调用图或调用表。
根据本公开的一些实施例,代码部分包括函数。
根据本公开的另一方面,还提供了一种用于处理器的多个执行模式的代码执行方法,其中,用于多个执行模式的可执行代码是根据以下步骤生成的:获取用户代码,其中,用户代码包括多个代码部分;基于多个执行模式之间的执行模式差异,在多个代码部分中确定需要差异执行的至少一个差异执行代码部分;根据所述多个代码部分之间的调用关系,针对差异执行代码部分生成分别对应于多个执行模式的多份差异可执行代码;以及,根据所述多个代码部分之间的调用关系,针对多个代码部分中除差异执行代码部分之外的至少一个代码部分生成对应于多个执行模式的一份共用可执行代码,其中,代码执行方法包括:针对多个执行模式,执行至少由多份差异可执行代码和共用可执行代码组成的可执行代码。
根据本公开的一些实施例,基于多个执行模式之间的执行模式差异,在多个代码部分中确定需要差异执行的至少一个差异执行代码部分的步骤是通过如下步骤实现的:基于多个执行模式之间的执行模式差异,确定在多个代码部分中的具有执行模式差异的种子代码部分;基于多个代码部分之间的调用关系,确定调用种子代码部分的可达代码部分;以及将种子代码部分和可达代码部分一起确定作为差异执行代码部分。
根据本公开的一些实施例,针对多个代码部分中除差异执行代码部分之外的至少一个代码部分生成对应于多个执行模式的一份共用可执行代码的步骤是通过如下步骤实现的:针对多个代码部分中除种子代码部分和可达代码部分之外的代码部分生成对应于多个执行模式的一份共用可执行代码。
根据本公开的一些实施例,执行至少由多份差异可执行代码和共用可执行代码组成的可执行代码的步骤包括:基于多个代码部分的调用关系,针对多个执行模式之一来执行多份差异可执行代码中的对应的其中一份差异可执行代码以及一份共用可执行代码。
根据本公开的一些实施例,基于多个执行模式之间的执行模式差异,在多个代码部分中确定需要差异执行的至少一个差异执行代码部分的步骤是通过如下步骤实现的:基于多个执行模式之间的执行模式差异,确定在多个代码部分中的具有执行模式差异的种子代码部分;将种子代码部分确定作为差异执行代码部分;其中,针对多个代码部分中除差异执行代码部分之外的至少一个代码部分生成对应于多个执行模式的一份共用可执行代码的步骤包括:基于多个代码部分之间的调用关系,确定调用种子代码部分的至少一个可达代码部分;针对至少一个可达代码部分生成关于种子代码部分的调用逻辑作为可达代码部分的共用可执行代码,其中,调用逻辑包括:基于当前执行模式来从多份差异可执行代码中选择性地执行种子代码部分的对应于当前执行模式的差异可执行代码,其中,当前执行模式是选自多个执行模式之一的模式。
根据本公开的一些实施例,执行由多份差异可执行代码和共用可执行代码组成的可执行代码的步骤包括:判断当前执行模式;以及基于当前执行模式以及多个代码部分的调用关系,通过调用逻辑针对当前执行模式来对应地执行多份差异可执行代码中的其中一份差异可执行代码、以及执行一份共用可执行代码。
根据本公开的一些实施例,判断当前执行模式的步骤包括:确定由执行状态寄存器指示的当前执行模式;或者确定由执行模式差异程序判断的当前执行模式。
根据本公开的又一方面,还提供了一种用于处理器的多个执行模式的代码生成装置,包括:获取单元,配置成获取用户代码,其中,用户代码包括多个代码部分;确定单元,配置成基于多个执行模式之间的执行模式差异,在多个代码部分中确定需要差异执行的至少一个差异执行代码部分;差异可执行代码生成单元,配置成根据所述多个代码部分之间的调用关系,针对差异执行代码部分生成分别对应于多个执行模式的多份差异可执行代码;以及共用可执行代码生成单元,配置成根据所述多个代码部分之间的调用关系,针对多个代码部分中除差异执行代码部分之外的至少一个代码部分生成对应于多个执行模式的一份共用可执行代码。
根据本公开的一些实施例,确定单元配置成:基于多个执行模式之间的执行模式差异,确定在多个代码部分中的具有执行模式差异的种子代码部分;基于多个代码部分之间的调用关系,确定调用种子代码部分的可达代码部分;将种子代码部分和可达代码部分一起确定作为差异执行代码部分。
根据本公开的一些实施例,共用可执行代码生成单元配置成:针对多个代码部分中除种子代码部分和可达代码部分之外的代码部分生成对应于多个执行模式的一份共用可执行代码。
根据本公开的一些实施例,对于生成的多份差异可执行代码和一份共用可执行代码,针对多个执行模式之一来执行多份差异可执行代码中的对应的其中一份差异可执行代码以及一份共用可执行代码。
根据本公开的一些实施例,确定单元配置成:基于多个执行模式之间的执行模式差异,确定在多个代码部分中的具有执行模式差异的种子代码部分;将种子代码部分确定作为差异执行代码部分。
根据本公开的一些实施例,共用可执行代码生成单元配置成:基于多个代码部分之间的调用关系,确定调用种子代码部分的至少一个可达代码部分;针对至少一个可达代码部分生成关于种子代码部分的调用逻辑作为可达代码部分的共用可执行代码,其中,调用逻辑包括:基于当前执行模式来从多份差异可执行代码中选择性地执行种子代码部分的对应于当前执行模式的差异可执行代码,其中,当前执行模式是选自多个执行模式之一的模式。
根据本公开的一些实施例,对于多个执行模式的多份差异可执行代码和一份共用可执行代码,判断当前执行模式,并基于当前执行模式以及多个代码部分的调用关系,通过调用逻辑针对当前执行模式来对应地执行多份差异可执行代码中的其中一份差异可执行代码、以及执行一份共用可执行代码。
根据本公开的一些实施例,当前执行模式是按照以下方式之一判断得到的:由执行状态寄存器指示当前执行模式;或者由执行模式差异程序判断当前执行模式。
根据本公开的一些实施例,确定单元配置成:基于多个执行模式之间的执行模式差异,得到具有执行模式差异的所有种子代码部分;标记在多个代码部分中的与判定的具有执行模式差异的所有种子代码部分相同的代码部分作为具有执行模式差异的种子代码部分。
根据本公开的一些实施例,多个代码部分之间的调用关系为多个代码部分的调用图或调用表。
根据本公开的一些实施例,代码部分包括函数。
根据本公开的又一方面,还提供了一种用于处理器的多个执行模式的代码执行装置,用于多个执行模式的可执行代码是根据上述代码生成装置生成的,代码执行装置包括:执行单元,配置成针对多个执行模式,执行至少由多份差异可执行代码和共用可执行代码组成的可执行代码。
根据本公开的又一方面,还提供了一种计算设备,包括:处理器;和存储器,其中,存储器中存储有计算机可读代码,计算机可读代码在由处理器运行时,进行如下之一:执行上述代码生成方法,或者执行上述代码执行方法。
根据本公开的又一方面,还提供了一种非暂时性计算机可读存储介质,其上存储有指令,指令在被处理器执行时,使得处理器进行如下之一:执行上述代码生成方法,或者执行上述代码执行方法。
根据本公开的又一方面,还提供了一种计算机程序产品,其包括计算机可读指令,计算机可读指令在被处理器执行时,使得处理器进行如下之一:执行上述代码生成方法,或者执行上述代码执行方法。
利用本公开实施例提供的用于处理器的多个执行模式的代码生成/执行方法、装置、设备、存储介质和程序产品,对于处理器的多个执行模式,能够基于多个执行模式之间的执行模式差异,确定需要差异执行的至少一个差异执行代码部分,并针对该差异执行代码部分生成分别对应于多个执行模式的多份差异可执行代码,以及针对除差异执行代码部分之外的至少一个代码部分生成一份共用可执行代码,即,能够根据多个执行模式之间的执行模式差异来有针对性地生成多份差异可执行代码,从而实现在能够支持处理器的多个执行模式的基础上,保证多执行模式情形中的执行效率以及执行效果。
具体实施方式
下面将结合本公开实施例中的附图,对本公开实施例中的技术方案进行清楚、完整地描述。显然,所描述的实施例仅是本公开一部分的实施例,而不是全部的实施例。基于本公开中的实施例,本领域普通技术人员在无需创造性劳动的前提下所获得的所有其他实施例,都属于本公开保护的范围。
此外,如本公开和权利要求书中所示,除非上下文明确提示例外情形,“一”、“一个”、“一种”和/或“该”等词并非特指单数,也可包括复数。本公开中使用的“第一”、“第二”以及类似的词语并不表示任何顺序、数量或者重要性,而只是用来区分不同的组成部分。同样,“包括”或者“包含”等类似的词语意指出现该词前面的元件或者物件涵盖出现在该词后面列举的元件或者物件及其等同,而不排除其他元件或者物件。“连接”或者“相连”等类似的词语并非限定于物理的或者机械的连接,而是可以包括电性的连接,不管是直接的还是间接的。
对于处理器而言,可以支持两个(或者可以称为两种)及以上的执行模式,其中,不同的执行模式可以是指针对用户指令的硬件执行行为不同。例如,不同的执行模式可以是指处理器的计算方式不同,诸如普通计算模式和张量(tensor)计算模式,也可以是指通用寄存器的数据宽度不同,诸如64比特执行模式和32比特执行模块,或者,也可以是指计算精度的不同,诸如对应于不同编码模式(例如,int8/int16/float/bfloat等)的执行模式,此外,也可以是指其他的执行模式,在此不再一一列举。
为了支持多个执行模式,相关技术中的编译器对于同一份用户代码将产生与多个执行模式分别对应的多份完整的可执行代码。需要注意的是,在本文中,多个执行模式表示两个或两个以上的执行模式。
图1示出了相关技术中针对两个执行模式生成两份可执行代码的示意图,其中,位于图1上部的代码为对应于用户代码的多个代码部分(代码部分可以是包括函数或其他代码),针对两个执行模式(例如,模式1和模式2),需要针对用户代码中的每个代码部分生成两份可执行代码。例如,对于如图1中示出的圆形框101和圆形框102,针对用户代码中的相同的代码部分,需要针对模式1和模式2分别生成两份相同的可执行代码。然而,这种实现方式将造成较长的编译时间、可执行代码的数据量比较大并且将使得执行时间变长,由此,降低了处理器的执行效率并影响处理器支持多个执行模式的处理效果。
具体的,首先,这种与多个执行模式分别对应的多份完整的可执行代码将需要更长的编译时间,这是由于用户代码中的每个函数都将被编译多次,并不可避免地产生数据量较大的可执行代码,这是因为针对用户代码中的每个函数都将产生多份可执行代码,对于一些大型的编译库,可执行代码数据量较大将会带来更多的问题。
其次,在执行阶段,多份完整的可执行代码将需要更长的执行时间,例如,在多个执行模式可以混合执行的情况下,内存需要加载多份可执行代码,这使得内存占用空间变大,缓存效率变低。
为解决上述相关技术中针对处理器的多个执行模式存在的至少一个问题,本公开的一些实施例提供了一种用于处理器的多个执行模式的代码生成方法,用于对处理器的多个执行模式有针对性地生成可执行代码,在实现支持处理器的多个执行模式的基础上,保证多执行模式情形中的执行效率以及执行效果。可以理解的是,在本文中涉及的处理器泛指各种类型的集成电路结构,诸如,微处理器、中央处理单元(Central Processing Unit,CPU)、图形处理单元(Graphics Processing Unit, GPU)、通用图形处理单元(General-purpose computing on graphics processing units, GPGPU)、系统级芯片(System onChip, SoC)等,在此不作限制。除非另有定义,本文中使用的所有术语具有与本公开所属领域的普通技术人员共同理解的相同含义。
为了更清楚地说明根据本公开实施例的代码生成方法,参考图2,其用于示出根据本公开实施例的代码生成方法的流程图。以下将结合图2来描述根据本公开实施例的代码生成方法的实施过程。
如图2所示,首先,在步骤S201,获取用户代码,其中,用户代码包括多个代码部分。例如,用户代码可以是指独立于机器而面向过程或对象的语言,例如,C语言、Java语言、C++语言、Python语言等,在此不作限制。用户代码中包括多个代码部分,本文中,代码部分可以表示为函数,例如,用户代码中包括多个函数。对于获取到的用户代码,需要编译器将高级语言编写的用户代码翻译为处理器可执行的二进制机器码。
接着,在步骤S202,基于多个执行模式之间的执行模式差异,在多个代码部分中确定需要差异执行的至少一个差异执行代码部分。
对于支持的多个执行模式,并非针对用户代码中的所有函数的可执行代码均不相同,而是仅有一部分的指令的执行行为存在差异,换句话说,对于用户代码中的函数,存在一部分函数需要根据执行模式的不同而差异执行,也存在其他部分函数对于多个执行模式而言执行行为是相同的。对于处理器而言,可以支持两个(或者可以称为两种)及以上的执行模式,其中,不同的执行模式可以是指针对用户指令的硬件执行行为不同。例如,不同的执行模式可以是指处理器的计算方式不同,诸如普通计算模式和张量(tensor)计算模式,也可以是指通用寄存器的数据宽度不同,诸如64比特执行模式和32比特执行模块,或者,也可以是指计算精度的不同,诸如对应于不同编码模式(例如,int8/int16/float/bfloat等)的执行模式,此外,也可以是指其他的执行模式,在此不再一一列举。
在此注意,“差异执行代码部分”不是指代码部分本身存在差异,而是指相同的代码部分在不同的执行模式下的执行结果不同,即执行过程和执行结果存在差异。
由此,在根据公开的一些实施例中,针对用户代码首先基于多个执行模式之间的执行模式差异来确定差异执行代码部分,再依据确定的差异执行代码部分来有针对性地生成用于多个执行模式的可执行代码。关于确定差异执行代码部分的过程将在下文详细介绍。
继续参考图2,在步骤S203,根据所述多个代码部分之间的调用关系,针对差异执行代码部分生成分别对应于多个执行模式的多份差异可执行代码,以及在步骤S204,根据所述多个代码部分之间的调用关系,针对多个代码部分中除差异执行代码部分之外的至少一个代码部分生成对应于多个执行模式的一份共用可执行代码。
在根据本公开的一些实施例中,仅针对确定的需要差异执行的至少一个差异执行代码部分来生成分别对应于多个执行模式的多份可执行代码,而对于除了差异执行代码部分之外的至少一个代码部分,将生成对应于多个执行模式的一份共用可执行代码。也就是说,减少了对该至少一个代码部分生成多分可执行代码的数据量和时间。相比于图1中针对多个执行模式生成完整的多份可执行代码的实现方式,根据本公开一些实施例的方法中,生成的可执行代码的总量(例如,二进制(binary)代码的总量)将明显降低,并因此缩短代码编译时间以及代码执行时间,从而能够在实现支持处理器的多个执行模式的基础上,保证处理器的执行效率以及执行效果。
图3示出了根据本公开一些实施例的确定至少一个差异执行代码部分的流程图,接下来,将结合图3详细描述确定需要差异执行的至少一个差异执行代码部分的过程。
如图3所示,首先,在步骤S2021,基于多个执行模式之间的执行模式差异,确定在多个代码部分中的具有执行模式差异的种子代码部分。根据本公开的一些实施例,步骤S2021可以包括:基于多个执行模式之间的执行模式差异,得到具有执行模式差异的所有种子代码部分,并标记在多个代码部分中的与判定的具有执行模式差异的所有种子代码部分相同的代码部分作为具有执行模式差异的种子代码部分。在本文中,具有执行模式差异的种子代码部分可以是用户代码中需要差异执行的函数,并将这种函数称为种子函数。当然,在此,确定所有种子代码部分和标记当前用户代码中的种子代码部分的步骤可以被包括在步骤S2021,即在确定差异执行代码部分时,但是本申请不限于此,该确定所有种子代码部分的步骤可以在确定差异执行代码部分之前的任何时候,且标记当前用户代码中的种子代码部分的步骤是为了指示在当前用户代码中哪些代码部分是种子代码部分,这也不是限制,还可以用其他方式来指示该代码部分是种子代码部分,例如用列表形式、映射表形式等等,或者该步骤也不是事先对所有代码部分确定哪些是种子代码部分,而可以是在对当前代码部分生成可执行代码时才判断该当前代码部分是否是种子代码部分等等。
接着,在步骤S2022,基于多个代码部分之间的调用关系,确定调用(被标记的)种子代码部分的可达代码部分,在步骤S2023,将种子代码部分和可达代码部分一起确定作为差异执行代码部分。
根据本公开的一些实施例,多个代码部分之间的调用关系可以是指多个代码部分的调用图(Call Graph),或者是指多个代码部分的调用表等,在此不作限制。例如,对于调用关系是指多个代码部分的调用图的情况下,可以通过调用图构建器(Call GraphBuilder)来生成表征用户代码的多个代码部分之间的调用关系的调用图。
图4示出了根据本公开实施例的调用图的示意图。调用图用于示出函数之间的调用关系,例如,函数Compute()调用函数getIdx()、函数abs()以及函数thread_block_barrier(),其中,可以将函数Compute()称为调用函数,将函数getIdx()、函数abs()以及函数thread_block_barrier()称为被调用的函数。以图4中示出的调用图为例,可以根据多个执行模式之间的执行模式差异确定得到具有执行模式差异的种子代码部分为函数thread_block_barrier(),即,在图4中,函数thread_block_barrier()作为种子函数。利用如图4所示的调用图可以得到该种子函数thread_block_barrier()的可达函数,其中,可达函数可以为调用该种子函数的函数或者为被该种子函数调用的函数,在图4中,种子函数thread_block_barrier()的可达函数为函数Compute()。
根据本公开的一些实施例,可以将以上种子函数(thread_block_barrier())和可达函数(Compute())一起确定作为差异执行代码部分。针对该差异执行代码部分,可以生成分别对应于多个执行模式的多份差异可执行代码。例如,在这些实施例中,步骤S204可以包括:针对多个代码部分中除种子代码部分和可达代码部分之外的(至少一个、或所有)代码部分生成对应于多个执行模式的一份共用可执行代码。例如,对于图4中示出的情形,可以对函数getIdx()和函数abs()生成对应于多个执行模式的一份共用可执行代码。
根据本公开的一些实施例,对于生成的多份差异可执行代码和一份共用可执行代码,针对多个执行模式之一来执行多份差异可执行代码中的对应的其中一份差异可执行代码以及一份共用可执行代码。对于生成的多份差异可执行代码和一份共用可执行代码,在处理器的执行阶段,能够根据当前的执行模式来执行多份差异可执行代码中对应于该当前执行模式的那份差异可执行代码以及该一份共用可执行代码。这在减少了可执行代码的数据量和生成时间的情况下保证了在每个执行模式下的可执行代码的正确执行。
图5A示出了根据本公开实施例的代码生成方法的实现过程示意图,图5B对应地示出了针对两个执行模式生成的可执行代码的示意图,以下将以图5A和图5B作为具体示例描述根据本公开一些实施例的代码生成方法以及根据该方法生成的可执行代码。
如图5A所示,首先,在步骤S501,接收用户代码,诸如以C语言或者C++语言编写的用户代码,用户代码中包括多个函数,例如,用户代码中的多个函数可以是图4中示出的函数Compute()、函数getIdx()、函数abs()以及函数thread_block_barrier()。
接着,在步骤S502和S503,通过调用图构建器基于用户代码来产生调用图(CallGraph)。
此外,在步骤S504,针对处理器的多个执行模式确定执行模式差异,以在步骤S505基于执行模式差异确定需要差异执行的种子函数。例如,种子函数可以是图4中示出的函数thread_block_barrier()。
在步骤S506,基于调用图以及确定的种子函数进行差异执行标记,例如,在调用图中标记出需要差异执行的种子函数thread_block_barrier()以及该种子函数的可达函数Compute(),将这两者确定为差异执行代码部分。
在步骤S507,基于标记的函数来针对性地生成可执行代码,其中,针对未被标记的部分生成一份共用可执行代码,因为这些函数对于处理器的多个执行模式而言,其硬件执行行为是相同的,采用一份共用代码即可实现执行的目的。此外,针对标记的部分,生成多份差异执行代码,以分别用于多个执行模式。
生成的可执行代码可以参照图5B,其中,对于除差异执行代码部分之外的代码部分(函数getIdx()和函数abs())生成一份共用可执行代码,对于差异执行代码部分(种子函数thread_block_barrier()和可达函数Compute()),生成分别对应于多个执行模式的多份差异可执行代码。
利用根据本公开一些实施例的代码生成方法,能够根据用户代码中需要差异执行的代码部分(在此是种子函数和种子函数的可达函数两者)来有针对性地生成多份可执行代码,而对于不需要差异执行的代码部分只生成一份共用的可执行代码,即,最终的可执行代码数据包中包含的是两份种子函数和两份可达函数以及一份公共的其他函数,由此相比于现有技术,减少了可执行代码的数量、代码的编译时间以及执行时间,而在执行时,执行与当前执行模式对应的那一份种子函数和可达函数以及一份其他公共的其他函数,从而实现在能够支持处理器的多个执行模式的基础上,保证多执行模式情形中的执行效率以及执行效果。
根据本公开的另一些实施例,图6示出了确定至少一个差异执行代码部分的另一流程图,如图6所示,步骤S202包括步骤S2021和S2024,首先,在步骤S2021,基于多个执行模式之间的执行模式差异,确定在多个代码部分中的具有执行模式差异的种子代码部分。此步骤S2021的实现过程与上文结合图3描述的步骤S2021类似,在此不再重复描述。
接着,如图6所示,在步骤S2024,将种子代码部分确定作为差异执行代码部分。在这些实施例中,将种子代码部分作为差异执行代码部分,并针对该差异执行代码部分生成分别对应于多个执行模式的多份差异可执行代码。
在这些实施例中,步骤S204包括:基于多个代码部分之间的调用关系,确定调用种子代码部分的至少一个可达代码部分;以及,针对至少一个可达代码部分生成关于种子代码部分的调用逻辑作为可达代码部分的共用可执行代码。其中,确定可达代码部分的过程与上文描述的过程类似,在此不再重复描述。
根据本公开的一些实施例,调用逻辑可以包括:基于当前执行模式来从多份差异可执行代码中选择性地执行种子代码部分的对应于当前执行模式的差异可执行代码,其中,当前执行模式是选自多个执行模式之一的模式。
根据本公开的一些实施例,对于多个执行模式的多份差异可执行代码和一份共用可执行代码,可以首先判断当前执行模式,并基于当前执行模式以及多个代码部分的调用关系,通过调用逻辑针对当前执行模式来对应地执行多份差异可执行代码中的其中一份差异可执行代码、以及执行一份共用可执行代码。
根据本公开的一些实施例,判断当前执行模式的步骤可以包括:由执行状态寄存器指示当前执行模式。例如,由硬件的状态寄存器来直接地提供关于当前执行模式的信息。在根据本公开的一些其他实施例中,判断当前执行模式的步骤可以包括:由执行模式差异程序判断当前执行模式。相比于上述状态寄存器的实现方式,例如,执行模式差异程序可以为软件的实现方式,例如,由执行模式差异程序针对16比特数据判断其值是bfloat16的1.0形式还是float16的1.0形式,并由此判断当前执行模式。
图7示出了根据本公开实施例的调用逻辑的示意图,如图7所示,对于种子函数thread_block_barrier(),通过调用图可以确定其可达函数,即函数Compute()。在将种子代码部分thread_block_barrier()确定作为差异执行代码部分的情况下,对种子代码部分thread_block_barrier()生成两份差异可执行代码thread_block_barrierM1()和thread_block_barrierM2(),对于可达函数Compute(),生成关于种子函数thread_block_barrier()的调用逻辑,图7左侧虚线框中的代码部分对应于该调用逻辑。在调用逻辑中,基于确定的当前执行模式(executionMode)来针对性地执行与该当前执行模式对应的种子函数。例如,在当前执行模式(executionMode)为执行模式1时,进行与执行模式1对应的差异可执行代码thread_block_barrierM1(),在当前执行模式(executionMode)为执行模式2时,进行与执行模式2对应的差异可执行代码thread_block_barrierM2()。
也就是说,在该实施例中,只是种子代码部分被重复生成了2份可执行代码,而在可达函数的可执行代码只是加入了上述调用逻辑,明确了在不同执行模式下调用不同的那一份种子函数的可执行代码,而不需要对可达函数重复生成2份可执行代码,如此,相比于先前描述的对种子函数和可达函数两者都生成多份可执行代码的情况,进一步减少了用于对可达函数生成2份可执行代码带来的代码数量、代码的编译时间以及执行时间,而在执行时,仍可执行可达函数以及可达函数所调用的与当前执行模式对应的那一份种子函数以及一份其他公共的其他函数,从而仍然实现了在能够支持处理器的多个执行模式的基础上,保证多执行模式情形中的执行效率以及执行效果。
可以理解的是,以上图7中示出的调用逻辑仅为示意性地,针对种子函数的调用逻辑还可以实现为其他形式,在此不作限制。
根据本公开的另一方面,还提供了一种用于处理器的多个执行模式的代码执行方法,图8示出了根据本公开实施例的用于处理器的多个执行模式的代码执行方法的流程图。
如图8所示,根据本公开实施例的代码执行方法包括步骤S206,针对处理器的多个执行模式,执行至少由多份差异可执行代码和共用可执行代码组成的可执行代码。具体的,用于多个执行模式的可执行代码是根据以下步骤生成的:获取用户代码,该用户代码包括多个代码部分;基于多个执行模式之间的执行模式差异,在多个代码部分中确定需要差异执行的至少一个差异执行代码部分;根据所述多个代码部分之间的调用关系,针对差异执行代码部分生成分别对应于多个执行模式的多份差异可执行代码;以及根据所述多个代码部分之间的调用关系,针对多个代码部分中除差异执行代码部分之外的至少一个代码部分生成对应于多个执行模式的一份共用可执行代码。
根据本公开的一些实施例,基于多个执行模式之间的执行模式差异,在多个代码部分中确定需要差异执行的至少一个差异执行代码部分的步骤是通过如下步骤实现的:基于多个执行模式之间的执行模式差异,确定在多个代码部分中的具有执行模式差异的种子代码部分;基于多个代码部分之间的调用关系,确定调用种子代码部分的可达代码部分;以及将种子代码部分和可达代码部分一起确定作为差异执行代码部分。根据本公开的一些实施例,针对多个代码部分中除差异执行代码部分之外的至少一个代码部分生成对应于多个执行模式的一份共用可执行代码的步骤是通过如下步骤实现的:针对多个代码部分中除种子代码部分和可达代码部分之外的代码部分生成对应于多个执行模式的一份共用可执行代码。
在根据本公开的这些实施例中,步骤S206可以包括:基于多个代码部分的调用关系,针对多个执行模式之一来执行多份差异可执行代码中的对应的其中一份差异可执行代码以及一份共用可执行代码。
以上描述的可执行代码的生成过程可以参照上文描述的根据本公开实施例的代码生成方法的实现方式,在此不再重复描述。
根据本公开的另一些实施例,基于多个执行模式之间的执行模式差异,在多个代码部分中确定需要差异执行的至少一个差异执行代码部分的步骤是通过如下步骤实现的:基于多个执行模式之间的执行模式差异,确定在多个代码部分中的具有执行模式差异的种子代码部分;将种子代码部分确定作为差异执行代码部分;其中,针对多个代码部分中除差异执行代码部分之外的至少一个代码部分生成对应于多个执行模式的一份共用可执行代码的步骤包括:基于多个代码部分之间的调用关系,确定调用种子代码部分的至少一个可达代码部分;针对至少一个可达代码部分生成关于种子代码部分的调用逻辑作为可达代码部分的共用可执行代码,其中,调用逻辑包括:基于当前执行模式来从多份差异可执行代码中选择性地执行种子代码部分的对应于当前执行模式的差异可执行代码,其中,当前执行模式是选自多个执行模式之一的模式。
在根据本公开的这些实施例中,步骤S206可以包括:判断当前执行模式;以及基于当前执行模式以及多个代码部分的调用关系,通过调用逻辑针对当前执行模式来对应地执行多份差异可执行代码中的其中一份差异可执行代码、以及执行一份共用可执行代码。具体的,当前执行模式可以是根据如下步骤确定的:确定由执行状态寄存器指示的当前执行模式;或者确定由执行模式差异程序判断的当前执行模式。
作为具体示例,图9示出了根据本公开实施例的代码生成方法和代码执行方法的实现过程示意图。如图9所示,方框901内的步骤可以是对应于根据本公开一些实施例的代码生成方法,方框902内的步骤可以是对应于根据本公开一些实施例的代码执行方法。
对于支持多个执行模式的处理器,在接收到用户代码之后,可以扫描输入的用户代码并构建用户代码中所有函数的调用图,接着,可以根据多个执行模式之间的执行模式差异,来在调用图中标记需要差异执行的种子函数,例如,种子函数可以是图4中示出的函数thread_block_barrier()。接着,针对确定的种子函数来对调用图进行遍历以确定该种子函数thread_block_barrier()的可达函数,例如,可达函数可以是图4中示出的函数Compute()。在确定以上信息之后,进行可执行代码的生成阶段,可以依据调用图进行判断,确定当前函数是否被标记,如果被标记,则表示该函数需要针对多个执行模式来差异执行,由此生成多份差异可执行代码。如果该当前函数未被标记,则表示该函数对于多个执行模式的执行行为相同,由此生成一份共用可执行代码。如图9所示,在代码执行阶段,对应于方框902,针对多个执行模式,执行至少由多份差异可执行代码以及一份共用可执行代码组成的可执行代码。
利用本公开实施例提供的用于处理器的多个执行模式的代码生成方法以及执行方法,对于处理器的多个执行模式,能够基于多个执行模式之间的执行模式差异,确定需要差异执行的至少一个差异执行代码部分,并针对该差异执行代码部分生成分别对应于多个执行模式的多份差异可执行代码,以及针对除差异执行代码部分之外的至少一个代码部分生成一份共用可执行代码,即,能够根据多个执行模式之间的执行模式差异来有针对性地生成多份差异可执行代码,从而实现在能够支持处理器的多个执行模式的基础上,保证多执行模式情形中的执行效率以及执行效果。
根据本公开的另一方面,还提供了一种用于处理器的多个执行模式的代码生成装置,用于对处理器的多个执行模式,基于多个执行模式之间的执行模式差异来确定需要差异执行的至少一个差异执行代码部分,并针对该差异执行代码部分生成分别对应于多个执行模式的多份差异可执行代码,以及针对除差异执行代码部分之外的至少一个代码部分生成一份共用可执行代码,即,能够根据多个执行模式之间的执行模式差异来有针对性地生成多份差异可执行代码,从而实现在能够支持处理器的多个执行模式的基础上,保证多执行模式情形中的执行效率以及执行效果。
图10A示出了根据本公开实施例的代码生成装置的示意性框图。如图10A所示,代码生成装置1000可以包括获取单元1010、确定单元1020、差异可执行代码生成单元1030以及共用可执行代码生成单元1040。
根据本公开的一些实施例,获取单元1010可以配置成获取用户代码,其中,用户代码包括多个代码部分。例如,用户代码可以是指独立于机器而面向过程或对象的语言,例如,C语言或者C++语言,在此不作限制。用户代码中包括多个代码部分,本文中,代码部分可以表示为函数,例如,用户代码中包括多个函数。对于获取到的用户代码,需要编译器将高级语言编写的用户代码翻译为处理器可执行的二进制机器码。根据本公开的一些实施例,代码部分包括函数。
根据本公开的一些实施例,确定单元1020可以配置成基于多个执行模式之间的执行模式差异,在多个代码部分中确定需要差异执行的至少一个差异执行代码部分。在根据公开的一些实施例中,针对用户代码首先基于多个执行模式之间的执行模式差异来确定差异执行代码部分,再依据确定的差异执行代码部分来有针对性地生成用于多个执行模式的可执行代码。关于确定差异执行代码部分的过程将在下文详细介绍。
根据本公开的一些实施例,差异可执行代码生成单元1030可以配置成:根据所述多个代码部分之间的调用关系,针对差异执行代码部分生成分别对应于多个执行模式的多份差异可执行代码。
根据本公开的一些实施例,共用可执行代码生成单元1040可以配置成根据所述多个代码部分之间的调用关系,针对多个代码部分中除差异执行代码部分之外的至少一个代码部分生成对应于多个执行模式的一份共用可执行代码。
在根据本公开的一些实施例中,仅针对确定的需要差异执行的至少一个差异执行代码部分来生成分别对应于多个执行模式的多份可执行代码,而对于除了差异执行代码部分之外的代码部分,将生成对应于多个执行模式的一份共用可执行代码。相比于图1中针对多个执行模式生成完整的多份可执行代码的实现方式,根据本公开一些实施例的方法中,生成的可执行代码的总量(例如,binary)将明显降低,并因此缩短代码编译时间以及代码执行时间,从而能够在实现支持处理器的多个执行模式的基础上,保证处理器的执行效率以及执行效果。
根据本公开的一些实施例,确定单元1020可以配置成:基于多个执行模式之间的执行模式差异,确定在多个代码部分中的具有执行模式差异的种子代码部分;基于多个代码部分之间的调用关系,确定调用种子代码部分的可达代码部分;将种子代码部分和可达代码部分一起确定作为差异执行代码部分。
根据本公开的一些实施例,共用可执行代码生成单元1040配置成:针对多个代码部分中除种子代码部分和可达代码部分之外的代码部分生成对应于多个执行模式的一份共用可执行代码。
根据本公开的一些实施例,对于生成的多份差异可执行代码和一份共用可执行代码,针对多个执行模式之一来执行多份差异可执行代码中的对应的其中一份差异可执行代码以及一份共用可执行代码。
根据本公开的一些实施例,确定单元1020配置成:基于多个执行模式之间的执行模式差异,确定在多个代码部分中的具有执行模式差异的种子代码部分;将种子代码部分确定作为差异执行代码部分。
根据本公开的一些实施例,共用可执行代码生成单元1040配置成:基于多个代码部分之间的调用关系,确定调用种子代码部分的至少一个可达代码部分;针对至少一个可达代码部分生成关于种子代码部分的调用逻辑作为可达代码部分的共用可执行代码,其中,调用逻辑包括:基于当前执行模式来从多份差异可执行代码中选择性地执行种子代码部分的对应于当前执行模式的差异可执行代码,其中,当前执行模式是选自多个执行模式之一的模式。
根据本公开的一些实施例,对于多个执行模式的多份差异可执行代码和一份共用可执行代码,判断当前执行模式,并基于当前执行模式以及多个代码部分的调用关系,通过调用逻辑针对当前执行模式来对应地执行多份差异可执行代码中的其中一份差异可执行代码、以及执行一份共用可执行代码。
根据本公开的一些实施例,当前执行模式是按照以下方式之一判断得到的:由执行状态寄存器指示当前执行模式;或者由执行模式差异程序判断当前执行模式。
根据本公开的一些实施例,确定单元1020配置成:基于多个执行模式之间的执行模式差异,得到具有执行模式差异的所有种子代码部分;标记在多个代码部分中的与判定的具有执行模式差异的所有种子代码部分相同的代码部分作为具有执行模式差异的种子代码部分。
根据本公开的一些实施例,多个代码部分之间的调用关系为多个代码部分的调用图或调用表。根据本公开的一些实施例,多个代码部分之间的调用关系可以是指多个代码部分的调用图(Call Graph),或者是指多个代码部分的调用表等,在此不作限制。例如,对于调用关系是指多个代码部分的调用图的情况下,可以通过调用图构建器(Call GraphBuilder)来生成表征用户代码的多个代码部分之间的调用关系的调用图。
关于代码生成装置1000执行的步骤可以参照以上结合附图描述的根据本公开的代码生成方法,在此不再重复描述。
根据本公开的又一方面,还提供了一种用于处理器的多个执行模式的代码执行装置,其中,用于多个执行模式的可执行代码是根据上述代码生成装置1000生成的。
图10B示出了根据本公开实施例的代码执行装置的示意性框图,如图10B所示,代码执行装置1200包括执行单元1210。
根据本公开的一些实施例,执行单元1210可以配置成:针对多个执行模式,执行至少由多份差异可执行代码和共用可执行代码组成的可执行代码。
关于代码执行装置1200执行的步骤可以参照以上结合附图描述的根据本公开的代码执行方法,在此不再重复描述。
利用本公开实施例提供的用于处理器的多个执行模式的代码执行装置,其中,对于处理器的多个执行模式,能够基于多个执行模式之间的执行模式差异,确定需要差异执行的至少一个差异执行代码部分,并针对该差异执行代码部分生成分别对应于多个执行模式的多份差异可执行代码,以及针对除差异执行代码部分之外的至少一个代码部分生成一份共用可执行代码,即,能够根据多个执行模式之间的执行模式差异来有针对性地生成多份差异可执行代码,从而使得在代码执行阶段,代码执行装置能够实现在支持处理器的多个执行模式的基础上,保证多执行模式情形中的执行效率以及执行效果。
根据本公开的又一方面,还提供了一种计算设备。图11示出了根据本公开实施例的计算设备的示意性框图。
如图11所示,计算设备2000可以包括处理器2010以及存储器2020。根据本公开实施例,存储器2020中存储有计算机可读代码,该计算机可读代码当由处理器2010运行时,进行如下之一:执行上述代码生成方法,或者执行上述代码执行方法。根据本公开的一些实施例,该计算机可读代码当由处理器2010运行时也可以执行上述代码生成方法以及上述代码执行方法。
处理器2010可以根据存储在存储器2020中的程序执行各种动作和处理。具体地,处理器2010可以是一种集成电路,具有信号的处理能力。上述处理器可以是通用处理器、数字信号处理器(DSP)、专用集成电路(ASIC)、现成可编程门阵列(FPGA)或者其他可编程逻辑器件、分立门或者晶体管逻辑器件、分立硬件组件。可以实现或者执行本发明实施例中公开的各种方法、步骤及逻辑框图。通用处理器可以是微处理器或者该处理器也可以是任何常规的处理器等,可以是X86架构或者是ARM架构等。
存储器2020存储有计算机可执行指令代码,该指令代码在被处理器2010执行时用于实现根据本公开实施例的代码生成方法和/或代码执行方法。存储器2020可以是易失性存储器或非易失性存储器,或可包括易失性和非易失性存储器两者。非易失性存储器可以是只读存储器(ROM)、可编程只读存储器(PROM)、可擦除可编程只读存储器(EPROM)、电可擦除可编程只读存储器(EEPROM)或闪存。易失性存储器可以是随机存取存储器(RAM),其用作外部高速缓存。通过示例性但不是限制性说明,许多形式的RAM可用,例如静态随机存取存储器(SRAM)、动态随机存取存储器(DRAM)、同步动态随机存取存储器(SDRAM)、双倍数据速率同步动态随机存取存储器(DDRSDRAM)、增强型同步动态随机存取存储器(ESDRAM)、同步连接动态随机存取存储器(SLDRAM)和直接内存总线随机存取存储器(DR RAM)。应注意,本文描述的存储器旨在包括但不限于这些和任意其它适合类型的存储器。
根据本公开实施例的方法或装置也可以借助于图12所示的计算设备3000的示例性架构来实现。如图12所示,计算设备3000可以包括总线3010、一个或多个CPU 3020、只读存储器(ROM)3030、随机存取存储器(RAM)3040、连接到网络的通信端口3050、输入/输出组件3060、硬盘3070等。计算设备3000中的存储设备,例如ROM 3030或硬盘3070可以存储本公开提供的代码生成方法和/或代码执行方法的处理和/或通信使用的各种数据或文件以及CPU所执行的程序指令。计算设备3000还可以包括用户界面3080。
当然,图12所示的架构只是示例性的,在实现不同的设备时,根据实际需要,可以省略图12示出的计算设备中的一个或多个组件。
根据本公开的又一方面,还提供了一种非暂时性计算机可读存储介质。图13示出了根据本公开实施例的非暂时性计算机可读存储介质的示意图。
如图13所示,计算机可读存储介质4020上存储有指令,指令例如是计算机可读指令4010。当计算机可读指令4010由处理器运行时,可以执行参照以上附图描述的代码生成方法和/或代码执行方法。计算机可读存储介质包括但不限于例如易失性存储器和/或非易失性存储器。易失性存储器例如可以包括随机存取存储器(RAM)和/或高速缓冲存储器(cache)等。非易失性存储器例如可以包括只读存储器(ROM)、硬盘、闪存等。例如,计算机可读存储介质4020可以连接于诸如计算机等的计算设备,接着,在计算设备运行计算机可读存储介质4020上存储的计算机可读指令4010的情况下,可以进行如上所描述的代码生成方法和/或代码执行方法。
根据本公开的又一方面,还提供了一种计算机程序产品或计算机程序,该计算机程序产品或者计算机程序包括计算机可读指令,该计算机可读指令存储在计算机可读存储介质中。计算机设备的处理器可以从计算机可读存储介质读取该计算机可读指令,处理器执行该计算机可读指令,使得该计算机设备执行上述各个实施例中描述的代码生成方法和/或代码执行方法。
根据本公开的一些实施例的计算机程序产品或计算机程序实现为软件包的形式并应用于诸如编译器的产品中,以用于实现对接收的用户代码中需要差异执行的代码部分来有针对性地生成多份可执行代码,以支持处理器实现多个执行模式。如上所述,本文中的多个执行模式指的是两个及两个以上的执行模式。
利用本公开实施例提供的代码生成/执行方法、装置、设备、存储介质和程序产品,对于处理器的多个执行模式,能够基于多个执行模式之间的执行模式差异,确定需要差异执行的至少一个差异执行代码部分,并针对该差异执行代码部分生成分别对应于多个执行模式的多份差异可执行代码,以及针对除差异执行代码部分之外的至少一个代码部分生成一份共用可执行代码,即,能够根据多个执行模式之间的执行模式差异来有针对性地生成多份差异可执行代码,从而实现在能够支持处理器的多个执行模式的基础上,保证多执行模式情形中的执行效率以及执行效果。
本领域技术人员能够理解,本公开所披露的内容可以出现多种变型和改进。例如,以上所描述的各种设备或组件可以通过硬件实现,也可以通过软件、固件、或者三者中的一些或全部的组合实现。
此外,虽然本公开对根据本公开的实施例的系统中的某些单元做出了各种引用,然而,任何数量的不同单元可以被使用并运行在客户端和/或服务器上。单元仅是说明性的,并且系统和方法的不同方面可以使用不同单元。
本公开中使用了流程图用来说明根据本公开的实施例的方法的步骤。应当理解的是,前面或后面的步骤不一定按照顺序来精确的进行。相反,可以按照倒序或同时处理各种步骤。同时,也可以将其他操作添加到这些过程中。
本领域普通技术人员可以理解上述方法中的全部或部分的步骤可通过计算机程序来指令相关硬件完成,程序可以存储于计算机可读存储介质中,如只读存储器、磁盘或光盘等。可选地,上述实施例的全部或部分步骤也可以使用一个或多个集成电路来实现。相应地,上述实施例中的各模块/单元可以采用硬件的形式实现,也可以采用软件功能模块的形式实现。本公开并不限制于任何特定形式的硬件和软件的结合。
以上是对本公开的说明,而不应被认为是对其的限制。尽管描述了本公开的若干示例性实施例,但本领域技术人员将容易地理解,在不背离本公开的新颖教学和优点的前提下可以对示例性实施例进行许多修改。因此,所有这些修改都意图包含在权利要求书所限定的本公开范围内。应当理解,上面是对本公开的说明,而不应被认为是限于所公开的特定实施例,并且对所公开的实施例以及其他实施例的修改意图包含在所附权利要求书的范围内。本公开由权利要求书及其等效物限定。