关于一般建议,例如数据结构选择,访问模式等,已经有很多答案。在这里,我想添加另一个称为软件管道的代码设计模式,该模式利用主动缓存管理。
这个想法是借鉴了其他流水线技术,例如CPU指令流水线。
这种模式最适用于
- 可以细分为合理的多个子步骤S [1],S [2],S [3],...,其执行时间与RAM访问时间大致相当(〜60-70ns)。
- 接受一批输入并对它们执行上述多个步骤以获得结果。
让我们以一个只有一个子过程的简单情况为例。正常情况下,代码需要:
def proc(input):
return sub-step(input))
为了获得更好的性能,您可能希望将多个输入分批传递给该函数,以便分摊函数调用的开销并增加代码缓存的局部性。
def batch_proc(inputs):
results = []
for i in inputs:
// avoids code cache miss, but still suffer data(inputs) miss
results.append(sub-step(i))
return res
但是,如前所述,如果该步骤的执行与RAM访问时间大致相同,则可以将代码进一步改进为以下形式:
def batch_pipelined_proc(inputs):
for i in range(0, len(inputs)-1):
prefetch(inputs[i+1])
# work on current item while [i+1] is flying back from RAM
results.append(sub-step(inputs[i-1]))
results.append(sub-step(inputs[-1]))
执行流程如下所示:
- prefetch(1) 要求CPU将输入[1]预取到高速缓存中,其中预取指令本身需要P个周期并返回,而在后台,输入[1]将在R个周期后到达高速缓存中。
- works_on(0) 在0上冷落并对其进行处理,这需要M
- prefetch(2) 发出另一个读取
- works_on(1) 如果P + R <= M,则在此步骤之前,input [1]应该已经在高速缓存中,因此避免了数据高速缓存未命中
- works_on(2) ...
可能涉及更多的步骤,然后您可以设计一个多阶段管道,只要这些步骤的时间和内存访问延迟匹配,就不会有太多的代码/数据缓存丢失。但是,此过程需要通过许多实验进行调整,以找出正确的步骤分组和预取时间。由于需要付出的努力,它在高性能数据/数据包流处理中得到了更多的采用。在DPDK QoS Enqueue管道设计中可以找到一个很好的生产代码示例:http :
//dpdk.org/doc/guides/prog_guide/qos_framework.html第21.2.4.3。章。排队管道。
可以找到更多信息:
https://software.intel.com/zh-CN/articles/memory-management-for-optimal-performance-on-intel-xeon-phi-coprocessor-alignment-and
http://infolab.stanford.edu/~ullman/dragon/w06/lectures/cs243-lec13-wei.pdf