OpenCL入门例程

发布时间 2023-05-09 11:06:31作者: 兜尼完

OpenCL是一个并行计算库。在Visual Studio中的配置类似于OpenCV,只需要把开发包下载下来,里面有include、lib、bin文件夹,在项目设置里添加上就行了。一般Windows系统自己带的就有OpenCL.dll,在Windows/System32/文件夹里。不同于英伟达的CUDA编程自己搞了个编译器集成到Visual Studio中。OpenCL不需要编译器,它是将GPU核函数源代码作为字符串传给SDK即时解释执行的。

下面将给出一个例子,需要读者熟悉C++11以上标准。该例子里核函数运算量比较大,因为测试发现过于简单的运算CPU更快。此例子在Release版下GPU运算速度略高于CPU。测试环境是VS2017、OpenCL306,CPU型号是Intel Core i5-7400,核芯显卡。当然在OpenCL SDK里的opencl.hpp头文件里也有一个官方例子说明了使用显卡加速的流程。

const int numElements = 1000000;

int main()
{
    std::string kernel{ R"CLC(
        kernel void vectorOpr(global const float *input, global float *output)
        {
            int i = get_global_id(0);
            for (int j = 0; j < 10; j++)
            {
                if (input[i] < 50)
                {
                    output[i] += 0;
                }
                else if (input[i] > 100)
                {
                    output[i] += 1;
                }
                else
                {
                    output[i] += sin(input[i] - 50) / cos(input[i] - 50);
                }
            }
        }
    )CLC" };

    cl::Program anyProgram(kernel);
    try
    {
        anyProgram.build("-cl-std=CL2.0");
    }
    catch (...)
    {
        cl_int buildErr = CL_SUCCESS;
        auto buildInfo = anyProgram.getBuildInfo<CL_PROGRAM_BUILD_LOG>(&buildErr);
        for (auto &pair : buildInfo)
        {
            std::cerr << pair.second << std::endl << std::endl;
        }
        return 1;
    }

    std::mt19937 mt;
    cl::coarse_svm_vector<float> input(numElements, 75);
    cl::vector<float> output(numElements, 1);
    for (auto& item : input)
    {
        item = mt() % 200;
    }
    cl::Buffer buff(output.begin(), output.end(), false);

    auto anyKernel = cl::KernelFunctor<float*, cl::Buffer&>(anyProgram, "vectorOpr");

    std::chrono::system_clock::time_point t1, t2;

    t1 = std::chrono::system_clock::now();
    anyKernel(cl::EnqueueArgs(cl::NDRange(numElements), cl::NDRange(1)), input.data(), buff);
    copy(buff, output.begin(), output.end());
    t2 = std::chrono::system_clock::now();
    std::cout << "显卡(ms):" << std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count() << std::endl;

    cl::vector<float> A(numElements, 75);
    cl::vector<float> C(numElements, 1);
    for (auto& item : A)
    {
        item = mt() % 200;
    }

    t1 = std::chrono::system_clock::now();
    for (int i = 0; i < numElements; i++)
    {
        for (int j = 0; j < 10; j++)
        {
            if (A[i] < 50)
            {
                C[i] += 0;
            }
            else if (A[i] > 100)
            {
                C[i] += 1;
            }
            else
            {
                C[i] += sin(A[i] - 50) / cos(A[i] - 50);
            }
        }
    }
    t2 = std::chrono::system_clock::now();
    std::cout << "CPU(ms):" << std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count() << std::endl;
    return 0;
}