尝试通过改进缓存局部性来改进矩阵乘法 运行 时间

Trying to improve matrix multiplication run time by improving cache locality

我正在尝试通过改进空间局部性来重新排列循环顺序,从而缩短我的 运行 矩阵乘法时间。我有一个在我的 class 中使用 C++ 执行此操作的示例,但尝试在 Chapel 中实现它导致我出现此错误。

var grid : [1..size, 1..size] uint(8);
var grid2 : [1..size, 1..size] uint(8);
var grid3 : [1..size, 1..size] int;
var grid4 : [1..size, 1..size] uint(8);
forall i in 1..size do
    forall k in 1..size do
        grid4 = grid[i,k];
        forall j in 1..size do
            grid3[i,j] += grid4 * grid2[k,j];
hello.chpl:20: error: 'i' undeclared (first use this function)
hello.chpl:20: error: 'k' undeclared (first use this function)

有两件事共同导致了这些错误:

1) Chapel 不是空格敏感语言。因此,在 Python 中,语句的缩进表示它们彼此之间的关系,而在 Chapel 中则不是这种情况。在这方面,它更像是 C、C++ 或 Java,比方说。

2) 循环语句中的 do 关键字(或条件语句中的 then 关键字)是一种 shorthand 形式,特定于控制结构,其主体只有一个声明。要在其主体中创建包含多个语句的循环或条件,您应该使用大括号来指定复合语句。编写 Chapel 程序的一种防御方法是始终使用大括号。请注意,我经常在合法的幻灯片或 Whosebug 帖子中使用 shorthands,因为它更简洁。

因此,您编写的循环结构(正确缩进)如下:

forall i in 1..size do
    forall k in 1..size do
        grid4 = grid[i,k];
forall j in 1..size do
    grid3[i,j] += grid4 * grid2[k,j];

这说明了为什么 ik 在最后一个循环中不可访问——它们特定于先前的范围。一种解决方法是:

forall i in 1..size do
    forall k in 1..size {
        grid4 = grid[i,k];
        forall j in 1..size do
            grid3[i,j] += grid4 * grid2[k,j];
    }

或者,在全括号版本中:

forall i in 1..size {
    forall k in 1..size {
        grid4 = grid[i,k];
        forall j in 1..size {
            grid3[i,j] += grid4 * grid2[k,j];
        }
    }
}

理想情况下,一个好的 Chapel 编辑器模式将有助于保护您免受此类问题的困扰,但目前只有少数此类编辑器模式可用,而且它们的质量参差不齐。在 Chapel 安装中,您会在 $CHPL_HOME/highlight 中找到 emacs 和 vim 模式(其中 emacs 模式往往不如 vim 模式成熟)。我相信还有一种在线可用的原子模式(可能还有其他),但我个人并不熟悉它们。

但是,正如我所说,一种非常安全的编程方式是始终在控制流中使用大括号,在这种情况下,由于大括号不平衡,简单的错误通常会表现为语法错误。