一种残膜回收机防缠绕挑膜装置的制 一种秧草收获机用电力驱动行走机构

共享数据结构的制作方法

2023-06-01 06:07:08 来源:中国专利 TAG:


1.本公开涉及编译基于图表的程序以在包括一个或多个处理器芯片的处理系统上运行,每个处理器芯片包括一个或多个处理器模块或“瓦片(tile)”。本公开还涉及一种处理系统,编译的代码已经被加载到该处理系统上。


背景技术:

2.程序通常是用高级编程语言编写的,这意味着一种从处理器的至少一些特定体系结构中抽象出来的语言,因此该语言比由目标处理器执行的低级机器代码指令更容易被人理解。编译指的是采用以高级语言编写的程序并将其降低到可由处理器执行的形式的过程,即,将高级程序转换成包括可由处理器执行的机器代码指令的低级程序。出于本公开的目的,“指令”表示机器代码指令,即处理器的执行单元被配置为识别和执行的指令类型的基本集合之一的实例。这个集合在本领域中被称为处理器的指令集。指令集中的每个指令类型由映射到执行单元中相应类型的操作的不同的相应操作码来定义,并且由用于采取该操作的相应的零个或多个操作码的零个或多个操作数字段来定义。
3.如今,高级程序通常采用图表的形式。例如,这可以是处理器包括多个处理器模块的情况,处理器模块有时也称为“瓦片”。每个瓦片包括其自己的内存和执行单元(通常每个配置有相同的指令集)。瓦片经由片上互连连接在一起,片上互连使得在不同瓦片上运行的代码段能够在同一芯片(即管芯(die))上的瓦片之间相互通信。在一些情况下,系统还可以包括多个芯片,每个芯片包括多个瓦片。在这种情况下,芯片可以通过外部互连连接在一起,使得不同芯片上的瓦片能够相互通信。该图描述了多个数据节点、计算顶点以及节点和/或顶点之间的边。编译器的任务之一是确定哪些数据节点和哪些顶点将在哪些瓦片上实现。因此,程序代码的独立部分可以在不同的瓦片上并行运行。因此,有可能以高度的并行性将多个独立的处理资源连接在一起。
4.并行处理的一个应用例子见于机器智能。如机器智能领域的技术人员所熟悉的,机器智能算法基于对“知识模型”执行迭代更新,该“知识模型”可以由多个互连节点或“神经元(neurone)”的网络来表示。每个神经元代表其输入的一个功能。一些神经元接收网络的输入,一些神经元接收来自一个或多个其它神经元的输入,而一些神经元的输出形成其它神经元的输入,一些神经元的输出提供网络的输出。此外,每个神经元的功能由一个或多个各自的参数来参数化,这些参数有时被称为权重(不一定意味着乘法权重,不过也是一种可能性)。在学习阶段,目标是基于一组经验输入数据,找到各种权重的值,使得网络作为一个整体将为一系列可能的输入生成期望的输出。实现这一点的各种算法在本领域中是已知的,例如基于随机梯度下降的反向传播算法。在基于输入数据的多次迭代中,权重被逐渐调整以减小它们的误差,因此网络向一个解收敛。在随后的阶段中,在给定一组指定的输入的情况下,所学习的模型随后可以被用来对输出进行预测,或者在给定一组指定的输出的情况下,对输入(原因)进行推断。
5.每个神经元的实现都涉及数据的处理,图表的互连对应于神经元之间要交换的数
据。通常,每个神经元的至少一些处理可以独立于网络中的一些或所有其它神经元进行,因此大型神经网络展示出了并行的巨大机会。
6.基于图表的方法决不限于多瓦片处理器或并行处理,也不限于神经网络或机器智能应用。一般来说,图表可以用来描述任何复杂的流程或计算和数据之间的相互关系。
7.为了最大限度地发挥并行处理的作用,需要在特定芯片允许的情况下并行执行尽可能多的任务。也就是说,理想情况下,所有瓦片在大部分时间内同时处于激活状态(执行代码)。为了激活瓦片,瓦片的执行单元正在执行指令,这些指令形成存储在瓦片的本地内存中的本地程序的一部分。一些类型的图表(特别是机器学习和神经网络图)需要在多个瓦片中同时执行相同的操作。为了实现这一点,需要在每个瓦片上提供相同的本地程序。这可以通过在芯片被配置为实现图表时将程序的编译版本降低到每个瓦片上来实现。


技术实现要素:

8.本发明人已经认识到这对芯片内每个瓦片的本地内存提出了容量需求。一旦本地程序已经以二进制(机器可读)形式永久存储在瓦片上,其就会用尽该内存空间,不管它当前是否正由瓦片执行。这种永久存储有时被称为“烘焙(baking)”为二进制。
9.发明人还认识到,类似的考虑适用于可以提供给本地程序的数据。该数据可以包括程序所需的常数,因此需要在具有需要常数的特定程序的所有瓦片上复制这些常数。
10.本公开解决了这些和其它挑战。
11.本公开的一个方面提供了一种在包括多个处理单元的计算机上存储代码的方法,每个处理单元具有被配置成存储包括可执行代码序列的只读元素的本地内存和用于执行存储在本地内存中的至少一些可执行代码序列的执行阶段,该方法包括:
12.将计算机的多个处理单元中的至少一个识别为主处理单元;
13.编译包括用于加载到计算机的处理单元中的可执行代码序列的只读元素,该编译包括向主处理单元分配至少一个可共享的只读元素;
14.在主处理单元的本地内存中存储至少一个可共享只读元素,其被指定为由至少一个其它处理单元的执行阶段使用,以及存储发送交换代码序列,其被指定为在编译时确定的时间点在主处理单元的执行阶段执行,所述发送交换代码序列使处理单元识别可共享只读元素并生成要传输以供至少一个其它处理单元接收的消息,该消息包括可共享只读数据元素。
15.可共享只读元素可以包括要在至少一个其它处理单元的执行阶段执行的可执行代码序列。
16.例如,可执行代码序列可以包括应用图中的顶点的实例。
17.在另一个例子中,可执行代码序列可以包括用于管理计算机的处理单元中的代码序列的执行的控制代码。
18.在另一示例中,可共享只读元素包括常数值,该常数值可以是以下之一:
19.顶点状态,
20.顶点描述符,以及
21.字段数据。
22.在一些实施例中,编译包括将至少一个不可共享的只读元素分配给多个处理单元
中的至少一个。
23.在一些实施例中,至少一个可共享只读元素被包含在包括多个可共享只读元素的共享数据结构中。
24.分配至少一个可共享只读元素的步骤可以包括将多个可共享只读元素分配给各个处理单元中的各个地址,并解决可共享只读元素的地址约束。
25.在一些实施例中,该方法包括在至少一个其它处理单元的本地内存中存储被指定在至少一个其它处理单元的执行阶段执行的接收交换代码序列,该接收交换代码序列使得至少一个其它处理单元将在消息中接收的可共享只读元素存储在至少一个其它处理单元的本地内存中的分配地址处。
26.在一些实施例中,将至少一个可共享只读元素分配给主处理单元的步骤包括:
27.识别要编译的程序流中包括多个可共享只读元素的至少一个共享数据结构,
28.将共享数据结构的内存中的存储需求与发送交换代码序列的内存中的存储需求进行比较,以及
29.基于该比较,确定是将只读元素作为可共享数据结构分配给主处理单元,还是在多个处理单元上复制该数据结构。
30.程序流可以表示应用图。
31.本公开的另一方面提供了一种计算机,包括:
32.多个处理单元,每个处理单元具有被配置成存储包括可执行代码序列的只读元素的本地内存以及用于执行存储在本地内存中的至少一些可执行代码序列的执行阶段,其中多个处理单元中的至少一个包括主处理单元,
33.所述主处理单元本地内存被配置为存储至少一个可共享的只读元素,其中该元素被指定为由至少一个其它处理单元的执行阶段使用;以及存储发送交换代码序列,其中该代码序列被指定为在主处理单元的执行阶段执行,并且该代码序列使得主处理单元识别可共享的只读元素并生成要被传输以供至少一个其它处理单元接收的消息,
34.其中至少一个其它处理单元已经在其本地内存中存储了接收交换代码序列,该接收交换代码序列使得所述至少一个其它处理单元从该消息中接收可共享只读元素,并且仅在使用期内将其存储在其本地内存中的地址处,至少一个其它处理单元被配置为在使用期过后从其本地内存中删除该可共享只读元素。不需要删除策略来从本地内存中移除可共享的只读元素。在一些实施例中,当新值被写入时,它可以被重写为编译时所确定的内容。在编译时,程序中不再需要它的点会被记录下来,这意味着它可以在以后被重写。它可能不会立即被重写,甚至可能根本不会被重写——这可能取决于编译器是否找到了另一个稍后写入的变量,该变量可以分配给一个重叠的地址。
35.由该发送交换代码生成的消息可以包括加载地址,可共享数据只读元素将在至少一个其它处理单元处被存储在加载地址处。加载地址可能在消息中,也可能在交换代码中。在一些实施例中,写入所接收的数据的地址在接收交换代码中有明确交待。
36.存储在主处理单元的内存中的至少一个可共享只读元素可以形成包括多个可共享只读元素的共享数据结构的一部分。
37.在一些实施例中,计算机包括多个主处理单元。
38.共享数据结构可以包括可执行代码序列或一组常数值。
39.在一些实施例中,将至少一个可共享只读元素分配给主处理单元的步骤包括:
40.识别要编译的程序流中包括多个可共享只读元素的至少一个共享数据结构,
41.将共享数据结构的内存中的存储需求与发送交换代码序列的内存中的存储需求进行比较,以及
42.基于该比较,确定是将只读元素作为可共享数据结构分配给所述主处理单元,还是在多个处理单元上复制该数据结构。
43.程序流可以表示应用图。
附图说明
44.为了帮助理解本公开的实施例并示出这些实施例是如何实施的,仅以示例的方式参考附图:
45.图1是包括多个瓦片的系统的示意框图;
46.图2是处理器模块的示意框图;
47.图3示出了存储代码序列的瓦片,该代码序列具有寻址不同变量的指针;
48.图4示出了存储变量的一组瓦片,这些变量是受相等地址约束的;
49.图4a和4b示出了不同组的变量;
50.图5示出了不同瓦片之间的数据交换;
51.图6示出了存储指向保存地址的寄存器的指针的一组瓦片;
52.图7示出了存储包括二维向量的指针的瓦片;
53.图8示出了存储包括向量列表的指针的瓦片;
54.图9示意性地示出了编译程序的方法;
55.图10示意性地示出了输入图的一部分;
56.图11示意性地示出了具有输入边和输出边的图的顶点;
57.图12示意性地示出了两个等效的图表表示;
58.图13是约束求解过程的示意流程图;以及
59.图14示出了两个瓦片中的每一个瓦片上的程序的示例。
具体实施方式
60.在下面描述的本发明的实施例中,描述了一种计算机和一种为计算机编译的方法,其中可以通过识别可以在计算机的处理单元之间共享的只读元素来优化内存使用。这里使用的术语“共享结构”或“共享数据结构”是指可以共享的只读元素。如果多个处理单元需要相同的只读元素,一种选择是在为每个处理单元编译的每个程序中包括适当的共享数据结构,使得在计算机上存在副本。根据本发明的实施例,提供了一种替代技术,其中共享数据结构存储在主处理单元中,并在需要时传输到一个或多个其它处理单元。在存储共享数据结构所需的存储量和在处理单元之间共享数据结构所需的交换代码的存储量之间,以及在程序运行时涉及的通信和时间开销之间,存在一种折衷。如果共享数据结构相对较小(就其用尽的内存资源而言),则在编译后的程序中的多个处理单元之间复制该共享数据结构可能更合适,而不是使用所述实施例的共享技术。
61.在本文描述的一个方面,执行分析以指示是使用共享方案,还是跨多个处理单元
复制数据结构。
62.只读元素可以是代码或常量变量。
63.图1示出了计算机100形式的示例处理系统,根据这里公开的实施例,编译的程序可以在其上执行。该计算机包括多个处理器模块4a、4b、4c等,称为瓦片。瓦片4a、4b、4c可以在一个或多个处理器芯片2上实现,每个芯片(即管芯)上有多个瓦片4。参考图2,每个单独的瓦片——例如瓦片4a——包括其自己相应的处理单元10,每个处理单元包括其自己相应的用于执行机器代码指令的执行单元18。每个单独的瓦片还包括其自己的相应内存22a,用于存储数据和代码。因此,计算机100支持大量的并行性,使得能够在不同的瓦片4a、4b、4c等上并行执行整个程序的不同部分。例如,芯片2可以包括≥10、≥20、≥50、≥100、≥200、≥500或者甚至≥1000个瓦片。例如,在示例实现中,每个芯片可以有1216或1280个瓦片。此外,在实施例中,每个处理单元可以采取多线程处理单元的形式,用于通过同一流水线交错多个并发线程。然而,这对目前的目的来说并不重要。
64.计算机100还包括互连6,该互连6包括硬件逻辑,该硬件逻辑形成使得不同瓦片4a、4b、4c等之间相互通信以交换数据的交换机制的一部分,例如使得由一个瓦片(例如瓦片4a)执行的计算结果可以被发送到另一个瓦片(例如瓦片4c)。互连6包括芯片2上的至少一个内部(片上)互连,用于在同一芯片2上的瓦片4a之间通信。根据本发明的实施例,互连6还使得共享数据结构能够在块内存之间交换。
65.作为编译过程的一部分,程序的不同部分被分配来在不同的瓦片4上运行,并且彼此交换数据,从而一起操作来整体实现整个程序。例如,程序可以包括包含神经网络的机器学习算法,并且不同的瓦片可以运行代表神经网络的不同顶点的程序部分。程序的不同部分在被编译时被配置成根据合适的同步方案(例如批量同步并行(bsp)、会合或邮箱方法)彼此同步。优选地,使用bsp方案。
66.根据bsp,每个瓦片以交替的方式执行计算阶段和交换阶段。在计算阶段,每个瓦片在瓦片上本地执行一个或多个计算任务,但是不与任何其它瓦片传递其计算的任何结果。在交换阶段,允许每个瓦片与组中的一个或多个其它瓦片交换来自前一计算阶段的一个或多个计算结果,但是直到该瓦片完成其交换阶段才开始新的计算阶段。此外,根据这种形式的bsp原理,在从计算阶段过渡到交换阶段、或者从交换阶段过渡到计算阶段、或者两者的结合点处放置屏障同步。也就是说,要么(a)在允许组中的任何瓦片进行到下一个交换阶段之前,要求所有瓦片完成它们各自的计算阶段,或者(b)在允许组中的任何瓦片进行到下一个计算阶段之前,要求组中的所有瓦片完成它们各自的交换阶段,或者(c)两者。当在此使用时,短语“在计算阶段和交换阶段之间”包含所有这些选项。
67.当根据bsp交换数据时,每个瓦片向同步模块指示其同步状态。一旦确定每个瓦片都准备好发送数据,同步过程将使系统进入交换阶段。在此交换阶段,数据值在瓦片之间移动(实际上是在内存到内存的数据移动中在瓦片的内存之间移动)。在交换阶段,不存在可能导致瓦片程序间并发危险的计算。
68.瓦片之间的数据或代码交换可以通过任何合适的交换机制进行。在我们的专利申请pwf ref 408525ep中描述了由graphcore开发的一种这样的机制,us-20190121387-a1,其内容通过引用并入此发明中。在交换阶段,每个共享元素沿着连接线移动,连接线提供了从瓦片到某个交换路径的出口。在每个时钟周期,共享元素沿其路径移动一定距离(例如以
流水线方式从一个锁存器到另一个锁存器)。当从瓦片发出共享元素时,它不与标识接收瓦片的头部一起发出。相反,接收瓦片知道它将在某个时间期待来自某个传输瓦片的元素。为了在该特定时间接收该元素,交换接收方瓦片控制开关将接收瓦片的输入连接到传输瓦片的交换路径。这被称为“时间确定性”。每个瓦片运行由程序员或编译器练习分配给它的程序,其中程序员或编译器功能知道特定瓦片在特定时间将传输什么,以及接收瓦片在特定时间需要接收什么。为了实现这一点,发送指令被包括在由在每个瓦片上的处理器执行的本地程序中,其中发送指令的执行时间是相对于在计算机中的其它瓦片上执行的其它指令的定时而预先确定的。
69.为了实现时间确定性,编译器基于元素在传输端接收瓦片之间行进所花费的时间(瓦片间延迟)来编译用于瓦片的程序。现在描述编译器编译图表的功能。编译器接收互连节点和链接的图表。节点和链接也可以被称为顶点和边。编译器将图中的函数编译成多个小代码,这些小代码被包含在本地程序中。每个本地程序都被设计为加载到计算机的特定块中。每个程序包括一个或多个小代码,加上每个由指令序列形成的管理子程序。在某些实施例中,编译器生成程序,使得它们在时间上相互链接;也就是说,它们是时间决定的。为此,编译器访问包括瓦片标识符的瓦片数据,这些瓦片标识符指示瓦片的物理相对位置,因此编译器需要理解瓦片间的延迟,以便以时间确定的方式生成本地程序。可以基于瓦片数据来计算延迟。可选地,瓦片数据可以结合数据结构,其中这些延迟可以通过查找表获得。
70.应当理解,图1的布置仅作为示例给出。更一般地,系统100可以在同一芯片2上包括多个处理器模块(处理单元)4,或者分布在多个芯片2上,每个芯片2具有一个或多个处理器模块4。原理上,在同一芯片上有多个处理器模块或者处理器模块分布在多个芯片上的情况下,可以应用这里描述的技术。然而,预期当在芯片上的多个瓦片之间共享数据结构时,使用本文描述的技术将有更大的益处,特别是在每个芯片有大量瓦片的情况下(例如如本文描述的实施例之一中的1216或1280个)。在单个芯片中的大量瓦片之间共享数据结构之后,用于共享数据结构的内存数量已经显著减少,使得芯片之间共享的内存减少相对于所使用的总内存来说可以忽略不计。此外,当在芯片之间共享时,在考虑运行时间成本时,需要考虑芯片之间的总带宽比芯片上的总带宽少的事实。
71.本公开涉及为例如图1所示类型的多瓦片芯片编译代码。为了最大化并行性的优势,许多瓦片可以同时在相同的顶点状态上执行相同的顶点集(计算集)。这要求在这些瓦片上提供必要的代码和数据。然而,这是对内存使用的复制,并且会限制可以在芯片上执行的模型的大小。为了克服这一点,本公开使得能够在运行时在瓦片之间共享某些结构。图5示出了这里讨论的核心原理。这些原理涉及一种用于共享通常总是活动于多个瓦片之间的特定恒定数据块的方法。这样的数据块在这里可以被称为“共享结构”。这样做的预期好处如下。在这种情况下,通常总是活动的数据可以是可执行代码或由可执行代码使用的数据元素,例如常量变量。通常总是活动的数据是只读数据。这种数据例如可以是顶点状态数据。顶点状态可以包含(i)指向数据的指针(这些指针是只读的)和/或(ii)数据(可以是也可以不是只读的)。如下文更全面描述的,对于每个顶点状态结构,执行检查以查看它是否仅包含指针和只读数据。如果有,就是一个要共享的候选数据。根据本文描述的技术,包含可改变的数据的顶点状态结构不适合共享。
72.一个好处是能够共享数据,这些数据以前是不变的,并且总是活动于多个瓦片之
间,因此它只在瓦片上需要它的时候存在。在瓦片上的可用内存稀缺的情况下,当需要共享数据结构时,可以选择该瓦片来接收共享数据结构,而不是一直不断地存储它们。这将释放内存不足的瓦片上的内存容量。共享的数据结构可以被移动到具有更多空闲空间的其它片上进行分配。这种瓦片可以成为主瓦片或存储瓦片,用于将共享结构传输到其它瓦片。
73.本文描述的技术的另一个好处是能够通过存储共享数据的单个副本并在需要时将其广播给需要相同数据的那些瓦片来减少跨瓦片的数据复制。
74.应当注意,当用于数据的多播交换时,这里描述的系统具有特别的优势,其中在同步的一组瓦片的相同交换阶段期间,共享数据结构从主瓦片发送到多个接收瓦片。也就是说,当需要只读数据元素时共享它们,而不是在每个瓦片上存储副本,随着接收数据的瓦片数量的增加,这变得更加有益。
75.还要注意,当在交换阶段期间共享多个只读数据元素时,可以提供一个或多个只读数据元素,以在紧随共享数据元素的交换阶段之后的计算阶段中使用。然而,一个或多个只读数据元素可以被提供用于计算阶段,该计算阶段不紧接在数据元素被共享的交换阶段之后。例如,在交换阶段,一行代码可以在主瓦片和一个或多个接收瓦片之间共享。在一些情况下,代码可以定义要在计算阶段运行的程序,该计算阶段不紧接在一个或多个接收瓦片处接收代码的交换阶段之后。请注意,共享只读数据元素之前的交换-计算周期越少,存储优势就越显著。
76.总之,本技术使得能够在瓦片上交换瓦片之间的数据所需的处理周期与存储始终有效的数据所需的内存容量之间进行折衷,目的在于减少最需要的瓦片上的内存资源的负担。
77.图5示出了这里讨论的原理。图5示出了如图1所示的芯片2的一些瓦片4a、4b、4c、4d、4e。根据本文所述的一个特征,芯片的瓦片阵列中的多个瓦片被分配用作跨多个瓦片使用所需的始终有效数据(共享结构)的存储瓦片。例如,在图5中,片4a和4b被分配为存储片。它们在这里可以被称为主瓦片。应当理解,术语“主瓦片”并不意味着任何特定的分级或控制功能,而仅仅意味着这些瓦片是用于可以在系统2中的其它瓦片中使用的始终有效数据的存储瓦片。每个主瓦片都有一个内存。在图5中,瓦片4a被示为具有内存22a,瓦片4b被示为具有内存22b。每个内存包括不同的部分或区域,这将在后面讨论。内存的某些部分可以被分配用于存储始终有效数据55a、55b,这些数据可以与芯片2中的其它瓦片共享。当本地瓦片(例如,分别为4a或4b)正在执行其处理功能时,内存的某些其它部分或区域可以被分配以仅在操作中使用。也就是说,每个瓦片上的内存22a、22b可以保存可能与其它瓦片共享的始终有效数据和可能仅在该瓦片上使用的始终有效数据的混合。在内存中也有一定量的地址空间被分配用于写入和读取已经由本地瓦片处理的变量。可用于交换的始终有效的数据可以通过在芯片2上实现的交换机制复制到其它瓦片上,而不是永久存储在每个瓦片的二进制代码中。例如,箭头100c表示来自内存22a的一部分数据55a通过芯片的交换机制被提供给另一个瓦片4c的情况。类似地,箭头100d表示与替代瓦片4d共享数据55a的相同部分,而箭头100e示出与另一替代瓦片4e共享数据55a的该部分。箭头只是示意性的,在实际实施例中,共享是通过互连6进行的。注意,来自内存22b的数据55b的部分可以类似地交换。还要注意,内存22a的不同部分可以由不同的瓦片共享(它可能不总是广播给瓦片4c、4d、4e等的相同部分)。还要注意的是,尽管图5中仅示出了五个瓦片,但是实际上,如参考图1所讨
论的,该阵列可以具有许多瓦片,其中少量瓦片被分配为主(存储)瓦片,而另一组瓦片被分配用于在需要时接收始终活跃数据。在这种情况下,少量的瓦片被认为是两个或三个,但是可以是任何数量,只要它不是任何特定芯片上的阵列中的完整瓦片集合。一般来说,除非芯片上少于三分之一的瓦片总数被指定为存储瓦片,并且剩余瓦片被指定为接收瓦片,否则是没有用的。
78.通过不要求在可能需要这些项目的芯片的每个瓦片中总的始终有效的数据可用,可以减少在程序执行中的任何时刻用于存储始终有效的数据的存储量。这使得更大的模型可以安装在一个芯片上,而不增加模型所需的瓦片数量或存储容量。
79.交换机制使用包括一组指令的交换代码序列,该交换代码序列在每个瓦片4内的本地程序中提供。每次与芯片上的另一个瓦片交换数据时,该交换代码序列将由瓦片的执行单元18执行。要共享的数据可以是本地处理的输出(结果),和/或这里描述的共享结构。瓦片之间的数据交换是通过互连6进行的。如本文所述,在编译时确定存储接收数据的内存中的地址。注意,交换序列具有用于将数据从存储瓦片传输到接收瓦片的代码。接收瓦片上的交换码用于使数据能够被接收。注意,本地程序中交换代码的位置也是编译器在编译时的责任。当编译并存储在芯片上的代码用于执行本文所讨论的图表形式的模型时,始终有效的数据可以包括以下一个或多个:
80.主机和全局交换数据包报头;
81.堆栈;
82.顶点实例;
83.复制描述符;
84.向量列表描述符;
85.顶点字段数据;
86.控制代码;
87.顶点代码;
88.内部和主机交换代码。
89.这些中的每一个可能具有不同的内存存储需求,例如需要不同数量的字节。
90.在下文中,在共享顶点代码、顶点状态和控制代码的类别的上下文中描述本技术。容易理解的是,这里描述的技术也可以应用于内存中其它类型的始终有效的数据。
91.如此处更详细描述的,顶点代码是为添加到图中的小代码生成的代码,并由添加到计算集合中的顶点使用。每个瓦片上实例化的每个顶点都需要顶点代码的一个副本。
92.顶点状态定义了每个瓦片上顶点类实例化的成员。
93.控制代码包括为运行计算集中的所有顶点、处理控制流以及在控制程序内执行其它控制功能而生成的代码,该控制程序构成每个瓦片上的局部程序的一部分。如前所述,术语“共享结构”在此用于表示在瓦片之间交换的始终有效的数据项。也就是说,共享结构可以在接收瓦片需要时从主(存储)瓦片之一传输到一个或多个接收瓦片。在编译时确定接收瓦片需要共享结构的时间。请注意,这不是绝对时间,而是相对于在接收瓦片上运行的程序的其它方面的时间。编译器了解程序在所有瓦片上的运行顺序,因此可以在适当的时间安排共享结构的交换。
94.当编译器为特定模型编译程序树时,它可以在程序树内的点引入共享结构交换代
码序列。这种共享结构交换代码序列使得共享结构能够在程序中的该点被交换。在修改程序树并试图在确定在每个瓦片上存储相关共享结构将增加总的最大有效内存的点处插入新的共享结构交换代码序列之前,可以执行程序树的有效性分析。也就是说,通过将共享结构的大小与用于传输和接收它的交换代码序列的大小进行比较,确定可以实现整个程序(跨所有瓦片)的最大有效内存的总体减少。这里注意“大小”表示在内存中存储共享结构所需的字节数。
95.通过使用这里所称的“相等地址约束”,可以增加跨瓦片共有的数据量(即,通过增加共享结构的大小)。
96.图3示出了只读数据,例如代码序列,其包括例如第一指针p1和第二指针p2。可以理解,两个指针是举例,也可以有一个或多个指针。每个指针可能有四个字节长。应该理解,指针可以是任何类型或任何长度。指针的不同格式将在后面讨论。只读数据可以是安装在主瓦片4a上的内存22a的一部分中的共享结构55a。当代码要在一组接收瓦片上使用时,交换代码序列由瓦片4a上的执行单元执行,以将共享结构55a传输到(在这种情况下作为示例示出)接收瓦片4b和4c。代码可以被接收并安装在瓦片4b中的addri(地址i)。代码可以被安装在瓦片4c中的addrj(地址j)处。
97.注意,如果已经为每个接受瓦片编译的本地程序了解在哪里定位代码以执行它,则没有必要将输入的只读数据(例如代码部分)存储在每个接受瓦片的相同地址。然而,当代码包含一个或多个指针时,如在本示例中,这些指针可以寻址代码要使用的变量。图3显示了四个独立的变量(var1、var2、var3、var4),其中var1和var2位于瓦片4b上,var3和var4位于瓦片4c上。变量不在共享结构中,而是从结构指向变量。变量不需要具有相同的值或大小。
98.对变量var1和var3应用相等地址约束确保它们被分配在相同的地址。因此,如果var1存储在瓦片4b中的addr1处,那么var3也存储在瓦片4c中的addr1处。共享结构中的一个或多个相同的指针可以用于引用两者。相应地,var2和var4可以被地址约束和指向。
99.例如,指针p1可以寻址变量var1,指针p2可以寻址变量var2。更复杂的指针格式将在后面讨论。如果应用相等地址约束,变量var1被存储在瓦片4b中的某个地址,并且var 3被约束为保存在瓦片4c中的相同地址。例如,addr1可用于在两个瓦片中存储var1/var 3。请注意,所有瓦片都有一个通用的寻址策略。类似地,变量var2可以存储在瓦片4b中的addr2处,而变量var4可以存储在瓦片4c中的addr2处。因此,无论代码部分是在瓦片4b还是在瓦片4c上运行,指针p1总是指向addr1处的变量var1/var3,指针p2总是指向addr2处的变量var2/var4。
100.例如,一段顶点代码中的指令序列原理上可以用在芯片内负责执行顶点代码的所有瓦片上。顶点状态或控制代码可以共享,使用指针访问数据(变量)。
101.在共享顶点状态的情况下,变量将表示顶点操作的数据(即,它通过图表的边连接到的变量)。在共享控制代码的情况下,该变量可以表示顶点状态(可能作为共享控制代码出现的运行指令指向顶点状态)。
102.不同的共享结构可以用于代码和数据,因为内存布局的其它约束在某些情况下可能意味着不可能总是将它们存储在一起。控制代码以及它所引用的顶点状态有可能被共享,在这种情况下,共享控制代码中的指针将指向顶点状态共享结构内部的地址,并且顶点
状态共享结构将受到相等地址约束。
103.变量可以是受到相等地址约束的,只要该变量还没有与任何其它变量相等的地址约束,该其它变量的瓦片与要约束的变量集的瓦片集相交。
104.例如,参见图4。在图4a中,第一组瓦片显示为瓦片1、瓦片2和瓦片3。变量a在瓦片1上,变量b在瓦片2上,变量c在瓦片3上。变量a、b和c表示一组被相等地址约束的变量。如果变量a、b和c在相同的相等地址集合中,则每个相应瓦片上的每个变量的地址被约束为相同。这显示在图4中的addr1上。
105.现在考虑存储在瓦片1、4和5上的一组附加变量d、e和f(见图4a)。类似的限制也适用。在这种情况下,这两个相等的地址集可能存在,因为只有变量a和d在同一瓦片上,使得它们可以被分配在不同的地址,而变量b和c以及e和f被约束到与它们的瓦片1代表相同的地址(在瓦片1中以虚线示出)。
106.图4示出了两组变量,其中瓦片内存的地址空间中的位置由相关矩形的位置示出。变量a、b和c是地址受限的。因此,在集合1中,变量a在瓦片1上的地址addr1处,变量b在瓦片2上的地址addr1处,变量c在瓦片3上的地址addr1处。在第二组中,变量d、e和f被约束为分配在相同的地址addr2。由于a和d在相同的瓦片1上,它们不能被分配在相同的地址,因此a、b和c的地址必须不同于d、e和f。
107.然而,考虑图4b中的另一种情况,其中第一个变量集是瓦片1上的a、瓦片2上的b和瓦片3上的c,第二个变量集是瓦片1上的d、瓦片2上的b和瓦片3上的c。请注意,在图4b中,不可能对这两个集合进行相等地址约束,因为变量b和c需要位于相同的地址,这将导致变量a和d也需要位于相同的地址。然而,由于变量a和d都位于瓦片1,这将导致冲突。
108.注意,在分配之前,地址addr 1和2不是预定的地址位置。然而,在编译器为整个代码分配完地址后,它们将变成预定的地址位置。同时,它们被标记为受到地址约束。
109.顶点状态中有几种可以被约束的指针格式。如果它们可以被约束,顶点状态可以形成共享结构的一部分。
110.顶点状态结构存储在内存中。它可能包含一个指针。在这种情况下,在顶点状态结构内部的某个偏移量处,该内存位置的值将是指针所指向的内存块的地址。
111.指针格式的最简单形式是一维向量。这些只是指向一个连续的内存块。为了共享它们,这个内存块必须受到相等地址约束。例如参见图6,其中指针pn指向形成内存22a的一部分的内存块的位置addrn。addrn保存变量var。
112.指针的另一种格式是二维向量,它包含额外的方向级别。基指针pb指向其它指针p1、p2等的连续块b。参见图7,其中pb标识地址addrq处的内存位置,其标识块b的基底。例如,上述顶点字段数据可以包括指针块。为了共享这一点,指针的连续块需要被地址约束。注意,顶点代码可以被共享和/或顶点状态可以被共享。是否共享顶点状态的选择与是否共享顶点代码无关。
113.指针的另一种形式是数据结构,例如向量列表,其包含额外的方向级别(类似于上面提到的二维向量),但是其中额外的级别也是内存的连续块——参见图8。也就是说,第一指针p
v1
(通过寄存器26)指向的内存块addrv是间接层,其包含到由基指针p
b1
表示的第二级内存addrw中的偏移量。外部内存位置的位置被烘焙到顶点状态本身中,这意味着该层也必须被约束,否则共享的内部状态将不同。向量列表有两个指针存储在顶点状态中。一个是指
向包含偏移量的内存块的指针p
r1
,另一个是添加偏移量的基指针p
b1
,以形成向量列表所引用的变量的地址。为了共享包含向量列表的顶点状态,包含偏移量的内存块的地址需要受到相同地址约束,并且基指针指向的内存位置也必须受到相同地址约束。
114.如果不可能创建一个共享结构来表示其中约束了一组变量的一段顶点状态,则编译器将试图寻址约束那些变量的一个更小的子集,以将顶点状态约束成两个相同的段。这可以不止一次地提供包含局部瓦片程序的顶点状态的共享结构。
115.顶点代码也可以被编译成共享结构。与顶点状态不同,在顶点状态中,每个顶点对于计算集中的一个顶点的单个指示是唯一的,在程序的整个生命周期中重复使用顶点代码。顶点代码可以通过以下方式形成共享结构。
116.一种方法是,所有顶点代码都存储在单个主文件(存储瓦片)上,并且动态地建立共享结构,该共享结构包含在共享结构的生命周期期间所需的顶点代码。
117.按照另一种方式,在编译时构建共享结构,复制在多个计算集中使用的任何顶点代码。
118.第二种方法比第一种方法简单,尽管它在整个芯片上使用了更多的内存。然而,已经发现复制顶点代码的额外内存的使用对简单性没有显著影响。每个顶点都有一个类型,类型定义了顶点运行时的输入和输出以及要执行的代码。特定类型的每个实例有时被称为小代码。多个顶点可以有相同的小代码。每个顶点都有一个单独的顶点状态结构,但是共享相同小代码的所有顶点都使用相同的代码。
119.考虑有两个计算集的情况,计算集a包含c0和c1类型的顶点,计算集b包含c0和c2类型的顶点。可以在每个计算集之前插入共享结构副本,包括在计算集a之前的共享结构副本中的c0和c1,以及计算集b之前的共享结构副本中的c0和c2。在这种情况下,在主瓦片上创建两个共享结构,一个包含c0和c1,一个包含c0和c2,即c0被复制并在主瓦片上存储两次。复制c0的好处是,每个共享结构副本所需的所有顶点代码都在一个连续块中,因此复制起来很简单。
120.通过这种方式,代码可以被共享,因此代码通过指针引用的所有内容要么也是共享的,要么受到相同地址约束。
121.控制代码包括不同的程序类型,根据要实现的功能具有管理程序代码。对于每个不同类型的控制代码程序,管理程序代码的每个不同排列被放置在共享结构内,并且每个瓦片上的控制程序使用调用指令分支到正确的偏移,并且在共享程序结束时分支回控制程序一次。
122.在某些应用中,每个程序可能只包含少量的汇编代码。例如,在计算机中运行顶点所需的控制代码可能只有四条指令(这只是一个例子,也可以使用其它数量的指令)。
123.在这种情况下,通过与折叠在一起的连续程序共享程序可以获得更大的好处。这可以通过获得两个共享程序之间所有瓦片的并集来实现。
124.图14示出了可以在两个瓦片中的每一个上实现的逻辑流程的示例。在这种情况下,瓦片4a是主瓦片,瓦片4c是几个接收瓦片中的一个。瓦片4c负责执行计算集,例如每个计算集可以是一组顶点。相同的顶点可以在不同的顶点状态下运行。这些计算集可以预编译到单个瓦片上,也可以从主瓦片共享。可以共享用于控制运行计算集合的顶点和/或顶点状态的执行的控制代码。根据这里的共享结构范例,它首先需要从主瓦片接收这些共享结
构。接收瓦片4c首先执行做交换步骤,该步骤使用交换代码来接收第一共享结构,例如顶点状态或控制代码。计算集合cs1、cs2在第一顶点状态的控制代码的控制下被执行,并且结果被复制到本地(在瓦片上)内存。随后,同一瓦片可能需要对表示第二顶点状态的不同数据集执行相同的计算集cs1、cs2。执行另一个做交换步骤以接收第二顶点状态的第二共享数据结构。请注意,当需要时,共享数据结构可以在每个执行阶段之前交换,或者可能有一个前瞻功能,该功能提前于需要时几个周期接收计算集。
125.主瓦片4a被示为具有一系列做交换步骤,每个步骤向接收瓦片4c发送始终有效数据。例如,共享数据结构在编译时确定的接收瓦片需要它们时被传输。实际上,主瓦片也将执行附加功能,但是出于本说明书的目的,其核心功能是向接收瓦片传输共享结构。
126.注意,在主瓦片中执行的交换相对于接收瓦片中的计算集合的执行的定时是由编译器在编译时并且在每个本地程序被存储到相应瓦片中之前确定的。
127.如上所述,图2给出了处理器模块或瓦片(例如瓦片4a)的示意性示例。在多个瓦片的情况下,在一些实施例中,每个瓦片可以包括处理器模块4的相同实例。然而,请注意,如本文所述,内存22a中保存的存储数据在瓦片之间可能不同。处理单元10包括执行单元18、一个或多个寄存器文件26、指令获取级(未示出)和指令解码级(未示出)。
128.内存22a包括多个独立的内存体或存储区230、231、232等。在实施例中,每个内存体23的大小是16kb,但是可以实现任何合适的大小。如上所述,内存22a的某些区域被安排成存储将由执行单元18执行的代码操作的数据,以及由执行单元18执行的代码执行的操作产生的数据。内存22a的其它区域用于存储代码本身。内存的其它区域可以存储共享结构。执行单元18被安排成接收和执行由获取级从内存22a获取并由解码级解码的机器代码指令27。执行单元18被配置成识别定义指令类型的某个指令集,每个指令类型由不同的相应操作码定义,并且包括对应的零个或多个操作数字段。发布到执行单元18中的每个指令27是由执行单元18的指令集定义的这些指令类型之一的实例。
129.这些指令类型可以包括内存访问指令(加载和存储类型指令)、逻辑指令(整数算术指令和浮点指令)和控制指令(用于管理本地程序)。执行单元18包括用于执行内存访问指令实例的加载-存储单元(lsu)55、用于执行整数算术指令实例的整数算术逻辑单元(ialu)56和用于执行浮点指令实例的浮点逻辑单元(fpu)59。执行单元18包括用于执行控制指令实例的附加单元(未示出)。执行单元18包括硬件逻辑,其被配置为由每个指令的操作码触发,以执行与被执行指令的类型相关联的相应操作。
130.每个内存访问指令在被执行时触发加载-存储单元(lsu)55执行至少一个加载操作或一个存储操作,这取决于内存访问指令的特定类型。加载操作包括将数据从内存22a中的源地址加载到寄存器文件26之一中的至少一个寄存器中。源内存地址和寄存器位置由指令的操作码指定。在实施例中,如上所述,通过指针来指定源内存地址(即,指令的操作码标识其中保存源内存地址的寄存器文件26之一中的寄存器,而不是直接指定内存地址)。存储操作包括将来自至少一个寄存器文件26的数据存储到内存22a中的目标地址。目标内存地址和寄存器位置由指令的操作码指定。在实施例中,目标内存地址通过指针来指定(即,指令的操作码标识寄存器文件26之一中保存目标内存地址的寄存器)。如上所述,不同的指针格式可以具有不同的方向级别。
131.诸如浮点和整数算术指令的逻辑指令分别触发浮点单元(fpu)59或整数逻辑单元
(ialu)56,以执行映射到操作码的一种数学运算。指令的操作码可以取一个或多个源操作码和一个或多个目标操作数,源操作数指定从中取值进行运算的一个或多个源寄存器,目标操作数指定将指令执行的运算的一个或多个结果放入其中的一个或多个目标寄存器。例如,一个简单的加法指令通常需要至少三个操作码:两个源和一个目标。当被执行时,它使执行单元18获取两个源寄存器中的值,将它们相加,并将结果和放入目标寄存器中。类似的逻辑适用于例如简单的减法、乘法和除法指令。各种其它类型的逻辑指令也可以包括在指令集中,例如向量乘法、矩阵乘法和卷积指令。如上所述,执行控制指令来管理本地程序。
132.因此,在处理模块上运行的代码可以用于将数据从内存22a加载到寄存器文件26中,对寄存器文件26中的数据执行操作,将结果存储回内存22a,并管理程序流。
133.这些指令在一系列指令发布周期内执行。在每个指令发布周期中,获取级向执行单元18提供至少一条指令29用于执行。在实施例中,执行单元18可以是流水线式的。此外,在一些实施例中,执行单元18可以包括多个并行流水线。
134.在实施例中,处理单元10可以是多线程处理单元,也称为桶线程处理单元。这意味着获取级被配置成从不同的程序线程获取指令,并且通常根据循环或加权循环调度,在不同的时隙中通过执行单元18在时间上交织它们。更通常地,执行单元18可以包括单个流水线或者甚至不需要被流水线化,并且处理单元10可以是多线程的或者被配置为仅执行单个程序线程。
135.图9示出了用于将高级的、基于图表的程序编译成低级机器代码程序以在计算机系统100上运行的装置,例如关于图1和2所描述的。
136.该装置包括计算机504,其可以采取服务器的形式,包括在一个或多个地理位置的一个或多个服务器单元,或者一个或多个用户终端,例如台式计算机,或者服务器和一个或多个用户终端的组合。计算机504被布置成运行编译器508,该编译器508采取存储在计算机504的计算机可读内存(例如,一个或多个内部和/或外部磁盘驱动器和/或eeproms)上的软件的形式,并且被布置成在计算机504的一个或多个处理器(例如,一个或多个cpu)上运行。当在计算机504上运行时,编译器508被安排成接收输入图502,并编译输入图502,以生成可执行程序506,然后该可执行程序506可以在诸如关于图1和2描述的多瓦片计算系统100上运行。
137.图10显示了一个输入图示例。输入图502包括多个数据节点512、多个计算顶点514和多个有向边516,每个有向边连接在相应的一对数据节点和顶点之间。
138.每个数据节点512代表一个数据元素,在这里意味着一个变量。注意,在计算或计算机科学的语境中,术语“变量”不一定意味着变量值必须在运行时改变:它可以变化或保持不变(即,在计算的意义上,常数可以被认为是一种变量)。这就是这里使用的术语“变量”的含义。为了避免与其它语境混淆,也可以采用术语“数据元素”。还要注意,这里所指的数据元素或变量指的是在任何一个时刻从该对象的特定值中提取的数字数据对象或结构。例如,变量或数据元素可以是在高级语言中标记为var1的数字对象,它可能碰巧取一个常数值,或者其值在编译程序运行期间可能变化一次或多次。
139.每条边516表示从计算顶点514到数据节点512的输出,反之亦然。每个计算顶点514(即,计算节点)表示要在从一个或多个数据节点512输出的边上接收的一个或多个输入上执行的一个或多个计算,其结果被输出到来自相应计算顶点514的输出边上的一个或多
个数据节点512(通常是一个或多个其它数据节点)。应当理解,图10中所示的特定图拓扑仅仅是示例性的,实际上,在潜在的更复杂的配置中,图502还倾向于包括更多的节点512、边516和顶点514。出于说明的目的,图10可以被认为示出了图表的示例片段。还要注意,虽然输入图502被示意性地示出为源自计算机504外部,这是一种可能性,但是它也可以源自同一计算机504内部(例如,已经使用合适的创作工具(未示出)创作和/或存储在其上)。
140.输入图502可以由人类开发者设计,以实现开发者希望的数据流和计算(这里的“开发者”可以是一个人或一个团队)。例如,图502可以包括作为神经网络一部分的张量流。注意,在图502实现神经网络的情况下,神经网络的每个节点或“神经元”可以包括图502(即程序的编程结构)的一个或多个计算顶点514和一个或多个数据节点512。即,可以在比程序的图502更高的抽象层次上描述神经网络的拓扑。
141.图11示出了特定计算顶点514的示例,该计算顶点514具有来自表示第一变量a的数据节点512的输入x,以及到表示第二变量b的第二数据节点512的输出y。如所示出的,顶点518可以包括一个或多个小代码518。小代码是一种特殊类型的线程,有时也被称为“原子”线程。其具有从线程开始(从被启动时)执行所需的所有输入信息,即,在被启动后,它不从程序的任何其它部分或从内存获取任何输入。此外,程序的其它部分不会使用线程的任何输出(结果),直到线程终止(完成)。除非遇到错误,否则它一定会完成。一些文献还将小代码定义为无状态的,即,如果运行两次,它不能从第一次运行中继承任何信息,但是这里不一定采用这个额外的定义。小代码是划分图502的便利方式,这使得顶点514在被编译器508降低时更容易在不同的线程、瓦片4和/或芯片2之间分离。在实施例中,每个顶点514可以仅由小代码形成。然而,这并非在所有实施例中都是必要的,并且更一般地,顶点518可以表示代码的任何部分。
142.还要注意,在一些表示中,相同的图502可以等效地由用边彼此连接的计算节点(顶点)来表示,并且数据元素(变量)被指示为边上的注释,而不是明确地指示为数据节点512。这显示在图12的左侧。可以等效地使用任一种表示。可以理解,边上的数据注释是描述数据节点的示意性等效方式,并且它们在任何给定工具中以任何给定视图呈现给人类开发者的方式不排除这样的事实,即实质上,可以被称为数据节点的数据项仍然存在于图的底层计算结构中,并且仍然可以读取到这里公开的数据节点512上。换句话说,由数据注释的边的表示是一种被认为是表示数据节点的方式,该数据节点具有从一个计算顶点到另一个顶点的输入边和输出边(参见图12)。这里通过解释概念的方式采用后一种表示,但是可以理解,实质上,这里要求保护的图指的是底层计算图,而不是向人类呈现的概念或图表方式。即图502指的是包括函数和通过函数的数据流的底层数据结构;其中这些函数可被称为计算顶点514,并且输入到这些函数或来自这些函数的数据可被称为数据节点512,流入或流出这些函数/顶点的任何逻辑数据流被称为边。
143.当编译器508编译图502,将其降低以在处理器模块4的执行单元上运行时,输入边516的低级实现可以包括由加载类型指令执行的加载操作,并且输出边516的低级实现可以包括由存储类型指令执行的存储操作。
144.根据本公开的实施例,编译器508包括分配器511,分配器511包括约束求解器,约束求解器被配置成在编译图502时应用一个或多个约束。
145.作为高级图502的编译的一部分,编译器508降低该图,例如降低到芯片2上的单个
瓦片4a、4b、4c等。各个瓦片具有为高级图中描述的边516分配的变量。每个变量被分配给内存22a内的存储空间的连续部分,其可以是内存的一个或多个连续字节(即,给定变量不能被分配给内存的非连续部分)。还要注意,任何地方对变量的引用都不排除常量这个选择。术语“数据元素”可以在这里的任何地方用来代替术语“变量”。因此,“数据元素”或“变量”可以包括代码。可能有不同种类的变量。例如,可以在用户提供的高级图中存在的变量和编译器操作的低级图中存在的变量之间进行区分。
146.例如,在用户创建的输入图中,没有包含代码的变量。用户通过选择要使用的小代码来指定要运行的代码,但是该代码的存储是隐式的——不可能在高级图中访问它。作为编译过程的一部分,高级输入图被转换成低级图,其中任何需要存储的内容都可以被表示为变量,包括顶点状态和顶点代码。
147.图13示出了示例方法的流程图,该方法可以由分配器511中的约束求解器执行,以求解对应于边512的不同变量的约束,并将它们分配给内存22中的相应区域。简而言之,该方法包括按顺序遍历所有变量的列表,并且对于每个变量,将它分配到它不会与列表中任何先前分配的变量冲突的内存的一部分中。
148.实际的内存地址是在编译过程的末尾逐步分配的。为了分配地址,首先定义约束。如果确定共享数据结构(而不是跨处理单元复制),则可以为其提供一个或多个地址约束。请注意,在共享数据结构(例如函数调用或其它跳转)包含指向其它内容的指针的情况下,它所指向的变量也必须被约束在代码共享的所有瓦片上的相同地址处。
149.为了促进更大的共享,相等地址约束被添加到分配器中,该分配器指定了必须被分配在相同地址的跨多个瓦片的一组变量。
150.在步骤s0中,具有相等地址约束的所有变量首先被分配到瓦片上,并且无约束变量随后被分配到每个瓦片上。
151.相等地址约束变量集被视为单个变量,该单个变量具有该集合中每个瓦片上所有变量的所有同等类别的干涉的并集,以及与它们共享元素约束的变量的干涉的并集,等等。同等类别将在后面讨论。从这一点开始,对于所有相等地址约束变量集,分配以类似的方式进行。一旦分配了所有受约束的变量,在步骤s5中,这些分配被分发给单独的瓦片分配器,并且对于剩余的不受约束的变量,继续每个瓦片的分配,如下所述。
152.在步骤s10,用于每个瓦片的方法包括为该瓦片的无约束变量分配顺序。任何顺序都可以。在实施例中,特定的顺序可以用作优化,以改善编译时间和/或分配质量(即,所需的瓦片内存的量)。然而,无论使用什么样的顺序,该方法仍然可以奏效,只是比使用其中一种优化方式要慢一些。例如,顺序可以是随机的。因此,无论选择什么顺序,步骤s10都会产生等待分配的变量的有序列表。
153.在步骤s20,该方法包括选择列表中的第一个无约束变量来开始分配。在步骤s30,该方法包括在内存22a中为所考虑的当前变量寻找空间,该变量在此时(第一次迭代)是列表中的第一个变量。注意,此时受约束变量已经被分配到内存位置。在为第一个变量选择内存区域时,需要考虑任何受到相等地址约束的变量分配。第一变量可以具有其它非关系约束,例如在指定类型的内存中选择地址范围。在步骤s40,该方法包括将考虑中的当前变量分配给内存22中的选定区域。
154.在步骤s50,该方法包括确定在步骤s40分配的变量是否是列表中的最后一个。如
果没有,该方法返回到步骤s30,寻找用于分配顺序列表中下一个变量的内存区域22a。现在不仅需要考虑任何非关系约束,还需要考虑任何关系约束。例如,关系约束可以是两个变量的数据不能同时从同一内存体23加载或存储到同一内存体23。在实施例中,这可以被实现为一种约束,即如果变量的数据在至少一些相同的时间内是“有效的”,即对于重叠的时间段,则变量不能被分配给相同的内存体。这里所说的变量将是“有效的”,是指在运行期间,变量的数据被写入内存22a和它被程序读取之间的时间。为了评估是否满足该约束,约束求解器511可以执行“有效性”分析,以确定在程序被编译和运行之后哪些变量将在什么时间是有效的,以及哪些变量将在重叠的时间是有效的。如果两个变量在重叠的时间内有效,那么它们可以被认为是相互冲突或干扰的(在某种意义上,如果编译器508试图将它们分配给相同的内存体23,那么内存体23的访问逻辑不能同时为它们服务)。
155.因此,在步骤s30,对于有序列表中除了第一个变量之外的每个变量,该方法包括为该变量寻找不与迄今为止分配的任何其它变量(有序列表中的任何其它先前的变量)冲突(干扰)的内存区域22a。即,它在内存体23中找到一个地址范围,该地址范围不与迄今为止分配的任何其它变量共享,该变量至少在一些相同的时间内是有效的。换句话说,列表中的当前变量被分配给内存22a中的剩余地址空间(尚未分配),该剩余地址空间不属于任何其它冲突的、已经分配的变量的同一内存体23。在步骤s40,该方法包括将列表中的当前变量分配给内存22a中的选定区域。
156.如果在步骤s50确定已经分配了列表中的最后一个变量,则该方法进行到步骤s70,在步骤s70完成对该瓦片的编译。当所有的瓦片都已完成时,可以生成可执行程序,其中分配的内存地址空间用于分别存储每个变量的数据,并且在运行时需要时将从该可执行程序加载数据(并且如果需要的话可能存储回去)。编译当然可以包括本领域技术人员熟悉的其它常规编译步骤。
157.如上所述,在实施例中,在步骤s10中确定的有序列表可以简单地采用任何顺序。然而,在优选实施例中,选择特定的顺序来试图优化约束求解过程的速度。这种优化可以包括多种技术中的任何一种、多种或全部。
158.在实施例中,步骤s10可以包括根据一个或多个特定度量对变量进行排序。例如,对变量进行排序的一种方式是根据大小(即,在内存中占用的空间量),较大的变量在列表的顶部,而较小的变量在列表的底部。这意味着先分配较大的变量,后分配较小的变量。这往往会更快,并改进打包,因为与按反过来的顺序分配相比,有更多的机会将较小的变量放在较大的变量周围。出于类似的原因,对变量进行排序的另一种方式是根据它们有效的时间,有效时间较长的变量位于列表的顶部,因此首先被分配,而有效时间较短的变量位于列表的较低位置,在有效时间较长的变量之后被分配。用于排序变量的另一个示例度量是根据它们将有效的程序行范围的大小,同样出于类似的原因(首先分配最长有效期的变量,然后在它们周围插入较短有效期的变量)。
159.在实施例中,可以使用这些度量和/或其它度量中的两个或更多个的组合来对变量进行排序;例如,首先按大小排序,然后按有效时间排序相同大小的任何变量,或者反过来。
160.作为上述的替代或补充,步骤s10的排序可以包括将变量分组为“同等类别”。每个同等类别都是一组变量,每个变量都会干扰一些或所有相同的其它变量。例如,如果变量a
和b都干扰变量d、c和e,那么a和b可以被放置在一个同等类别中,而d、c和e可以被放置在另一个同等类别中(注意,仅仅因为a和b在时间上与c重叠,并不一定意味着a和b彼此重叠)。在一个结构化的程序中,往往会有多组变量干扰相同的其它变量。在实施例中,排序可以包括根据诸如类别中变量的数量(最大的类优先)、以字节为单位的类的总大小(最大的类优先)、类跨越的总有效时间(最长的类优先)等度量对同等类别进行排序。分组为同等类别的优点在于,它减少了约束求解器过程的处理时间,因为这意味着分配器511中的约束求解器不必在每次分配类别中的每个单独变量时重新计算干扰信息。
161.在实施例中,变量也可以在同等类别内排序,例如再次根据诸如变量大小或有效性时间的度量。因此,变量可以首先按类别排序,然后按每个类中的一个或多个度量排序。
162.在实施例中,约束求解器中的可变约束构建器利用所施加的关系约束类型来构建成对约束。非关系约束信息也由约束构建器从高级约束描述中提取。
163.图的有效性分析将受到类似影响的变量分组为同等类别。这减少了分别保存每个变量的有效性信息的负担。有效性分析还构建了一个表,其中列出了哪些同等类别可以相互干扰,哪些不能相互干扰(即哪些变量同时是有效的和不有效的)。内存分配器使用这些信息以及变量的约束信息。
164.在实施例中,对于每个瓦片,约束求解器511中的内存分配器功能遵循以下步骤:
165.i.为受到相等地址约束的变量接收受到相等地址约束的分配。
166.ii.根据某种度量对同等类别进行排序。常用的度量是同等类别中总变量的大小,或者它干扰的类别的数量。
167.iii.根据某种度量对每个同等类别中的变量进行排序。常用的度量是尺寸和排列。
168.iv.变量分配的排序按照步骤i和步骤ii确定的同等类别的排序进行。
169.v.对于排序后的同等类别中的每个变量v,在内存中寻找空间,使得该变量上的所有约束都得到满足,并且v不会与已经分配给同等类别的任何变量冲突,从而干扰v所属的类别。变量上的约束包括所有关系约束和非关系约束。对于关系约束,这意味着如果v与v1有关系约束,并且v1已经被分配,则关系约束必须与非关系约束一起被满足。如果没有与v共享关系约束的变量被分配,那么只满足非关系约束。
170.应当理解,上述实施例仅通过示例的方式进行了描述。一旦给出本文的公开内容,所公开的技术的其它变型或使用情况对于本领域技术人员来说将变得显而易见。本公开的范围不受所描述的实施例的限制,而是仅受所附权利要求的限制。
再多了解一些

本文用于创业者技术爱好者查询,仅供学习研究,如用于商业用途,请联系技术所有人。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表