- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
您好,我是 JOCL (opencl) 的新手。我编写这段代码是为了获取每张图像的强度总和。内核采用一个一维数组,其中包含所有图像的所有像素,这些像素彼此放在一起。一张图片是 300x300 ,所以每张图片有 90000 像素。目前它比我按顺序执行此操作时慢。
我的代码
package PAR;
/*
* JOCL - Java bindings for OpenCL
*
* Copyright 2009 Marco Hutter - http://www.jocl.org/
*/
import IMAGE_IO.ImageReader;
import IMAGE_IO.Input_Folder;
import static org.jocl.CL.*;
import org.jocl.*;
/**
* A small JOCL sample.
*/
public class IPPARA {
/**
* The source code of the OpenCL program to execute
*/
private static String programSource =
"__kernel void "
+ "sampleKernel(__global uint *a,"
+ " __global uint *c)"
+ "{"
+ "__private uint intensity_core=0;"
+ " uint i = get_global_id(0);"
+ " for(uint j=i*90000; j < (i+1)*90000; j++){ "
+ " intensity_core += a[j];"
+ " }"
+ "c[i]=intensity_core;"
+ "}";
/**
* The entry point of this sample
*
* @param args Not used
*/
public static void main(String args[]) {
long numBytes[] = new long[1];
ImageReader imagereader = new ImageReader() ;
int srcArrayA[] = imagereader.readImages();
int size[] = new int[1];
size[0] = srcArrayA.length;
long before = System.nanoTime();
int dstArray[] = new int[size[0]/90000];
Pointer srcA = Pointer.to(srcArrayA);
Pointer dst = Pointer.to(dstArray);
// Obtain the platform IDs and initialize the context properties
System.out.println("Obtaining platform...");
cl_platform_id platforms[] = new cl_platform_id[1];
clGetPlatformIDs(platforms.length, platforms, null);
cl_context_properties contextProperties = new cl_context_properties();
contextProperties.addProperty(CL_CONTEXT_PLATFORM, platforms[0]);
// Create an OpenCL context on a GPU device
cl_context context = clCreateContextFromType(
contextProperties, CL_DEVICE_TYPE_CPU, null, null, null);
if (context == null) {
// If no context for a GPU device could be created,
// try to create one for a CPU device.
context = clCreateContextFromType(
contextProperties, CL_DEVICE_TYPE_CPU, null, null, null);
if (context == null) {
System.out.println("Unable to create a context");
return;
}
}
// Enable exceptions and subsequently omit error checks in this sample
CL.setExceptionsEnabled(true);
// Get the list of GPU devices associated with the context
clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, null, numBytes);
// Obtain the cl_device_id for the first device
int numDevices = (int) numBytes[0] / Sizeof.cl_device_id;
cl_device_id devices[] = new cl_device_id[numDevices];
clGetContextInfo(context, CL_CONTEXT_DEVICES, numBytes[0],
Pointer.to(devices), null);
// Create a command-queue
cl_command_queue commandQueue =
clCreateCommandQueue(context, devices[0], 0, null);
// Allocate the memory objects for the input- and output data
cl_mem memObjects[] = new cl_mem[2];
memObjects[0] = clCreateBuffer(context,
CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
Sizeof.cl_uint * srcArrayA.length, srcA, null);
memObjects[1] = clCreateBuffer(context,
CL_MEM_READ_WRITE,
Sizeof.cl_uint * (srcArrayA.length/90000), null, null);
// Create the program from the source code
cl_program program = clCreateProgramWithSource(context,
1, new String[]{programSource}, null, null);
// Build the program
clBuildProgram(program, 0, null, null, null, null);
// Create the kernel
cl_kernel kernel = clCreateKernel(program, "sampleKernel", null);
// Set the arguments for the kernel
clSetKernelArg(kernel, 0,
Sizeof.cl_mem, Pointer.to(memObjects[0]));
clSetKernelArg(kernel, 1,
Sizeof.cl_mem, Pointer.to(memObjects[1]));
// Set the work-item dimensions
long local_work_size[] = new long[]{1};
long global_work_size[] = new long[]{(srcArrayA.length/90000)*local_work_size[0]};
// Execute the kernel
clEnqueueNDRangeKernel(commandQueue, kernel, 1, null,
global_work_size, local_work_size, 0, null, null);
// Read the output data
clEnqueueReadBuffer(commandQueue, memObjects[1], CL_TRUE, 0,
(srcArrayA.length/90000) * Sizeof.cl_float, dst, 0, null, null);
// Release kernel, program, and memory objects
clReleaseMemObject(memObjects[0]);
clReleaseMemObject(memObjects[1]);
clReleaseKernel(kernel);
clReleaseProgram(program);
clReleaseCommandQueue(commandQueue);
clReleaseContext(context);
long after = System.nanoTime();
System.out.println("Time: " + (after - before) / 1e9);
}
}
根据答案中的建议,通过 CPU 的并行代码几乎与顺序代码一样快。是否还有更多可以改进的地方?
最佳答案
for(uint j=i*90000; j < (i+1)*90000; j++){ "
+ " c[i] += a[j];"
1) 您正在使用全局内存 (c[]) 求和,这很慢。使用私有(private)变量使其更快。 像这样:
"__kernel void "
+ "sampleKernel(__global uint *a,"
+ " __global uint *c)"
+ "{"
+ "__private uint intensity_core=0;" <---this is a private variable of each core
+ " uint i = get_global_id(0);"
+ " for(uint j=i*90000; j < (i+1)*90000; j++){ "
+ " intensity_core += a[j];" <---register is at least 100x faster than global memory
//but we cannot get rid of a[] so the calculation time cannot be less than %50
+ " }"
+ "c[i]=intensity_core;"
+ "}"; //expecting %100 speedup
现在你有 c[图像数量] 个强度总和数组。
你的 local-work-size 是 1 那么如果你有至少 160 张图像(这是你的 gpu 的核心数)那么计算将使用所有核心。
您将需要 90000*num_images 次读取和 num_images 次写入以及 90000*num_images 寄存器读/写。使用寄存器将使您的内核时间减半。
2) 你每 2 次内存访问只做 1 次数学运算。每次内存访问至少需要 10 个数学运算才能使用 gpu 峰值 Gflops 的一小部分(6490M 峰值为 250 Gflops)
您的 i7 cpu 可以轻松达到 100 Gflops,但您的内存将成为瓶颈。当您通过 pci-express 发送整个数据时,情况更糟。(HD Graphics 3000 额定为 125 GFLOPS)
// Obtain a device ID
cl_device_id devices[] = new cl_device_id[numDevices];
clGetDeviceIDs(platform, deviceType, numDevices, devices, null);
cl_device_id device = devices[deviceIndex];
//one of devices[] element must be your HD3000.Example: devices[0]->gpu devices[1]->cpu
//devices[2]-->HD3000
在你的程序中:
// Obtain the cl_device_id for the first device
int numDevices = (int) numBytes[0] / Sizeof.cl_device_id;
cl_device_id devices[] = new cl_device_id[numDevices];
clGetContextInfo(context, CL_CONTEXT_DEVICES, numBytes[0],
Pointer.to(devices), null);
第一个设备可能是 gpu。
关于java - 使用 JOCL/OPENCL 加速强度总和计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13543248/
package parallelencode; import org.jocl.*; import static org.jocl.CL.*; public class ParallelEncode
我已经审核 openCL 的调用代码一段时间了,但没有发现任何内存泄漏。请注意,我正在使用 JOCL,因此我有一堆 JUnit 测试。如果我单独运行任何测试,或者如果我运行任何测试的 4/5,它总是会
我正在尝试编写实时光线追踪器。我为此使用 Java 和 OpenGL 和 OpenCL 的 Jogamp 绑定(bind)(调用 Jogl 和 Jocl)。我的 .cl 内核中已经有光线追踪代码并且运
您好,我是 JOCL (opencl) 的新手。我编写这段代码是为了获取每张图像的强度总和。内核采用一个一维数组,其中包含所有图像的所有像素,这些像素彼此放在一起。一张图片是 300x300 ,所以每
当我在 clEnqueueReadBuffer 上进行实验时,出现了一个异常: 线程“main”中的异常 java.lang.IllegalArgumentException:非阻塞读取操作只能使用指
所以我有一个看起来像这样的内核: __kernel void my_kernel( __global const uchar *array, const uint number, __global c
我正在尝试运行 this tutorial在我的 Mac 上。 本教程适用于 Windows,并打包了 jocl 版本 1.3 (JOCL-0.1.3a-beta.jar) 和适用于 Windows
Jocl(opencl wrapper) 内核运行使 java3d 输出被禁用。当 opencl 完成时,java3d 继续工作。 如何让 Opencl(jocl) 和 opengl(java3d)
JavaCL 使用 JNA,JOCL 使用 JNI,所以我希望 JavaCL 表现出更好的跨平台兼容性,而 JOCL 通常应该具有更好的性能。 JOCL 与 JOGL2 一起进行了测试,这应该使得在
是否存在一种方法可以在 JOCL 中将标量参数传递给内核而不创建新数组?在 C++ 中,可以简单地将标量参数(例如 int)转换为 void* 最佳答案 是的,有像 putArg(float)、put
我是一名优秀的程序员,十分优秀!