繁体   English   中英

为什么MATLAB的元素指数加速为512个元素?

[英]Why does MATLAB's element-wise exponentiation speed up for 512 elements?

当数组的大小变为512时,MATLAB用于计算常数基数和指数数组的元素指数的幂函数变得明显更快。我希望看到计算时间随输入大小而增加,但是,有明显的下降当指数数组中有512个元素时。 这是一个示例代码

x_list = 510:514;
for i = 1:numel(x_list)
    x = x_list(i);
    tic
    for j = 1:10000
        y = power(2,1:x); 
    end
    toc
end

代码的输出是

Elapsed time is 0.397649 seconds.
Elapsed time is 0.403687 seconds.
Elapsed time is 0.318293 seconds.
Elapsed time is 0.238875 seconds.
Elapsed time is 0.175525 seconds.

这里发生了什么?

图片

我看到使用随机数作为指数的相同效果,因为我看到使用1:n范围内的整数:

x = 500:540;
t = zeros(size(x));
for ii = 1:numel(x)
    %m = 1:x(ii);
    m = 500*rand(1,x(ii));
    t(ii) = timeit(@()power(2,m));
end
plot(x,t)

图表显示在512左右的执行时间内跳转

当强制MATLAB使用带有maxNumCompThreads(1)的单个线程并再次运行上面的代码时,我会看到这个图形(注意y轴,峰值只是噪声):

图表没有显示512的跳转

在我看来,MATLAB使用单个核来计算511个值的指数,并在矩阵较大时激活所有核。 使用多线程有一个开销,对于小型数组来说这样做是不值得的。 通过节省时间来平衡开销的确切点取决于许多因素,因此对何时切换到多线程计算的硬编码固定阈值导致具有与系统的特性不同的系统上的执行时间的跳跃。确定了门槛。

请注意,@ norok2没有看到同样的跳转,因为在他们的系统中, MATLAB仅限于一个线程

这与计算功率的数量的大小有关,而不是与容器的大小有关。

如果你使用随机数,对于不同的容器大小,人们不会观察到时间的跳跃:

x = 450:1550;
y = zeros(numel(x), 1);
X = rand(1, 10000);
for i = 1:length(x)
    f = @() 2 .^ X(1:x(i));
    y(i) = timeit(f);
end

figure()
plot(x, y)

power_test_1

因此,问题必须是计算非常大的数字。 我首先认为这可能与溢出有关,但溢出发生在2 ^ 1024 == inf ,由MATLAB遵循的IEEE标准规定,我认为对于inf这比计算数字要快得多真的。

这由以下基准支持,其中数组的大小保持不变:

x = 450:1550;
y = zeros(numel(x), 1);
X = rand(1, 10000);
for i = 1:length(x)
    f = @() 2 .^ (ones(1, 500) * x(i));
    y(i) = timeit(f);
end

figure()
plot(x, y)

power_test_2

为什么这可能与您的设置相关,当2 ^ 512而不是2 ^ 1024 ,我真的不明白。

(注意我使用了2 .^ ...而不是power(2, ...)但结果是一样的。)


另外,在我的系统中运行@ CrisLuengo的代码并不会真正重现任何跳转。

x = 500:540;
t = zeros(size(x));
for ii = 1:numel(x)
    %m = 1:x(ii);
    m = 500*rand(1,x(ii));
    t(ii) = timeit(@()power(2,m));
end
plot(x,t)

迄今为止的所有证据表明,峰值与JIT延迟/热身有关。

在此输入图像描述

以下是使用运行MATLAB R2018a的4核Windows机器确认Cris发现的内容。 我首先测试了以下代码,以表明指数的具体值不是跳转的罪魁祸首:

t = zeros(4, 1000);
for p = 1:size(t, 1)
  for n = 1:size(t, 2)
    t(p, n) = timeit(@() power(2, (2.^(p-1)).*ones(1, n)));
  end
end

以下是结果:

在此输入图像描述

对于指数为1(返回相同值)或2(返回值本身)的简并边缘情况,计算运行得更快,如预期的那样。 但是,数组大小为512或更高的跳转表示开销被添加到这些边缘情况,而当阵列大小超过512时,指数4和8的计算时间减少。较大的指数值只是重现上面的曲线。

然后我又运行了两个测试:一个是数组大小介于1和511之间,另一个是数组大小介于512和1024之间。这是处理器负载的样子:

在此输入图像描述

处理器3在第一次测试期间显示大的负载尖峰,而所有4个处理器在第二次测试期间显示负载尖峰。 这证实了多线程用于512或更大的阵列大小。 这也解释了较大尺寸的边缘情况的较慢计算,因为多线程的开销超过了通过拆分更简单的计算所提供的加速。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM