gpt4 book ai didi

compilation - 如何用内核编译opencl项目

转载 作者:行者123 更新时间:2023-12-03 13:26:24 25 4
gpt4 key购买 nike

我完全是opencl的初学者,我在互联网上搜索并找到了一些opencl项目的“helloworld”演示。通常在这种最小的项目中,有一个 *.cl 文件包含某种 opencl 内核,一个 *.c 文件包含主要功能。那么问题是我如何使用命令行编译这种项目。我知道我应该在 linux 上使用某种 -lOpenCL 标志,在 mac 上使用 -framework OpenCL。但我不知道将 *.cl 内核链接到我的主源文件。感谢您的任何评论或有用的链接。

最佳答案

在 OpenCL 中,.cl包含设备内核代码的文件通常在运行时编译和构建。这意味着在您的主机 OpenCL 程序的某个地方,您必须编译和构建您的设备程序才能使用它。此功能可实现最大的便携性。

让我们考虑一个我从两本书中收集的例子。下面是一个非常简单的 OpenCL 内核,将两个全局数组中的两个数字相加,并将它们保存在另一个全局数组中。我将此代码保存在一个名为 vector_add_kernel.cl 的文件中.

kernel void vecadd( global int* A, global int* B, global int* C ) {
const int idx = get_global_id(0);
C[idx] = A[idx] + B[idx];
}

下面是用 C++ 编写的利用 OpenCL C++ API 的主机代码。我将它保存在一个名为 ocl_vector_addition.cpp 的文件中在我保存 .cl 的地方旁边文件。
#include <iostream>
#include <fstream>
#include <string>
#include <memory>
#include <stdlib.h>

#define __CL_ENABLE_EXCEPTIONS
#if defined(__APPLE__) || defined(__MACOSX)
#include <OpenCL/cl.cpp>
#else
#include <CL/cl.hpp>
#endif

int main( int argc, char** argv ) {

const int N_ELEMENTS=1024*1024;
unsigned int platform_id=0, device_id=0;

try{
std::unique_ptr<int[]> A(new int[N_ELEMENTS]); // Or you can use simple dynamic arrays like: int* A = new int[N_ELEMENTS];
std::unique_ptr<int[]> B(new int[N_ELEMENTS]);
std::unique_ptr<int[]> C(new int[N_ELEMENTS]);

for( int i = 0; i < N_ELEMENTS; ++i ) {
A[i] = i;
B[i] = i;
}

// Query for platforms
std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms);

// Get a list of devices on this platform
std::vector<cl::Device> devices;
platforms[platform_id].getDevices(CL_DEVICE_TYPE_GPU|CL_DEVICE_TYPE_CPU, &devices); // Select the platform.

// Create a context
cl::Context context(devices);

// Create a command queue
cl::CommandQueue queue = cl::CommandQueue( context, devices[device_id] ); // Select the device.

// Create the memory buffers
cl::Buffer bufferA=cl::Buffer(context, CL_MEM_READ_ONLY, N_ELEMENTS * sizeof(int));
cl::Buffer bufferB=cl::Buffer(context, CL_MEM_READ_ONLY, N_ELEMENTS * sizeof(int));
cl::Buffer bufferC=cl::Buffer(context, CL_MEM_WRITE_ONLY, N_ELEMENTS * sizeof(int));

// Copy the input data to the input buffers using the command queue.
queue.enqueueWriteBuffer( bufferA, CL_FALSE, 0, N_ELEMENTS * sizeof(int), A.get() );
queue.enqueueWriteBuffer( bufferB, CL_FALSE, 0, N_ELEMENTS * sizeof(int), B.get() );

// Read the program source
std::ifstream sourceFile("vector_add_kernel.cl");
std::string sourceCode( std::istreambuf_iterator<char>(sourceFile), (std::istreambuf_iterator<char>()));
cl::Program::Sources source(1, std::make_pair(sourceCode.c_str(), sourceCode.length()));

// Make program from the source code
cl::Program program=cl::Program(context, source);

// Build the program for the devices
program.build(devices);

// Make kernel
cl::Kernel vecadd_kernel(program, "vecadd");

// Set the kernel arguments
vecadd_kernel.setArg( 0, bufferA );
vecadd_kernel.setArg( 1, bufferB );
vecadd_kernel.setArg( 2, bufferC );

// Execute the kernel
cl::NDRange global( N_ELEMENTS );
cl::NDRange local( 256 );
queue.enqueueNDRangeKernel( vecadd_kernel, cl::NullRange, global, local );

// Copy the output data back to the host
queue.enqueueReadBuffer( bufferC, CL_TRUE, 0, N_ELEMENTS * sizeof(int), C.get() );

// Verify the result
bool result=true;
for (int i=0; i<N_ELEMENTS; i ++)
if (C[i] !=A[i]+B[i]) {
result=false;
break;
}
if (result)
std::cout<< "Success!\n";
else
std::cout<< "Failed!\n";

}
catch(cl::Error err) {
std::cout << "Error: " << err.what() << "(" << err.err() << ")" << std::endl;
return( EXIT_FAILURE );
}

std::cout << "Done.\n";
return( EXIT_SUCCESS );
}

我在装有 Ubuntu 12.04 的机器上编译此代码,如下所示:
g++ ocl_vector_addition.cpp -lOpenCL -std=c++11 -o ocl_vector_addition.o

它产生 ocl_vector_addition.o ,当我运行时,显示成功输出。如果您查看编译命令,您会发现我们没有传递任何关于我们的 .cl 的信息。文件。我们只用过 -lOpenCL标志为我们的程序启用 OpenCL 库。另外,不要被 -std=c++11 分心。命令。因为我用了 std::unique_ptr在主机代码中,我必须使用此标志才能成功编译。

那么这是哪里 .cl正在使用的文件?如果您查看主机代码,您会发现我在下面编号重复的四个部分:
// 1. Read the program source
std::ifstream sourceFile("vector_add_kernel.cl");
std::string sourceCode( std::istreambuf_iterator<char>(sourceFile), (std::istreambuf_iterator<char>()));
cl::Program::Sources source(1, std::make_pair(sourceCode.c_str(), sourceCode.length()));

// 2. Make program from the source code
cl::Program program=cl::Program(context, source);

// 3. Build the program for the devices
program.build(devices);

// 4. Make kernel
cl::Kernel vecadd_kernel(program, "vecadd");

在第一步中,我们读取保存设备代码的文件的内容并将其放入 std::string命名为 sourceCode .然后我们制作一对字符串及其长度并将其保存到 source类型为 cl::Program::Sources .在我们准备好代码之后,我们制作一个 cl::program名为 program 的对象对于 context并将源代码加载到程序对象中。第三步是为 device 编译(和链接)OpenCL 代码。 .由于设备代码是在第 3 步中构建的,我们可以创建一个名为 vecadd_kernel 的内核对象。并关联名为 vecadd 的内核里面有我们的 cl::kernel目的。这几乎就是编译 .cl 所涉及的一系列步骤。程序中的文件。

我展示和解释的程序从内核源代码创 build 备程序。另一种选择是使用二进制文件。使用二进制程序会增加应用程序加载时间并允许程序的二进制分发,但会限制可移植性,因为在一个设备上运行良好的二进制文件可能在另一台设备上无法运行。使用源代码和二进制创建程序也分别称为离线和在线编译(更多信息 here)。我在这里跳过它,因为答案已经太长了。

关于compilation - 如何用内核编译opencl项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26517114/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com