在条件下访问矩阵元素
Access matrix element in condition
我正在尝试减少我的 MatLab 代码的计算时间。为此,我使用 MatLab profiler.
在某些函数中我遇到了同样的情况。我遍历一个网格(一个二维矩阵)并测试每个单元格是否有(或没有)一些值(每次两个)。而且病情需要很长时间。大部分时间花在这些功能上。
这是我的代码中的一个示例:
time Calls line
16 function tGrid=some_compute(grid, tGrid, trans)
0.005 125 17 global depth width tWidth
18
< 0.001 125 19 for i=1:depth
0.022 125000 20 for j=1:width
2.270 37500000 21 if (grid(i, j)~=0 && grid(i, j)~=1)
22
23 % Get the transformed coordinates of the current cell
0.864 79997 24 [x, y]=get_trans(trans, i, j);
25
0.006 79997 26 if (x~=-1 && y~=-1)
0.006 79992 27 tGrid(x, y)=grid(i, j);
0.004 79992 28 end % If x~=-1 && y~=-1
0.004 79997 29 end % If grid~=0 && grid~=1
1.933 37500000 30 end % For j=width
0.008 125000 31 end % For i=depth
32
< 0.001 125 33 end
此函数共调用125次,耗时5.24s。
正如我们所见,第21行花费了更多的时间来执行。虽然 grid(i, j)
在条件中被访问了两次,并且也在第 27 行中使用了,但我猜想通过将它存储在一个变量之前,它会加速我的代码。
所以,我做了这个简单的修改:
time Calls line
16 function tGrid=some_compute(grid, tGrid, trans)
0.005 125 17 global depth width tWidth
18
< 0.001 125 19 for i=1:depth
0.021 125000 20 for j=1:width
2.062 37500000 21 val=grid(i, j);
1.681 37500000 22 if (val~=0 && val~=1)
23
24 % Get the transformed coordinates of the current cell
0.793 79997 25 [x, y]=get_trans(trans, i, j);
26
0.005 79997 27 if (x~=-1 && y~=-1)
0.005 79992 28 tGrid(x, y)=val;
0.004 79992 29 end % If x~=-1 && y~=-1
0.004 79997 30 end % If grid~=0 && grid~=1
1.731 37500000 31 end % For j=width
0.007 125000 32 end % For i=depth
33
< 0.001 125 34 end
而现在,这个函数调用125次总共需要6.32s。
正如我们所见,获取单元格的值所花费的时间与获取它两次并将其与两个值进行比较所花费的时间一样多。第 22 行的 if 和第一个版本一样慢。我不明白为什么。
我不能告诉你到底发生了什么,因为我不知道底层的 MATLAB 库是如何实现的。但是,出现的结果可能是有原因的。
如果我没有算错的话,您正在使用 dense 1000x300 矩阵,这是一个包含 300.000 个浮点数的数组。
来自这一行
2.062 37500000 21 val=grid(i, j);
您可以计算出单次执行大约需要 55 纳秒(时间/调用 * 10^9),这对于简单的数据访问来说是相当长的时间。如果你有一个 2GHz 处理器,一个处理周期需要 0.5 纳秒。那将是 110 个周期。但是,由于您使用的是一个巨大的密集矩阵,您可能会在这里面临很多缓存未命中。可以肯定的是,大幅减小矩阵大小(从 40x12 开始)并计算每次执行的时间。如果您有缓存未命中问题,它应该下降到大约 1-2 纳秒。
如果缓存未命中确实是问题所在,我担心您的问题并没有真正简单的解决方案,因为它需要以内存友好的方式重组数据。 Matlab 是一种脚本语言这一事实并没有使它变得更容易,因为您没有为您执行优化的编译器。你可以尝试切换内循环和外循环,希望内存访问模式变得更好。
问候
getting the value of the cell take as much time as getting it twice and compare it to two values. [...] I don't understand why.
这是因为您的代码 运行 在 JIT(即时编译器)下。该编译器优化您的代码。尽管没有记录它究竟是如何工作的以及实施了什么样的优化,但从您的实验中可以清楚地看出 grid(i, j)~=0 && grid(i, j)~=1
被优化为仅获取值 grid(i,j)
一次。
我正在尝试减少我的 MatLab 代码的计算时间。为此,我使用 MatLab profiler.
在某些函数中我遇到了同样的情况。我遍历一个网格(一个二维矩阵)并测试每个单元格是否有(或没有)一些值(每次两个)。而且病情需要很长时间。大部分时间花在这些功能上。
这是我的代码中的一个示例:
time Calls line
16 function tGrid=some_compute(grid, tGrid, trans)
0.005 125 17 global depth width tWidth
18
< 0.001 125 19 for i=1:depth
0.022 125000 20 for j=1:width
2.270 37500000 21 if (grid(i, j)~=0 && grid(i, j)~=1)
22
23 % Get the transformed coordinates of the current cell
0.864 79997 24 [x, y]=get_trans(trans, i, j);
25
0.006 79997 26 if (x~=-1 && y~=-1)
0.006 79992 27 tGrid(x, y)=grid(i, j);
0.004 79992 28 end % If x~=-1 && y~=-1
0.004 79997 29 end % If grid~=0 && grid~=1
1.933 37500000 30 end % For j=width
0.008 125000 31 end % For i=depth
32
< 0.001 125 33 end
此函数共调用125次,耗时5.24s。
正如我们所见,第21行花费了更多的时间来执行。虽然 grid(i, j)
在条件中被访问了两次,并且也在第 27 行中使用了,但我猜想通过将它存储在一个变量之前,它会加速我的代码。
所以,我做了这个简单的修改:
time Calls line
16 function tGrid=some_compute(grid, tGrid, trans)
0.005 125 17 global depth width tWidth
18
< 0.001 125 19 for i=1:depth
0.021 125000 20 for j=1:width
2.062 37500000 21 val=grid(i, j);
1.681 37500000 22 if (val~=0 && val~=1)
23
24 % Get the transformed coordinates of the current cell
0.793 79997 25 [x, y]=get_trans(trans, i, j);
26
0.005 79997 27 if (x~=-1 && y~=-1)
0.005 79992 28 tGrid(x, y)=val;
0.004 79992 29 end % If x~=-1 && y~=-1
0.004 79997 30 end % If grid~=0 && grid~=1
1.731 37500000 31 end % For j=width
0.007 125000 32 end % For i=depth
33
< 0.001 125 34 end
而现在,这个函数调用125次总共需要6.32s。
正如我们所见,获取单元格的值所花费的时间与获取它两次并将其与两个值进行比较所花费的时间一样多。第 22 行的 if 和第一个版本一样慢。我不明白为什么。
我不能告诉你到底发生了什么,因为我不知道底层的 MATLAB 库是如何实现的。但是,出现的结果可能是有原因的。
如果我没有算错的话,您正在使用 dense 1000x300 矩阵,这是一个包含 300.000 个浮点数的数组。
来自这一行
2.062 37500000 21 val=grid(i, j);
您可以计算出单次执行大约需要 55 纳秒(时间/调用 * 10^9),这对于简单的数据访问来说是相当长的时间。如果你有一个 2GHz 处理器,一个处理周期需要 0.5 纳秒。那将是 110 个周期。但是,由于您使用的是一个巨大的密集矩阵,您可能会在这里面临很多缓存未命中。可以肯定的是,大幅减小矩阵大小(从 40x12 开始)并计算每次执行的时间。如果您有缓存未命中问题,它应该下降到大约 1-2 纳秒。
如果缓存未命中确实是问题所在,我担心您的问题并没有真正简单的解决方案,因为它需要以内存友好的方式重组数据。 Matlab 是一种脚本语言这一事实并没有使它变得更容易,因为您没有为您执行优化的编译器。你可以尝试切换内循环和外循环,希望内存访问模式变得更好。
问候
getting the value of the cell take as much time as getting it twice and compare it to two values. [...] I don't understand why.
这是因为您的代码 运行 在 JIT(即时编译器)下。该编译器优化您的代码。尽管没有记录它究竟是如何工作的以及实施了什么样的优化,但从您的实验中可以清楚地看出 grid(i, j)~=0 && grid(i, j)~=1
被优化为仅获取值 grid(i,j)
一次。