首页 理论教育PCIExpress体系结构导读:软件预读机制的改进程序分析

PCIExpress体系结构导读:软件预读机制的改进程序分析

【摘要】:源代码3-3 软件预读机制的改进程序对于以上这个例子,采用这种预读方法可以有效提高执行效率,对此有兴趣的读者可以对以上几个程序进行简单的对比测试。源代码3-4 软件预读机制的改进程序还可以对ip、数据a和b进行充分预读之后,再一边预读数据,一边计算ip的值,最后计算ip的最终结果。

软件预读机制由来已久,首先实现预读指令的处理器是Motorola的88110处理器,这颗处理器首先实现了“touch load”指令,这条指令是PowerPC处理器dcbt指令[47]的雏形。88110处理器是Motorola第一颗RISC处理器,具有里程碑意义。这颗处理器从内核到外部总线的设计都具有许多亮点,是Motorola对PowerPC架构做出的巨大贡献。PowerPC架构中著名的60X总线也源于88110处理器。

后来绝大多数处理器都采用这类指令进行软件预读,Intel在i486处理器中提出了Dum-my Read指令,这条指令也是后来x86处理器中PREFETCHh指令[48]的雏形。

这些软件预读指令都有一个共同的特点,就是在处理器真正需要数据之前,向存储器发出预读请求,这个预读请求不需要等待数据真正到达存储器之后,就可以执行完毕[49]。从而处理器可以继续执行其他指令,以实现存储器访问与处理器运算同步进行,从而提高了程序的整体执行效率。由此可见,处理器采用软件预读可以有效提高程序的执行效率。下面考虑源代码3-1所示的实例。

源代码3-1 源代码3-1没有采用软件预读机制的程序

这个例子在对数组进行操作时被经常使用,这段源代码的作用是将int类型的数组a和数组b的每一项进行相乘,然后赋值给ip,其中数组a和b都是Cache行对界的。源代码3-1中的程序并没有使用预读机制进行优化,因此这段程序在执行时会因为a[i]和b[i]中的数据不在处理器的Cache中,而必须启动存储器读操作。因此在这段程序在执行过程中,必须要等待存储器中的数据后才能继续,从而降低了程序的执行效率。为此将程序进行改动,如源代码3-2所示。

源代码3-2 采用软件预读机制的程序

以上程序对变量ip赋值之前,首先预读数组a和b,当对变量ip赋值时,数组a和b中的数据已经在Cache中,因而不需要进行再次进行存储器操作,从而在一定程度上提高了代码的执行效率。以上代码仍然并不完美,首先,ip、a[0]和b[0]并没有被预读,其次,在一个处理器中预读是以Cache行为单位进行的,因此对a[0]、a[1]进行预读时都是对同一个Cache行进行预读[50],从而这段代码对同一个Cache行进行了多次预读,结果影响了执行效率。为此再次改动程序,如源代码3-3所示。(www.chuimin.cn)

源代码3-3 软件预读机制的改进程序

对于以上这个例子,采用这种预读方法可以有效提高执行效率,对此有兴趣的读者可以对以上几个程序进行简单的对比测试。但是提醒读者注意,有些较为先进的编译器,可以自动加入这些预读语句,程序员不必手工加入这些预读指令。实际上源代码3-3中的程序还可以进一步优化。这段程序的最终优化如源代码3-4所示。

源代码3-4 软件预读机制的改进程序

还可以对ip、数据a和b进行充分预读之后,再一边预读数据,一边计算ip的值,最后计算ip的最终结果。使用这种方法可以使数据预读和计算充分并行,从而优化了整个任务的执行时间。

由以上程序可以发现,采用软件预读机制可以有效地对矩阵运算进行优化,因为矩阵运算进行数据访问时非常有规律,便于程序员或编译器进行优化,但是并不是所有程序都能如此方便地使用软件预读机制。此外预读指令本身也需要占用一个机器周期,在某些情况下,采用硬件预读机制更为合理。