以下是相关程序的摘录.矩阵img[][]的大小为SIZE×SIZE,并在以下位置初始化:
img[j][i] = 2 * j + i
然后,你创建一个矩阵res[][],这里的每个字段都是img矩阵中它周围9个字段的平均值.为简单起见,边框保留为0.
for(i=1;i<SIZE-1;i++)
for(j=1;j<SIZE-1;j++) {
res[j][i]=0;
for(k=-1;k<2;k++)
for(l=-1;l<2;l++)
res[j][i] += img[j+l][i+k];
res[j][i] /= 9;
}
Run Code Online (Sandbox Code Playgroud)
这就是该计划的全部内容.为了完整起见,以下是之前的内容.没有代码.如您所见,它只是初始化.
#define SIZE 8192
float img[SIZE][SIZE]; // input image
float res[SIZE][SIZE]; //result of mean filter
int i,j,k,l;
for(i=0;i<SIZE;i++)
for(j=0;j<SIZE;j++)
img[j][i] = (2*j+i)%8196;
Run Code Online (Sandbox Code Playgroud)
基本上,当SIZE是2048的倍数时,此程序很慢,例如执行时间:
SIZE = 8191: 3.44 secs
SIZE = 8192: 7.20 secs
SIZE = 8193: 3.18 secs
Run Code Online (Sandbox Code Playgroud)
编译器是GCC.据我所知,这是因为内存管理,但我对这个主题并不太了解,这就是我在这里问的原因.
另外如何解决这个问题会很好,但如果有人能够解释这些执行时间,我已经足够开心了.
我已经知道malloc/free了,但问题不在于使用的内存量,它只是执行时间,所以我不知道这会有多大帮助.
我正在进行一些矩阵乘法基准测试,如前面提到的 为什么MATLAB在矩阵乘法中如此之快?
现在我有另一个问题,当乘以两个2048x2048矩阵时,C#和其他矩阵之间存在很大差异.当我尝试只乘2047x2047矩阵时,看起来很正常.还添加了一些其他的比较.
1024x1024 - 10秒.
1027x1027 - 10秒.
2047x2047 - 90秒.
2048x2048 - 300秒.
2049x2049 - 91秒.(更新)
2500x2500 - 166秒
对于2k×2k的情况,这是三分半钟的差异.
使用2dim数组
//Array init like this
int rozmer = 2048;
float[,] matice = new float[rozmer, rozmer];
//Main multiply code
for(int j = 0; j < rozmer; j++)
{
for (int k = 0; k < rozmer; k++)
{
float temp = 0;
for (int m = 0; m < rozmer; m++)
{
temp = temp + matice1[j,m] * matice2[m,k]; …Run Code Online (Sandbox Code Playgroud) 我有一个矩阵乘法代码,如下所示:
for(i = 0; i < dimension; i++)
for(j = 0; j < dimension; j++)
for(k = 0; k < dimension; k++)
C[dimension*i+j] += A[dimension*i+k] * B[dimension*k+j];
Run Code Online (Sandbox Code Playgroud)
这里,矩阵的大小由表示dimension.现在,如果矩阵的大小是2000,运行这段代码需要147秒,而如果矩阵的大小是2048,则需要447秒.所以虽然差别没有.乘法是(2048*2048*2048)/(2000*2000*2000)= 1.073,时间上的差异是447/147 = 3.有人可以解释为什么会发生这种情况吗?我预计它会线性扩展,但这不会发生.我不是要尝试制作最快的矩阵乘法代码,只是试图理解它为什么会发生.
规格:AMD Opteron双核节点(2.2GHz),2G RAM,gcc v 4.5.0
程序编译为 gcc -O3 simple.c
我也在英特尔的icc编译器上运行了这个,并看到了类似的结果.
编辑:
正如评论/答案中所建议的那样,我运行了维度= 2060的代码,需要145秒.
继承完整的计划:
#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>
/* change dimension size as needed */
const int dimension = 2048;
struct timeval tv;
double timestamp()
{
double t;
gettimeofday(&tv, NULL);
t = tv.tv_sec + (tv.tv_usec/1000000.0); …Run Code Online (Sandbox Code Playgroud) 我发现在MSVC(在Windows上)和GCC(在Linux上)为Ivy Bridge系统编译的代码之间的性能差异很大.代码执行密集矩阵乘法.我使用GCC获得了70%的峰值失误,而MSVC只获得了50%.我想我可能已经把他们两个内在函数如何转换的差异分开了.
__m256 breg0 = _mm256_loadu_ps(&b[8*i])
_mm256_add_ps(_mm256_mul_ps(arge0,breg0), tmp0)
Run Code Online (Sandbox Code Playgroud)
GCC这样做
vmovups ymm9, YMMWORD PTR [rax-256]
vmulps ymm9, ymm0, ymm9
vaddps ymm8, ymm8, ymm9
Run Code Online (Sandbox Code Playgroud)
MSVC这样做
vmulps ymm1, ymm2, YMMWORD PTR [rax-256]
vaddps ymm3, ymm1, ymm3
Run Code Online (Sandbox Code Playgroud)
有人可以向我解释这两种解决方案是否以及为何能够在性能上产生如此大的差异?
尽管MSVC使用少一条指令,但它会将负载与多线程联系起来,这可能会使它更加依赖(也许负载无法按顺序完成)?我的意思是Ivy Bridge可以在一个时钟周期内完成一个AVX加载,一个AVX mult和一个AVX加载,但这要求每个操作都是独立的.
也许问题出在其他地方?您可以在下面看到最里面循环的GCC和MSVC的完整汇编代码.你可以在这里看到循环的C++代码循环展开以实现Ivy Bridge和Haswell的最大吞吐量
g ++ -S -masm = intel matrix.cpp -O3 -mavx -fopenmp
.L4:
vbroadcastss ymm0, DWORD PTR [rcx+rdx*4]
add rdx, 1
add rax, 256
vmovups ymm9, YMMWORD PTR [rax-256]
vmulps ymm9, ymm0, ymm9
vaddps ymm8, ymm8, ymm9
vmovups ymm9, YMMWORD PTR [rax-224] …Run Code Online (Sandbox Code Playgroud) 我正在以顺序方式运行.cpp代码(i)和(ii)使用OpenMP语句.我想看看时差.为了计算时间,我用这个:
#include <time.h>
.....
main()
{
clock_t start, finish;
start = clock();
.
.
.
finish = clock();
processing time = (double(finish-start)/CLOCKS_PER_SEC);
}
Run Code Online (Sandbox Code Playgroud)
在代码的顺序(上面)运行中,时间非常准确.运行它需要大约8秒钟.当我在代码中插入OpenMP语句然后计算时间缩短时,但是在控制台上显示的时间大约为8-9秒,实际上它实际上只有3-4秒!
以下是我的代码抽象的样子:
#include <time.h>
.....
main()
{
clock_t start, finish;
start = clock();
.
.
#pragma omp parallel for
for( ... )
for( ... )
for (...)
{
...;
}
.
.
finish = clock();
processing time = (double(finish-start)/CLOCKS_PER_SEC);
}
Run Code Online (Sandbox Code Playgroud)
当我运行上面的代码时,我得到了减少的时间,但显示的时间在实时方面并不准确.在我看来,似乎clock()函数正在计算每个线程的个别时间并将它们相加并显示它们.
有人能说出这个的原因或建议我使用任何其他计时功能来衡量OpenMP程序的时间吗?
谢谢.
背景
如果您一直关注我的帖子,我试图复制Kazushige Goto关于方阵乘法的开创性论文中的结果C = AB.我在这里可以找到关于这个主题的最后一篇文章.在我的代码版本中,我遵循Goto的内存分层和打包策略2x8以及C使用128位SSE3内在函数的内核计算块.我的CPU是i5-540M,超线程关闭.有关我的硬件的其他信息可以在另一篇文章中找到,并在下面重复.
我的硬件
我的CPU是Intel i5 - 540M.您可以在cpu-world.com上找到相关的CPUID信息.微体系结构是Nehalem(westmere),因此理论上每循环每个核心可以计算4个双精度触发器.我将只使用一个核心(没有OpenMP),所以对于超线程关闭和4步Intel Turbo Boost,我应该会看到一个高峰( 2.533 Ghz + 4*0.133 Ghz ) * ( 4 DP flops/core/cycle ) * ( 1 core ) = 12.27 DP Gflops.作为参考,两个核心都运行在峰值,英特尔Turbo Boost提供了两步加速,我应该获得理论峰值22.4 DP Gflops.
我的软件
Windows7 64位,但MinGW/GCC 32位由于我的电脑限制.
这次有什么新鲜事?
2x4块C.这提供了更好的性能,并且与Goto所说的一致(一半寄存器用于计算C).我试过很多大小:1x8,2x8,2x4,4x2,2x2,4x4.clock().问题
我正在研究高性能矩阵乘法算法,如OpenBLAS或GotoBLAS,我正在尝试重现一些结果.这个问题涉及矩阵乘法算法的内核.具体来说,我正在研究计算C += AB,在我的CPU的峰值速度下,在哪里A和B是2x2类型的矩阵double.有两种方法可以做到这一点.一种方法是使用SIMD指令.第二种方法是使用SIMD寄存器直接在汇编代码中编码.
到目前为止我看过的是什么
所有相关论文,课程网页,许多SO Q&As处理主题(太多无法列出),我已经在我的计算机上编译了OpenBLAS,查看了OpenBLAS,GotoBLAS和BLIS源代码,Agner的手册.
硬件
我的CPU是Intel i5 - 540M.您可以在cpu-world.com上找到相关的CPUID信息.微体系结构是Nehalem(westmere),因此理论上每循环每个核心可以计算4个双精度触发器.我将只使用一个核心(没有OpenMP),所以对于超线程关闭和4步Intel Turbo Boost,我应该会看到一个高峰( 2.533 Ghz + 4*0.133 Ghz ) * ( 4 DP flops/core/cycle ) * ( 1 core ) = 12.27 DP Gflops.作为参考,两个核心都运行在峰值,英特尔Turbo Boost提供了两步加速,我应该获得理论峰值22.4 DP Gflops.
建立
我将我的2x2矩阵声明为double并使用随机条目对其进行初始化,如下面的代码片段所示.
srand(time(NULL));
const int n = 2;
double A[n*n];
double B[n*n];
double C[n*n];
double T[n*n];
for(int i = 0; i < n*n; i++){
A[i] = (double) rand()/RAND_MAX; …Run Code Online (Sandbox Code Playgroud) assembly ×3
c ×3
c++ ×3
gcc ×2
performance ×2
algorithm ×1
arrays ×1
blas ×1
c# ×1
matrix ×1
openmp ×1
optimization ×1
time ×1
visual-c++ ×1
x86 ×1