Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/tfs/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用open mp的慢速稀疏矩阵向量积(CSR)_C_Openmp - Fatal编程技术网

使用open mp的慢速稀疏矩阵向量积(CSR)

使用open mp的慢速稀疏矩阵向量积(CSR),c,openmp,C,Openmp,我正在尝试使用open mp加速稀疏矩阵向量积,代码如下: void zAx(double * z, double * data, long * colind, long * row_ptr, double * x, int M){ long i, j, ckey; int chunk = 1000; //int * counts[8]={0}; #pragma omp parallel num_threads(8) { #pragma omp for private(ckey,j,i)

我正在尝试使用open mp加速稀疏矩阵向量积,代码如下:

void zAx(double * z, double * data, long * colind, long * row_ptr, double * x, int M){

long i, j, ckey;
int chunk = 1000;
//int * counts[8]={0};
#pragma omp parallel num_threads(8)
{ 
  #pragma omp for private(ckey,j,i) schedule(static,chunk)
  for (i=0; i<M; i++ ){ 
    z[i]=0;
    for (ckey=row_ptr[i]; ckey<row_ptr[i+1]; ckey++) {
      j = colind[ckey];
      z[i] += data[ckey]*x[j];
    }              
  }
}
}
void zAx(双*z,双*data,长*colind,长*row\u ptr,双*x,int M){
长i,j,ckey;
int-chunk=1000;
//int*计数[8]={0};
#pragma omp并行num_线程(8)
{ 
#专用(ckey,j,i)计划的pragma omp(静态,块)

对于(i=0;i我不能将此写在评论中,所以我会这样做作为答案。我认为这是问题所在,但不是100%确定

跨线程共享变量可能会导致问题。我不认为这是一个问题,但可能是。通常只有在写入时才有问题,但如果没有锁定,则只会导致数据损坏。不确定OpenMP是否在内部执行任何锁定

你的线程很可能会因为锁而暂停,这是多线程运行速度比单个线程慢得多的唯一原因。这或者根本不是你的代码。最好在内存中的小数据集上测试它,而不存在潜在的瓶颈(因此,您所做的只是处理数据并仅对zAx函数进行计时)

0.3M^2=90B。这意味着您在分页或加载文件时肯定会遇到问题。(如果您使用int,则大小为4倍)

更好的方法可能是在磁盘并行加载Y数量时对矩阵的X数量进行操作。通过正确选择X和Y,速度不会有太大降低。如果要加载8GB、处理,然后再加载8GB,则每次加载数据都必须等待

通过监视处理和文件加载不进行任何操作的时间,选择X和Y=(8GB-X),可以使处理变得智能化


要检查磁盘访问是否存在问题,请尝试使用较小的数据集和time only zAx,看看是否有帮助。如果有,则是磁盘。如果没有,则是代码。

欢迎来到内存限制问题的奇妙世界。为了减轻您的痛苦,我想通知您,稀疏矩阵向量乘法是其中之一许多东西无法在单个多核芯片上有效并行甚至矢量化,除非所有数据都能放入最后一级缓存或内存总线非常宽

为什么?原因很简单,因为计算与内存访问的比率非常低。对于内部循环的每次迭代,只要将列索引提取到
j
(8字节),将矩阵元素提取到
数据中(8字节),向量元素的值(8字节)和结果的上一个值(因为编译器很少优化对共享变量的访问)(8字节)。然后执行2个非常快的浮点运算(FLOP)并执行存储(尽管
+=
运算符被转换为一条指令,但它仍然是一条“fetch-modify-write”指令)。总共加载32个字节,并对其执行2次浮点运算。这使每个字节进行1/16次浮点运算

一个支持SSE的现代CPU核心可以执行4次双精度触发器/周期,这通常会导致每个CPU核心8千兆次左右(假设基本频率为2 GHz)。使用AVX,该数字会翻倍,因此在2 GHz Intel Sandy/Ivy桥接器或AMD等效设备上,每个内核最多可获得16千兆次。为了用数据饱和此处理能力,给定1/16次浮点/字节,您将需要至少128 GiB/s的内存带宽

像Xeon X7560这样的高端Nehalem EX处理器以2,26 GHz(9,04千兆次/核心)的速度运行,其共享三级缓存(一级和二级缓存为每个核心)提供大约275 GiB/s。在9,04 GFLOPS/core时,每个core需要144,64 GiB/s才能为
zAx
例程的内环提供数据。这意味着在理想情况下,此CPU的L3缓存不能提供超过2个完全矢量化的乘法内核

如果没有SSE矢量化,双精度的触发器速率将降低两倍,因此可以预期问题将扩展到4个线程。一旦问题变得比L3缓存更大,情况将变得非常糟糕,因为内存总线提供的带宽将减少约十倍

尝试以下版本的内部循环,看看编译器是否足够聪明,可以遵循OpenMP的轻松内存视图:

#pragma omp for private(ckey,j) schedule(static,chunk)
for (i=0; i<M; i++){
  double zi = 0.0;
  for (ckey=row_ptr[i]; ckey<row_ptr[i+1]; ckey++) {
    j = colind[ckey];
    zi += data[ckey]*x[j];
  }
  z[i] = zi;
}
#专用(ckey,j)计划的pragma omp(静态,块)

对于(i=0;您正在运行的机器有多少个内核?您的M4内核有多少(多线程,我已经检查了omp_max_thread_num),我想是8gb内存。看看“顶端”这个进程使用了大约700%的cpu和20%的ram。谢谢。有一点敏感的代码我无法复制,但我会做一个简单的例子,然后再给你回复。你能告诉我必须花多少时间,它需要顺序、2个线程、4个线程和8个线程吗?我已经用一些信息更新了帖子-对不起,about格式。似乎大矩阵的大小可能是阻碍我前进的原因。谢谢你的输入。我会尝试一下你的建议,但我不认为这个大小是一个你怀疑的大问题。矩阵存储为CSR稀疏矩阵,并且大部分为零。此外,我不认为我正在增加行ptr?它几乎是随机访问的,可以吗但这是个问题。我喜欢你的答案,除了“你正在递增所有线程在内存中共享的值row_ptr”。我没有递增,row_ptr[I+1]只是读而不是写,所以没有问题。@dreamcrash对,不确定我看到了什么;/(我想是累了;)@大狗是的,我的错误,疲劳和头痛时视力模糊;/Ok,如果它相对稀疏,我想象你只是将它从内存缓冲区扩展到当前正在使用的值?如果是,那么可能这也是一个问题?如果我是你,我会做的是尝试找到瓶颈。在较小的内存中检查你的函数本身(几个gigs)矩阵,并在1个线程和10个线程上进行比较。1个线程应该慢得多(至少是2的一个因数)。如果不是,则是代码。如果是