c++ - 2 个数组/图像相乘的多线程性能 - Intel IPP

标签 c++ multithreading openmp intel-ipp

我正在使用 Intel IPP 对 2 个图像(数组)进行乘法运算。
我使用的是 Intel Composer 2015 Update 6 附带的 Intel IPP 8.2。

我创建了一个简单的函数来乘以太大的图像(整个项目已附上,见下文)。
我想看看使用英特尔 IPP 多线程库的好处。

这是简单的项目(我还附上了 Visual Studio 的完整项目):

#include "ippi.h"
#include "ippcore.h"
#include "ipps.h"
#include "ippcv.h"
#include "ippcc.h"
#include "ippvm.h"

#include <ctime>
#include <iostream>

using namespace std;

const int height = 6000;
const int width  = 6000;
Ipp32f mInput_image [1 * width * height];
Ipp32f mOutput_image[1 * width * height] = {0};

int main()
{
    IppiSize size = {width, height};

    double start = clock();

    for (int i = 0; i < 200; i++)
        ippiMul_32f_C1R(mInput_image, 6000 * 4, mInput_image, 6000 * 4, mOutput_image, 6000 * 4, size); 

    double end = clock();
    double douration = (end - start) / static_cast<double>(CLOCKS_PER_SEC);

    cout << douration << endl;
    cin.get();

    return 0;
}

我使用英特尔 IPP 单线程和一次使用英特尔 IPP 多线程编译了这个项目。

我尝试了不同大小的数组,在所有这些数组中,多线程版本都没有产生任何 yield (有时甚至更慢)。

我就纳闷了,这个任务怎么用多线程就没有收获呢?
我知道英特尔 IPP 使用 AVX,我认为任务可能会受内存限制?

我尝试了另一种方法,通过手动使用 OpenMP 来实现使用英特尔 IPP 单线程实现的多线程方法。
这是代码:

#include "ippi.h"
#include "ippcore.h"
#include "ipps.h"
#include "ippcv.h"
#include "ippcc.h"
#include "ippvm.h"

#include <ctime>
#include <iostream>

using namespace std;

#include <omp.h>

const int height = 5000;
const int width  = 5000;
Ipp32f mInput_image [1 * width * height];
Ipp32f mOutput_image[1 * width * height] = {0};

int main()
{
    IppiSize size = {width, height};

    double start = clock();

    IppiSize blockSize = {width, height / 4};

    const int NUM_BLOCK = 4;
    omp_set_num_threads(NUM_BLOCK);

    Ipp32f*  in;
    Ipp32f*  out;

    //  ippiMul_32f_C1R(mInput_image, width * 4, mInput_image, width * 4, mOutput_image, width * 4, size);

    #pragma omp parallel            \
    shared(mInput_image, mOutput_image, blockSize) \
    private(in, out)
    {
        int id   = omp_get_thread_num();
        int step = blockSize.width * blockSize.height * id;
        in       = mInput_image  + step;
        out      = mOutput_image + step;
        ippiMul_32f_C1R(in, width * 4, in, width * 4, out, width * 4, blockSize);
    }

    double end = clock();
    double douration = (end - start) / static_cast<double>(CLOCKS_PER_SEC);

    cout << douration << endl;
    cin.get();

    return 0;
}

结果是一样的,同样没有性能提升。

有没有办法在这种任务中从多线程中获益?
我如何验证任务是否受内存限制,因此并行化它没有好处? 使用 AVX 在 CPU 上并行化乘以 2 个数组的任务是否有好处?

我试过的计算机是基于 Core i7 4770k (Haswell) 的。

这是 Project in Visual Studio 2013 的链接.

谢谢。

最佳答案

您的图像总共占用 200 MB(2 x 5000 x 5000 x 4 字节)。因此,每个 block 包含 50 MB 的数据。这是 CPU L3 缓存大小的 6 倍多(参见 here )。每个 AVX vector 乘法操作 256 位数据,这是半个缓存行,即它每条 vector 指令消耗一个缓存行(每个参数半个缓存行)。 Haswell 上的向量化乘法有 5 个周期的延迟,FPU 每个周期可以退出两条这样的指令(参见 here )。 i7-4770K 的内存总线额定为 25.6 GB/s(理论最大值!)或每秒不超过 4.3 亿条缓存行。 CPU 的标称速度为 3.5 GHz。 AVX 部分的时钟频率较低,假设为 3.1 GHz。以这种速度,每秒需要多一个数量级的缓存行才能完全满足 AVX 引擎的需求。

在这些情况下,矢量化代码的单个线程几乎完全饱和了 CPU 的内存总线。添加第二个线程可能会导致非常轻微的改进。添加更多线程只会导致争用和增加开销。加速这种计算的唯一方法是增加内存带宽:

  • 在具有更多内存 Controller 的 NUMA 系统上运行,因此具有更高的总内存带宽,例如多路服务器主板;
  • 切换到具有更高内存带宽的不同架构,例如Intel Xeon Phi 或 GPGPU。

关于c++ - 2 个数组/图像相乘的多线程性能 - Intel IPP,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36966474/

相关文章:

C++ 模板继承。子类应该用固定类型替换基类中的类型

java - 限制线程访问给定的 block 代码

c++0x 线程初始化

c++ - 我是否正在使用OpenMP干扰其他程序?

c - 在 OpenMP 中使用任务指令的正确方法是什么

c++ - 如何将 openMP 应用于 C++ 函数以验证数独谜题解决方案的所有行?

c++ - 使用 OpenCV 在 C++ 中缩放图像,但不使用 pyrDown() 或 pyrUp() 函数

c++ - 是否有将基本类型转换为字符串的无警告模板函数

c++ - 在 C++ 中链接和通信到 AutoCAD

c# - 持有线程的类的 IDisposable 实现