并行gfor 1

  • 0 replies
  • 2785 views
并行gfor 1
« 于: 二月 24, 2012, 09:59:15 am »
GFOR/GEND循环创建会即时执行所有的for循环迭代, 只要迭代是相互独立的没有调用关系。而标准的 FOR循环是一步一步的执行每个迭代。GFOR/GEND 在同时执行所有的迭代。JACKET是通过一开始就平铺出所有需要循环迭代的值,然后在一次执行这些平铺的迭代值计算的。
gfor有很多限制, 只能在合适的时候使用GFOR循环。但对于绝大多数循环在循环体内使用GPU变量都将会比for循环慢慢迭代高效。但不管是在matlab中还是JACKET中尽可能的使用 vectorize 来代替使用for或者gfor循环。
目前为止还有很多函数不支持gfor循环。支持gfor的函数
A = gones(n,n,m);
B = gones(n);
gfor k = 1:m
  A(:,:,k) = A(:,:,k) * B; % matrix-matrix multiply
gend

迭代器迭代器可以参与运算。
A = gones(n,n,m);
B = gones(n);
gfor k = 1:2:m
  A(:,:,k) = k*B + sin(k+1);  % expressions
gend

New in v1.5.1 迭代定义可能包括在算术表达式中.
A = gones(n,n,m);
B = gones(n);
gfor k = m/4:m-m/4
 A(:,:,k) = k*B + sin(k+1);  % expressions
gend
更复杂的下标运算支持.
A = gones(n,n,m);
B = gones(n,10);
gfor k = 1:2:m
  A(:,1:10,k) = k*B;  % subscripting
gend

New in v1.5 迭代器可以参与下标运算

A = gones(n,2*m);
B = gones(n,m);
gfor k = 2:m
  B(:,k) = A(:,floor(k+.2));
gend

在环回用在循环中,你可以使用你刚才计算的结果。
[A B C] = deal(gones(n));
gfor k = 1:n
  A(:,k) = 4 * B(:,k);
  C(:,k) = 4 * A(:,k); % use it again
gend

虽然它是更有效地存储一个临时变量的值:
[A B C] = deal(gones(n));
gfor k = 1:n
  a = 4 * B(:,k);
  A(:,k) = a;
  C(:,k) = 4 * a;
gend

在某些情况下计算,GFOR行为不同于典型的for循环。例如,只要一个结果,因为是独立的访问。
A = gones(n);
gfor k = 1:n
  A(:,k) = sin(k) + A(:,k);
gend

同样下标和GPU提供的数据用于分配在GFOR下。
A = gones(n,n,m,k);
m = m * k;  % precompute since cannot have expressions in iterator
gfor k = 1:m
  A(:,:,k) = 4 * A(:,:,k); % collapse last dimension
gend
迭代独立循环的身体最重要的属性是每个迭代必须是其他迭代独立。访问一个单独的迭代结果产生不确定的行为
B = 0;
gfor k = 1:n
  B = B + k; % bad
gend
没有条件语句中的循环体(即没有分支)。但是可以找到办法来克服这个限制。考虑下面的两个例子:
Example 1:  Problem
A = gones(n,m);
gfor k = 1:n
  if k > 10  % bad
    A(:,k) = k + 1;
  end
gend你可以使用条件数来改替分支预测:
Example 1:  Solution
A = gones(n,m);
gfor k = 1:n
  condition = k > 10; % good
  A(:,k) = ~condition*A(:,k) + condition*(k+1);
gend

另一个在GFOR克服限制条件语句的例子如下:

Example 2:  Problem
A = gones(n,n,m);
B = grand(n);
gfor k = 1:4
  if mod(k,2) ~= 0
    A(:,:,k) = B + k;
  else
    A(:,:,k) = B * k;
  end
gend
Example 2:  Solution
A = gones(n,n,m);
B = grand(n);
gfor k = 1:2:4
  A(:,:,k) = B + k;
gend
gfor k = 2:2:4
  A(:,:,k) = B * k;
gend

 
没有细胞数组赋值
gfor k = 1:n
  A{k} = k; % bad
gend

嵌套循环嵌套限制在GFOR -循环GFOR -环是不受支持的。您可能会交错for循环,只要他们是完全的GFOR循环迭代器无关。

gfor k = 1:n
  gfor j = 1:m  % bad
  % ...
  gend
gend

这将产生一个警告:

警告:检测到可能的嵌套GFOR

为了检测嵌套,JACKET采用了简单的内部开关:GFOR打开它,GEND将其关闭。所以,如果你重新输入,而无需做了GEND清理,内部警告标志GFOR语句,然后你会得到这个警告,虚惊一场:

>> gfor ii = 1:8
>> gend
>> gfor ii = 1:8
>> gfor ii = 1:8    %redefine 'ii' and produce false alarm warning
Warning: Detected possible nested GFOR>> gend
>> gfor ii = 1:8    % no problem
>> gend

嵌套FOR -在循环gfor下的支持,只要GFOR迭代器不是在for循环迭代器使用,具体如下:
gfor k = 1:n
  for j = 1:m+k % bad
  % ...
  end
gend

gfor k = 1:n
  for j = 1:m   % good
  % ...
  end
gend

嵌套GFOR -在循环for内循环是完全支持。

for k = 1:n
  gfor j = 1:m  % good
  % ...
  gend
end

GFOR命令行解析GFOR必须在一个单独占一行。

gfor k = 1:n; A(:,k) = k;
gend % bad
 
gfor k = 1:n  % this comment is okay
  A(:,k) = k;
gend
 
gfor k = 1:ceil(2*n)/2  % expressions
  A(:,k) = k;
gend

迭代器不能再gfor外使用,不能咋gend后面使用迭代否则他得值不是最后一次迭代值。
gfor k = 1:n
  % ...
gend
A = A / k; % bad

 由于每个计算内存并行的考虑是为所有的迭代器值,有足够的可用内存卡做所有迭代同时进行。问题超出内存时,会引发“内存不足”的错误。解决你的GPU的内存限制,打破了GFOR循环成段组成,可能要考虑使用更大的内存的GPU。
% BEFORE
gfor k = 1:400
  B = A(:,k);
  C(:,:,k) = B * B';  % outer product expansion runs out of memory
gend
 
% AFTER
for kk = 1:100:400
  gfor k = kk:kk+100-1  % four batches of 100
    B = A(:,k);
    C(:,:,k) = B * B';  % now several smaller problems fit in card memory
  gend
end

在JACKET中迭代循环的变量不能使用i,j。因为在JACKET中I,J表示复数和图像的定义。
例如,运行提示你可能与我得到这个错误:
>> gfor i = 1:4
Warning: GFOR variable name conflicts with builtin command
如果一个函数内使用gfor然后预分配:

  i = [];
  gfor i = 1:n
    ...
  gend
  迭代器不允许在:语句中,下标索引向量矩阵和“:”内GFOR表达可能只与循环迭代完成。其他变量或表达式中的迭代器会
A = gones(100,100);
gfor k = 5:95
  A(k-4:k+4,k-4:k-4) = ... %  bad
gend
迭代器必须是均匀分布的迭代表达式必须是均匀分布的实际值的行向量。
gfor i = 1:n       % good
gfor i = m:n       % good
gfor i = 5:2:100   % good
gfor i = 1:2:n     % good
gfor i = [1 4 2 3] % bad
 
下标数据不能直接回落到MATLAB,这不是简单的转换GFOR定期MATLAB数组阵列,因为GFOR阵列包含(平铺)的多个副本。数组转换为MATLAB的GFOR需要考虑到这一点
 size(A)==size(single(A)).
这样会提示警告:
A = grand(2)
gfor k = 1:2
  a = A(:,k);
  single(a)
gend

产生一个警告:
A =
    0.1209    0.8746
    0.6432    0.3369
Warning: Only storing result from first GFOR iteration into MATLAB variable
ans =
    0.1209
    0.6432

另一个地方这往往表明了这是在IF语句隐含拉MATLAB的数据返回到生产这一警告。
要查看GFOR数据的内容,你必须分配到使用迭代器变量。

A = grand(2)
B = gzeros(1,2);
gfor k = 1:2
  a = A(:,k);
  B(1,k) = a(2);  % look at second entry in each column
gend

一旦你使用了分配存储每个标砖,你应可以转换回CPU
B = single(B);  % now back on CPU

CPU变量下标由于GFOR数据到CPU变量直接转换为未定义,它也是未定义使用GFOR数据到CPU变量标。
 We catch this and error out:
A = rand(4);
gfor ii = 1:4
  A(ii);
??? Error using ==> garray.subsindex at 3
未定义的行为:处理器下标GFOR迭代与变量
这个错误是发生在MATLAB是试图成为一个经常性的CPU使用的GPU变量是在一个GFOR计算所涉及的变量指标。在这种情况下,Matlab要求CPU的指标,但这些指标是平铺的数据,因此目前还不清楚哪些平铺重新

EXAMPLE:
for i = 1:n
  A(i) = A(i) + 1;
end
 
A = A + 1;  % vectorized version

for i = 1:n
  A(:,:,i) = fft2(A(:,:,i)); % runs each FFT in sequence
end
 
gfor i = 1:n
  A(:,:,i) = fft2(A(:,:,i));  % vectorized version: runs 'n' FFTs in parallel
gend

Examples
A = grand(n,m);
B = gzeros(n,m);
gfor k = 1:m
  B(:,k) = fft(A(:,k));    % FFT
gend

A = gones(n,m);
B = gones(size(A));
gfor k = 2:m
  B(:,k) = A(:,k-1);
gend

A = gones(n,m);
B = gones(size(A));
gfor k = 1:m
  a = A(:,k);
  b = gzeros(n,1);
  b([1 3]) = a([1 3]);  % each GFOR tile gets its own unique copy of 'b'
  B(:,k) = b;
gend