JOCL 开发

JOCL 介绍

jocl实际上就是对opencl用java语言进行了封装,许多代码都和opencl一样,这一点使得用过opencl的可以非常快的上手,可以到github查看源码

由于java没有指针,所以jocl不得不用Pointer来获取地址,这样就感觉jocl其实看起来比opencl还要复杂

JOCL 开发环境搭建

参考别人的文章https://my.oschina.net/qutter... 完成jocl开发环境搭建

  1. 更新显卡驱动
  2. 安装opencl驱动,应该最新版本的显卡驱动都是支持opencl的,可以用 GPU Caps Viewer 来测试,如果没有,AMD的话可以到https://support.amd.com/en-us... 下载驱动
  3. 下载opencl sdk

  4. 下载安装jdk http://www.oracle.com/technet...,不要忘了设置环境变量
  5. 下载安装eclipse http://www.eclipse.org/downlo...
  6. 下载jar包 http://www.jocl.org/downloads...,需要提取里面的相应jar文件放到项目Referenced Libraries里面,把dll文件放到jdk安装路径/bin下
  7. 现在可以直接到官网 http://www.jocl.org/samples/s... 找sample来运行了

封装JOCL

原始的jocl就是对opencl的C语言的重写,是比较麻烦的,下面给出封装代码

PackJocl.java

package jocl;

import static org.jocl.CL.CL_CONTEXT_PLATFORM;
import static org.jocl.CL.CL_DEVICE_TYPE_GPU;
import static org.jocl.CL.CL_MEM_COPY_HOST_PTR;
import static org.jocl.CL.CL_MEM_READ_ONLY;
import static org.jocl.CL.CL_TRUE;
import static org.jocl.CL.clBuildProgram;
import static org.jocl.CL.clCreateBuffer;
import static org.jocl.CL.clCreateCommandQueue;
import static org.jocl.CL.clCreateContext;
import static org.jocl.CL.clCreateKernel;
import static org.jocl.CL.clCreateProgramWithSource;
import static org.jocl.CL.clEnqueueNDRangeKernel;
import static org.jocl.CL.clEnqueueReadBuffer;
import static org.jocl.CL.clGetDeviceIDs;
import static org.jocl.CL.clGetPlatformIDs;
import static org.jocl.CL.clReleaseCommandQueue;
import static org.jocl.CL.clReleaseContext;
import static org.jocl.CL.clReleaseKernel;
import static org.jocl.CL.clReleaseMemObject;
import static org.jocl.CL.clReleaseProgram;
import static org.jocl.CL.clSetKernelArg;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

import org.jocl.CL;
import org.jocl.Pointer;
import org.jocl.Sizeof;
import org.jocl.cl_command_queue;
import org.jocl.cl_context;
import org.jocl.cl_context_properties;
import org.jocl.cl_device_id;
import org.jocl.cl_kernel;
import org.jocl.cl_mem;
import org.jocl.cl_platform_id;
import org.jocl.cl_program;

/**
 * A small JOCL sample.
 */
public class PackJocl
{
    cl_context context;                // 上下文
    cl_command_queue commandQueue;    // 命令队列
    cl_program program;                // 程序对象
    cl_kernel kernel;                // Kernel对象
    cl_mem memObjects[];            // 内存对象数组
    
    /**
     * 读取文件的内容
     * @param file 想要读取的文件对象
     * @return 返回文件内容
     */
    public static String readCl(File file){
        StringBuilder result = new StringBuilder();
        try{
            BufferedReader br = new BufferedReader(new FileReader(file));//构造一个BufferedReader类来读取文件
            String s = null;
            while((s = br.readLine())!=null){//使用readLine方法,一次读一行
                result.append(System.lineSeparator()+s);
            }
            br.close();    
        }catch(Exception e){
            e.printStackTrace();
        }
        return result.toString();
    }
    
    PackJocl(){
        
    }
    
    /**
     * 加载平台和驱动
     * @param platformIdx 平台index
     * @param deviceIdx 驱动index
     */
    @SuppressWarnings("deprecation")
    public void init(int platformIdx, int deviceIdx){
        final int platformIndex = platformIdx; // 选择哪个平台
        final long deviceType = CL_DEVICE_TYPE_GPU;
        final int deviceIndex = deviceIdx;

        // Enable exceptions and subsequently omit error checks in this sample
        CL.setExceptionsEnabled(true);

        // Obtain the number of platforms
        int numPlatformsArray[] = new int[1];
        clGetPlatformIDs(0, null, numPlatformsArray);
        int numPlatforms = numPlatformsArray[0];

        // Obtain a platform ID
        cl_platform_id platforms[] = new cl_platform_id[numPlatforms];
        clGetPlatformIDs(platforms.length, platforms, null);
        cl_platform_id platform = platforms[platformIndex];

        // Initialize the context properties
        cl_context_properties contextProperties = new cl_context_properties();
        contextProperties.addProperty(CL_CONTEXT_PLATFORM, platform);
        
        // Obtain the number of devices for the platform
        int numDevicesArray[] = new int[1];
        clGetDeviceIDs(platform, deviceType, 0, null, numDevicesArray);
        int numDevices = numDevicesArray[0];
        
        // 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];
        context = clCreateContext(
        contextProperties, 1, new cl_device_id[]{device}, 
        null, null, null);
    
        // Create a command-queue for the selected device
        commandQueue = clCreateCommandQueue(context, device, 0, null);
    }
    
    /**
     * 创建Kernel
     * @param clName Kernel文件名
     * @param funcName Kernel函数名
     */
    public void createKernel(String clName, String funcName){
        program = clCreateProgramWithSource(context, 1, new String[]{  readCl(new File(clName)) }, null, null);
        
        // Build the program
        clBuildProgram(program, 0, null, null, null, null);
            
        // Create the kernel
        kernel = clCreateKernel(program, funcName, null);
    }
    
    /**
     * 创建Kernel
     * @param p 包含所有参数的指针数组
     * @param n 分配内存空间大小 
     */
    public void setParameters(Pointer[] p, int n){
        memObjects = new cl_mem[p.length];
        for(int i = 0; i < p.length; i++){
            memObjects[i] = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, Sizeof.cl_float * n, p[i], null);
        }
        
        for(int i = 0; i < p.length; i++){
            clSetKernelArg(kernel, i, Sizeof.cl_mem, Pointer.to(memObjects[i]));
        }
        
    }
    
    /**
     * 执行Kernel
     * @param dim 维数
     * @param global_work_size[] global_work_size
     * @param local_work_size[] local_work_size
     */
    public void execute(int dim, long global_work_size[], long local_work_size[]){
         // Execute the kernel
         clEnqueueNDRangeKernel(commandQueue, kernel, dim, null,global_work_size, local_work_size, 0, null, null);
    }

    /**
     * 把显存里的计算结果取回内存
     * @param index 参数位置
     * @param dstPointer 结果指针
     * @param size 分配内存空间大小 
     */
    public void getData(int index, Pointer dstPointer, int size){
         clEnqueueReadBuffer(commandQueue, memObjects[index], CL_TRUE, 0, size * Sizeof.cl_float, dstPointer, 0, null, null);
    }
    
    public void clear(){
         clReleaseMemObject(memObjects[0]);
         clReleaseMemObject(memObjects[1]);
         clReleaseMemObject(memObjects[2]);
         clReleaseKernel(kernel);
         clReleaseProgram(program);
         clReleaseCommandQueue(commandQueue);
         clReleaseContext(context);
    }
  
}

PackageTest.java

package jocl;

import org.jocl.Pointer;

public class PackageTest {
    public static void main(String args[]){
        PackJocl  jocl= new PackJocl();
        
        // 初始化,第一个参数是平台index,第二个参数是驱动index
        jocl.init(1,0);
        
        // 创建内核, 第一个是内核文件名,第二个是内核函数名
        jocl.createKernel("E://kernel.cl", "add");
        
        // 获取测试数据并复制到显存
        int n = 10;
        float srcArrayA[] = new float[n];
        float srcArrayB[] = new float[n];
        float dstArray[] = new float[n];
        for (int i=0; i<n; i++)
        {
            srcArrayA[i] = i;
            srcArrayB[i] = i;
        }
        Pointer parameters[] = {
                Pointer.to(srcArrayA),
                Pointer.to(srcArrayB),
                Pointer.to(dstArray)};
        
        jocl.setParameters(parameters, n);
        
        // 执行
        jocl.execute(1,new long[]{n}, new long[]{1});
        
        // 获取执行结果
        jocl.getData(2, Pointer.to(dstArray), n);
        
        // clear
        jocl.clear();
        
        System.out.println(dstArray[9]);
        
        
    }
}

kernel.cl 我是放在E盘根目录下,所以PackageTest.java中写的jocl.createKernel("E://kernel.cl", "add"); 你可以改成其他的

__kernel void add(__global const float *a, __global const float *b, __global float *c)
{
    int gid = get_global_id(0);
    printf("%d\t",gid);
    c[gid] = a[gid] + b[gid];
}

运行结果
blog1.PNG
第一次写文章,希望可以帮助到你

本文同步更新我的个人博客https://blog.yjqing.xin/jocl

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值