考虑以下简单的速度测试arrayfun
:
T = 4000;
N = 500;
x = randn(T, N);
Func1 = @(a) (3*a^2 + 2*a - 1);
tic
Soln1 = ones(T, N);
for t = 1:T
for n = 1:N
Soln1(t, n) = Func1(x(t, n));
end
end
toc
tic
Soln2 = arrayfun(Func1, x);
toc
Run Code Online (Sandbox Code Playgroud)
在我的机器上(Linux Mint 12上的Matlab 2011b),该测试的输出是:
Elapsed time is 1.020689 seconds.
Elapsed time is 9.248388 seconds.
Run Code Online (Sandbox Code Playgroud)
什么了?!?arrayfun
虽然公认的解决方案更清洁,但速度要慢一个数量级.这里发生了什么?
此外,我做了类似的测试方式cellfun
,发现它比显式循环慢约3倍.同样,这个结果与我的预期相反.
我的问题是:为什么是arrayfun
和cellfun
这么多慢?鉴于此,有没有充分的理由使用它们(除了使代码看起来很好)?
注意:我说的是arrayfun
这里的标准版本,而不是并行处理工具箱中的GPU版本.
编辑:为了清楚起见,我知道 …
背景
我的问题是由简单的观察推动的,这有点破坏了经验丰富的MATLAB用户经常持有/做出的信念/假设:
底线:核心MATLAB功能是高效的,并且尝试使用MATLAB代码超越它是很困难的,如果不是不可能的话.
研究向量索引的性能
下面显示的示例代码是基本的:我为所有向量条目指定标量值.首先,我分配一个空向量x
:
tic; x = zeros(1e8,1); toc
Elapsed time is 0.260525 seconds.
Run Code Online (Sandbox Code Playgroud)
有x
,我想它所有的项目设置为相同的值.在实践中,你会采用不同的方式,例如,x = value*ones(1e8,1)
但这里的重点是研究向量索引的性能.最简单的方法是写:
tic; x(:) = 1; toc
Elapsed time is 0.094316 seconds.
Run Code Online (Sandbox Code Playgroud)
我们称之为方法1(从赋值的值x
).它看起来非常快(至少比内存分配更快).因为我在这里做的唯一事情就是对内存进行操作,我可以通过计算获得的有效内存带宽并将其与计算机的硬件内存带宽进行比较来估算此代码的效率:
eff_bandwidth = numel(x) * 8 bytes per double * 2 / time
Run Code Online (Sandbox Code Playgroud)
在上面,我乘以2
因为除非使用SSE流,否则在存储器中设置值要求向量既可以从存储器读取也可以写入存储器.在上面的例子中:
eff_bandwidth(1) = 1e8*8*2/0.094316 = 17 Gb/s
Run Code Online (Sandbox Code Playgroud)
我的计算机的STREAM基准内存带宽约为17.9 Gb/s,所以确实如此 - 在这种情况下,MATLAB可以提供接近峰值的性能!到现在为止还挺好.
Method 1 is suitable if you want to set all …
我需要有关以下代码性能的帮助.它对两个动态分配的任意大小的数组执行memcpy:
int main()
{
double *a, *b;
unsigned n = 10000000, i;
a = malloc(n*sizeof(double));
b = malloc(n*sizeof(double));
for(i=0; i<n; i++) {
a[i] = 1.0;
/* b[i] = 0.0; */
}
tic();
bzero(b, n*sizeof(double));
toc("bzero1");
tic();
bzero(b, n*sizeof(double));
toc("bzero2");
tic();
memcpy(b, a, n*sizeof(double));
toc("memcpy");
}
Run Code Online (Sandbox Code Playgroud)
tic/toc测量执行时间.
在我的电脑上,memcpy需要0.035秒(Linux,gcc版本4.4.6).如果我现在取消注释初始化目标数组b的行,则代码快三倍(!) - 0.011s.
我在使用循环而不是memcpy时观察到类似的行为.通常我不关心这个,因为它足以在使用之前"初始化"内存.但是,我现在需要执行一个简单的内存复制,并尽可能快地完成.初始化数据需要将0写入存储器,这不是必需的并且需要时间.我想用所有可用的内存带宽执行内存复制.
有这个问题的解决方案吗?或者它是否与Linux处理动态内存的方式相关(某种懒惰的页面分配?)并且无法解决?它在其他系统上怎么样?
编辑:使用gcc 4.6获得相同的结果.我用-O3编译.
编辑: 谢谢大家的意见.我明白内存映射需要时间.我想我只是很难接受它需要这么长时间,比实际的内存访问时间长得多.代码已被修改为包含使用两个后续bzero调用的数组b初始化的基准.时间现在显示
bzero1 0.273981
bzero2 0.056803
memcpy 0.117934
显然,第一bzero调用做多的不止流零记忆-这是内存映射和内存归零.另一方面,第二个bzero调用占用了memcpy所需的一半时间,这与预期完全一样 - 只写时间与读写时间.据我所知,由于操作系统安全原因,第二次bzero调用的开销必须在那里.剩下的呢?我能否以某种方式减少它,例如使用更大的内存页面?不同的内核设置?
我应该提一下,我在Ubuntu wheeze上运行它.
我正在编写一个代码,我要求用户输入.但是,通知用户这个字符串的字符串有点长,当我使用代码时,它们都会在命令窗口中的一行中写入.我想把它分散在多行上.我的代码是:
n = input(['The matrix is diagonally dominant. Please choose which method you wish to'...
' use: 1 (Gaussian elimination), 2 (Jacobi iterations),'...
' 3 (Gauss-Seidel iterations). If you enter any other number'...
' Gaussian elimination will automatically be used: ']);
Run Code Online (Sandbox Code Playgroud)
如果可取的话,我希望显示超过4行,如代码中所示.我该如何完成这项工作?
是否可以在omp并行块之外使用omp pragma,如critical,single,master或barrier?我有一个可以从OMP并行块调用的函数.如果是,我需要将部分代码包含在关键部分中.换句话说,这段代码好吗?
void myfunc(){
#pragma omp critical
{ /* code */ }
}
// not inside an omp parallel region
myfunc();
#pragma omp parallel
{
// inside an omp parallel region
myfunc();
}
Run Code Online (Sandbox Code Playgroud)
我在OpenMP文档中没有提到这一点.我猜代码应该与1个线程执行完全一样 - 这就是它与gcc一起工作的方式.我想知道这种行为是否可移植,或者是规范没有定义的东西,可以预期任何事情.
我偶然发现了以下问题.下面的代码片段在Mac OS X上没有与我试过的任何Xcode链接(4.4,4.5)
#include <stdlib.h>
#include <string.h>
#include <emmintrin.h>
int main(int argc, char *argv[])
{
char *temp;
#pragma omp parallel
{
__m128d v_a, v_ar;
memcpy(temp, argv[0], 10);
v_ar = _mm_shuffle_pd(v_a, v_a, _MM_SHUFFLE2 (0,1));
}
}
Run Code Online (Sandbox Code Playgroud)
代码仅作为示例提供,并且在运行时会出现段错误.关键是它不能编译.编译使用以下行完成
/Applications/Xcode.app/Contents/Developer/usr/bin/gcc test.c -arch x86_64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk -mmacosx-version-min=10.7 -fopenmp
Undefined symbols for architecture x86_64:
"___builtin_ia32_shufpd", referenced from:
_main.omp_fn.0 in ccJM7RAw.o
"___builtin_object_size", referenced from:
_main.omp_fn.0 in ccJM7RAw.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)
不使用-fopenmp
标志时,代码编译得很好gcc
.现在,我用Google搜索了一圈,发现,与相连的第一个问题的解决方案 …
我绝对不是FFMPEG专家,但根据这份文件:
预设是一组选项,可以提供一定的编码速度与压缩比.较慢的预设将提供更好的压缩(压缩是每个文件大小的质量).一般用法是使用您耐心等待的最慢预设.按速度降序排列的当前预设为:超快,超快,非常快,快,快,中,慢,慢,小,安慰剂.
据我了解,ffmpeg
预设不应影响输出视频的质量,而应仅确定压缩比/输出文件大小.因此,假设相同的质量设置(我将使用-crf 24
),文件应该比例如faster
预设的slower
预设大.这将是使用较慢预设的唯一原因 - 获得较小的文件大小.
事实证明并非如此.我使用不同的预设从handycam编码高清流,其他一切都是相同的:
ffmpeg -y -i "$fname" -vf yadif=1,scale=-1:720 -acodec aac -ab 128k -ac 2 -strict experimental -vcodec libx264 -vpre slow -threads 2 -crf 24 "$outp"
Run Code Online (Sandbox Code Playgroud)
令人惊讶的是,我获得了veryfast
预设的最小文件大小!例如:
slower
:输出比特率3500kbps,编码速度17 fps,文件大小29MBveryfast
:输出比特率3050kbps,编码速度34 fps,文件大小25MB我认为不应该如此.现在我想知道,是因为veryfast
预设的编码质量较差?或者在我使用的情况下,slower
由于某种原因根本没有意义?
在Agner Fog的优秀微体系结构中 .pdf (第9.14节)我读到:
存储转发在以下情况下有效:[...]当写入128或256位后,读取相同大小和相同的地址,对齐16.
另一方面,我阅读了英特尔架构优化参考手册(2.2.5.2 Intel Sandy Bridge,L1 DCache)
在以下情况下,存储无法转发到负载:[...]任何跨越32字节存储的16字节边界的负载.
任何负载听起来像32字节加载..我写了以下简单的代码来测试这一点,似乎32字节存储不转发到Sandy Bridge架构上的后续32字节加载.这是代码:
#include <stdlib.h>
#include <malloc.h>
int main(){
long i;
// aligned memory address
double *tempa = (double*)memalign(4096, sizeof(double)*4);
for(i=0; i<4; i++) tempa[i] = 1.0;
for(i=0; i<1000000000; i++){ // 1e9 iterations
#ifdef TEST_AVX
__asm__("vmovapd %%ymm12, (%0)\n\t"
"vmovapd (%0), %%ymm12\n\t"
:
:"r"(tempa));
#else
__asm__("movapd %%xmm12, (%0)\n\t"
"movapd (%0), %%xmm12\n\t"
:
:"r"(tempa));
#endif
}
}
Run Code Online (Sandbox Code Playgroud)
在循环中唯一做的是从4k对齐的存储器位置和向量寄存器读取/写入.使用AVX指令集(gcc -O3 -DTEST_AVX
)编译时,我的2.7GHz i7-2620M的执行时间为3.1秒.使用SSE2指令集时,时间为2.5秒.我看了一下性能指标.在AVX情况下,我计算每次迭代一次存储转发块事件(计数器03H 02H LD_BLOCKS.STORE_FORWARD
).计数器为SSE2情况读取0.
任何人都可以对此有所了解吗?SB确实不支持将32字节存储转发到32字节加载吗?如果是后者,溢出ymm …
我有一个M x N
矩阵.我想N
用M x M
矩阵乘以每列.以下是循环中的这个,但我不知道如何对其进行矢量化.
u=repmat(sin(2*pi*f*t),[n 1]);
W = rand(n);
answer = size(u);
for i=1:size(u,2)
answer(:,i) = W*u(:,i);
end
Run Code Online (Sandbox Code Playgroud) 我想知道matlab如何能够如此快速地乘以两个矩阵.当乘以两个N×N矩阵时,执行N ^ 3次乘法.即使使用Strassen算法,它也需要N ^ 2.8次乘法,这仍然是一个很大的数字.我正在运行以下测试程序:
a = rand(2160);
b = rand(2160);
tic;a*b;toc
Run Code Online (Sandbox Code Playgroud)
使用2160是因为2160 ^ 3 = ~10 ^ 10(a*b应该是大约10 ^ 10次乘法)
我有:
Elapsed time is 1.164289 seconds.
Run Code Online (Sandbox Code Playgroud)
(我在2.4Ghz笔记本上运行,没有发生线程)这意味着我的计算机在1秒多一点的时间内完成了10 ^ 10的操作.
怎么会这样?
performance matlab matrix time-complexity matrix-multiplication