1

通常,BLAS 子程序是为某个独特的操作定义的。例如,

DAXPY是必然的y <-- ax + y

DSCAL是必然的x = ax

我希望达到的是:

z = ax+byy = ax

我如何“扩展” BLAS 的子程序以便我可以执行上述操作? (这些操作不一定相互遵循)

我试过了:

  • 声明一个虚拟对象,然后DCOPY将虚拟对象设置为所需的向量。像,DCOPY(dummy,x); DSCAL(a,dummy),DCOPY(y,dummy)

  • 创建我自己的 OpenMP 实现

  • DCOPY(y,a*x)使用诸如for y=ax之类的技巧

但问题是,这些方法似乎都没有给我一个确凿的答案,哪个是解决这个问题的最佳方法。我知道我应该“配置文件,配置文件,配置文件”而不是询问,但我已经尝试了所有这些,但是每次我稍微改变向量时,之前最好的方法突然变成最差的方法,反之亦然。

还,

  • 我的目的是尽可能实现最佳性能。
  • 我知道优化这些操作可能不会给我带来太多的性能提升,但我正在尝试尽可能节省每一皮秒。
  • FWIW,我正在链接到英特尔 MKL
4

3 回答 3

2

首先,在您对 y <- ax 的解释中,您可以使用 DCOPY(y,x); 删除一个过度复制;DSCAL(a,y)。

其次,OpenMP 恕我直言,这不是这类问题的解决方案,因为它们是“内存绑定”的。代价在于通过计算和矢量化流水线化内存访问,这通过使用矢量内存访问来使用更多带宽。手动调整的代码应该非常复杂,因为(分支预测、缓存策略、寄存器文件配置等)您需要 R. Clint Whaley 的 Atlas 库之类的东西,它会自动为特定平台生成优化的操作实现。AFAIK,有 BLAST 标准(2001),也许你会发现你提出的操作的类似变体。可能您需要给他们发送电子邮件以将这些操作添加到他们的自动调谐器中。

作为起点,我建议您使用 z = ax+by 的以下实现。在这种情况下,无论如何都会写入 z,只要 x 和 y 是只读的,您可以使用: DCOPY(z,y); DSCAL(b,z); DAXPY(a, x, z);

您还可以阅读有关 ATLAS 项目的文章,其中包含有关代码优化关键方面(madd 操作的存在、缓存特性、寄存器文件配置、指令延迟等)的主要考虑因素,并尝试编写类似代码生成器的东西为您的操作流水线执行各种操作并在各种变体之间执行搜索。

这是一个有趣的话题,我一直在具有显式管理的内存层次结构的异构多核架构上实现 BLAS,比如 Cell 处理器。祝你好运!希望我的回答有用!

于 2012-04-14T20:20:26.030 回答
0

由于您使用的是 MKL,因此您可以使用扩展名 DAXPBY,它可以使用y <-- ax + by. 您的操作将变为:

`z = ax + by`: DCOPY(n,z,1,y,1), then DAXPBY(n,a,x,1,b,z,1)
`y = ax`: DAXPBY(n,a,x,1,0,y,1)

您也可以尝试让编译器矢量化简单的标量代码;从理论上讲,这些简单的操作应该适合自动矢量化(当然,在实践中......)

于 2012-04-24T01:47:58.033 回答
0

我建议您使用 Fortran 95 数组表示法编写自己的例程,并查看编译器是否能够生成像样的代码。我怀疑它会,因为带宽有限的操作几乎被天真的实现最大化了,即由大师编写的优化的 BLAS1 库实现可能不会比未优化的 Netlib BLAS1 快很多,除非数据已经驻留在缓存中(其中情况下,矢量化会有一些效果)。

I have made such comparisons in the past and found that, for any vector not resident in cache, the difference between optimized and unoptimized BLAS1 style routines is negligible.

于 2015-01-05T06:12:41.387 回答