Performance 可以进行矢量化吗?这有什么好处吗?
这个函数在我的运行中占用了很多时间。但我们看到的是,大部分时间都是在内置的功能领域。此代码是否可以矢量化以提高性能 探查器报告-Performance 可以进行矢量化吗?这有什么好处吗?,performance,matlab,vectorization,Performance,Matlab,Vectorization,这个函数在我的运行中占用了很多时间。但我们看到的是,大部分时间都是在内置的功能领域。此代码是否可以矢量化以提高性能 探查器报告- time calls 1 function [S S_area] = Polygons_intersection_Compute_area(S) 2 % Guillaume JACQUENOT 3 % guillaume at jacquenot at
time calls
1 function [S S_area] = Polygons_intersection_Compute_area(S)
2 % Guillaume JACQUENOT
3 % guillaume at jacquenot at gmail dot com
4 % 2007_10_08
5 % 2009_06_16
6 % Compute area of each polygon of in S.
7 % Results are stored as a field in S
8
0.50 51945 9 S_area = struct('A', {});
0.20 51945 10 for i=1:numel(S)
0.28 103890 11 S(i).area = 0;
1.34 103890 12 S_area(i).A = zeros(1,numel(S(i).P));
0.69 103890 13 for j=1:numel(S(i).P)
9.24 103890 14 S_area(i).A(j) = polyarea(S(i).P(j).x,S(i).P(j).y);
0.28 103890 15 S(i).area = S(i).area + (1-2*S(i).P(j).hole) * S_area(i).A(j);
0.01 103890 16 end
0.08 103890 17 end
我看到4个问题。我将按潜在性能增益的递增顺序讨论它们 第一:使用i和j作为循环变量名。这些也是Matlab中虚单位的名称,这意味着Matlab将需要花费一些时间查找您所指的单位。问题是,它必须在每次迭代中都这样做,如果循环没有JIT'ed,而你的循环没有,我会去做的 第二:为多维结构编制索引比你想象的要花更多的时间。多维结构在这方面有点臭名昭著,最好避免对它们执行太多的索引操作。通常,制作一个元素的简单副本,在该副本上执行所有操作,然后将副本写回结构可以大大提高性能 第三:您没有以最有效的方式预先分配S_区域。您甚至不预分配结构,而是在预分配S_Area.A.时在第一个循环中增加它。这一切都可以改进,见下文 第四:polyarea不是一个内置函数,因此这个双循环不会被JIT’ed。如果您调用循环中的任何函数,您或Mathworks用M语言而不是C语言编写,JIT编译器将无法编译您的循环。这是迄今为止JIT框架中最烦人和最可改进的限制,而JIT循环的运行速度通常比非JIT循环快100倍或更多 唯一的解决方案通常是在循环体中内联一个非内置函数。在Matlab中,这意味着:将函数体的全部内容复制粘贴到循环中,并对该体中调用的所有非内置函数递归执行此操作 以上所有内容都会导致此版本的代码:
% pre-allocate S_area
S_area(numel(S)).A = [];
As = cellfun(@(x) zeros(numel(x),1), {S.P}, 'UniformOutput', false);
[S_area.A] = deal(As{:});
% number of polygons for all S(ii)
numPolys = cellfun(@numel, {S.P});
% enter loop
for ii = 1:numel(S)
% extract S(ii) only once
Sii = S(ii);
Sii.area = 0;
Aii = S_area(ii).A;
for jj = 1:numPolys(ii)
p = Sii.P(jj); % extract polygon only once
x = p.x; % and its x and y components
y = p.y;
sz = size(p);
% NOTE: core of polyarea. Note that all checks and flexibility, and
% therefore user-friendliness, is GONE. Very little has to go wrong
% here before a hard-to-understand error is issued.
Area = reshape(abs(sum( (x([2:sz(1) 1],:) - x(:,:)).* ...
(y([2:sz(1) 1],:) + y(:,:)))/2),[1 sz(2:end)]);
Aii(jj) = Area;
Sii.area = Sii.area + Area*(1-2*p.hole);
end
% place copies back into the strucure
S_area(ii).A = Aii;
S(ii).area = Sii.area;
end
我无法像你一样正确地测试这个,所以如果你发现一些错误,请让我知道,我会尝试更正它们 我看到了4个问题。我将按潜在性能增益的递增顺序讨论它们 第一:使用i和j作为循环变量名。这些也是Matlab中虚单位的名称,这意味着Matlab将需要花费一些时间查找您所指的单位。问题是,它必须在每次迭代中都这样做,如果循环没有JIT'ed,而你的循环没有,我会去做的 第二:为多维结构编制索引比你想象的要花更多的时间。多维结构在这方面有点臭名昭著,最好避免对它们执行太多的索引操作。通常,制作一个元素的简单副本,在该副本上执行所有操作,然后将副本写回结构可以大大提高性能 第三:您没有以最有效的方式预先分配S_区域。您甚至不预分配结构,而是在预分配S_Area.A.时在第一个循环中增加它。这一切都可以改进,见下文 第四:polyarea不是一个内置函数,因此这个双循环不会被JIT’ed。如果您调用循环中的任何函数,您或Mathworks用M语言而不是C语言编写,JIT编译器将无法编译您的循环。这是迄今为止JIT框架中最烦人和最可改进的限制,而JIT循环的运行速度通常比非JIT循环快100倍或更多 唯一的解决方案通常是在循环体中内联一个非内置函数。在Matlab中,这意味着:将函数体的全部内容复制粘贴到循环中,并对该体中调用的所有非内置函数递归执行此操作 以上所有内容都会导致此版本的代码:
% pre-allocate S_area
S_area(numel(S)).A = [];
As = cellfun(@(x) zeros(numel(x),1), {S.P}, 'UniformOutput', false);
[S_area.A] = deal(As{:});
% number of polygons for all S(ii)
numPolys = cellfun(@numel, {S.P});
% enter loop
for ii = 1:numel(S)
% extract S(ii) only once
Sii = S(ii);
Sii.area = 0;
Aii = S_area(ii).A;
for jj = 1:numPolys(ii)
p = Sii.P(jj); % extract polygon only once
x = p.x; % and its x and y components
y = p.y;
sz = size(p);
% NOTE: core of polyarea. Note that all checks and flexibility, and
% therefore user-friendliness, is GONE. Very little has to go wrong
% here before a hard-to-understand error is issued.
Area = reshape(abs(sum( (x([2:sz(1) 1],:) - x(:,:)).* ...
(y([2:sz(1) 1],:) + y(:,:)))/2),[1 sz(2:end)]);
Aii(jj) = Area;
Sii.area = Sii.area + Area*(1-2*p.hole);
end
% place copies back into the strucure
S_area(ii).A = Aii;
S(ii).area = Sii.area;
end
我无法像你一样正确地测试这个,所以如果你发现一些错误,请让我知道,我会尝试更正它们 我想说,打10万个电话9秒不算太差。@Jonas-谢谢你的投入。事实上,这就是我想知道的,是不是不坏,还是我们还有办法挤出一些额外的时间。我想说,打10万个电话9秒不算太差。@Jonas-谢谢你的投入。事实上,这就是我想知道的,是不是不坏,或者我们还有办法挤出一些额外的时间。+1是很好的解释。不过有几点建议:1不要使用arrayfun,2计算numelSi.P并替换numel调用。3最有可能的情况是,您可以更换/删除尺寸呼叫以及重塑。@Rody-感谢您提供的详细答案。我对matlab很陌生,你的解释不仅对这个问题很有帮助,而且对我对matlab的全面理解也很有帮助。我尝试了你的代码版本,它运行得很好。但在时间上没有任何改善,事实上它又花了半秒钟。我想这就像乔纳斯所说的,也许在这段代码中没有任何时间方面的改进空间。你喜欢吃什么
k?@Vikram:你有什么版本的Matlab?@Vikram:奇怪……你的S结构平均有多大?+1解释得很好。不过有几点建议:1不要使用arrayfun,2计算numelSi.P并替换numel调用。3最有可能的情况是,您可以更换/删除尺寸呼叫以及重塑。@Rody-感谢您提供的详细答案。我对matlab很陌生,你的解释不仅对这个问题很有帮助,而且对我对matlab的全面理解也很有帮助。我尝试了你的代码版本,它运行得很好。但在时间上没有任何改善,事实上它又花了半秒钟。我想这就像乔纳斯所说的,也许在这段代码中没有任何时间方面的改进空间。你觉得怎么样?@Vikram:你有什么版本的Matlab?@Vikram:奇怪……你的S型结构平均有多大?