1. 程式人生 > >OpenCL和CUDA的使用比較

OpenCL和CUDA的使用比較

OpenCL和CUDA雖然不是同一個平級的東西,但是也可以橫向比較!

對OpenCL和CUDA的異同做比較:

  •         指標遍歷

OpenCL不支援CUDA那樣的指標遍歷方式, 你只能用下標方式間接實現指標遍歷. 例子程式碼如下:
// CUDA

struct Node { Node* next; }
n = n->next;

 // OpenCL

struct Node { unsigned int next; }

n = bufBase + n;

  • Kernel 程式異同

CUDA的程式碼最終編譯成顯示卡上的二進位制格式,最後由cudart.dll(個人猜測)裝載到GPU並且執行。OpenCL中執行時庫中包含編譯器,

使用虛擬碼,程式執行時即時編譯和裝載。這個類似JAVA, .net 程式,道理也一樣,為了支援跨平臺的相容。kernel程式的語法也

有略微不同,如下:

 

可以看出大部分都相同。只是細節有差異:

1)CUDA 的kernel函式使用“__global__”申明而OpenCL的kernel函式使用“__kernel”作為申明。

2)OpenCL的所有引數都有“__global”修飾符,代表這個引數所指地址是在全域性記憶體。

3)眾所周知,CUDA採用threadIdx.{x|y|z}, blockIdx.{x|y|z}來獲得當前執行緒的索引號,而OpenCL

     通過一個特定的get_global_id()函式來獲得在kernel中的全域性索引號。OpenCL中如果要獲得在當前工作

     組(對等於CUDA中的block)中的區域性索引號,可以使用get_local_id()

  • Host程式碼的異同

把上面的kernel程式碼編譯成“vectorAdd.cubin”,CUDA呼叫方法如下:

OpenCL的程式碼以文字方式存放在“sProgramSource”。 呼叫方式如下:

  • 初始化部分的異同 

CUDA 在使用任何API之前必須呼叫cuInit(0),然後是獲得當前系統的可用裝置並獲得Context。
cuInit(0);
cuDeviceGet(&hContext, 0);
cuCtxCreate(&hContext, 0, hDevice));

OpenCL不用全域性的初始化,直接指定裝置獲得控制代碼就可以了
cl_context hContext;
hContext = clCreateContextFromType(0, CL_DEVICE_TYPE_GPU, 0, 0, 0);

裝置建立完畢後,可以通過下面的方法獲得裝置資訊和上下文:
size_t nContextDescriptorSize;
clGetContextInfo(hContext, CL_CONTEXT_DEVICES, 0, 0, &nContextDescriptorSize);
cl_device_id * aDevices = malloc(nContextDescriptorSize);

clGetContextInfo(hContext, CL_CONTEXT_DEVICES, nContextDescriptorSize, aDevices, 0);

OpenCL introduces an additional concept: Command Queues. Commands launching kernels and
reading or writing memory are always issued for a specific command queue. A command queue is
created on a specific device in a context. The following code creates a command queue for the
device and context created so far:
cl_command_queue hCmdQueue;
hCmdQueue = clCreateCommandQueue(hContext, aDevices[0], 0, 0);
With this the program has progressed to the point where data can be uploaded to the device’s
memory and processed by launching compute kernels on the device.

  • Kernel Creation

CUDA kernel 以二進位制格式存放與CUBIN檔案中間,其呼叫格式和DLL的用法比較類似,先裝載二進位制庫,然後通過函式名查詢

函式地址,最後用將函式裝載到GPU執行。示例程式碼如下:
CUmodule hModule;
cuModuleLoad(&hModule, “vectorAdd.cubin”);
cuModuleGetFunction(&hFunction, hModule, "vectorAdd");

OpenCL 為了支援多平臺,所以不使用編譯後的程式碼,採用類似JAVA的方式,裝載文字格式的程式碼檔案,然後即時編譯並執行。
需要注意的是,OpenCL也提供API訪問kernel的二進位制程式,前提是這個kernel已經被編譯並且放在某個特定的快取中了。

// 裝載程式碼,即時編譯
cl_program hProgram;
hProgram = clCreateProgramWithSource(hContext, 1, “vectorAdd.c", 0, 0);
clBuildProgram(hProgram, 0, 0, 0, 0, 0);
// 獲得kernel函式控制代碼
cl_kernel hKernel;
hKernel = clCreateKernel(hProgram, “vectorAdd”, 0);

  • 裝置記憶體分配

記憶體分配沒有什麼大區別,OpenCL提供兩組特殊的標誌,CL_MEM_READ_ONLY  和 CL_MEM_WRITE_ONLY 用來控制記憶體

的讀寫許可權。另外一個標誌比較有用:CL_MEM_COPY_HOST_PTR 表示這個記憶體在主機分配,但是GPU可以使用,執行時會自動

將主機記憶體內容拷貝到GPU,主機記憶體分配,裝置記憶體分配,主機拷貝資料到裝置,3個步驟一氣呵成。
// CUDA

CUdeviceptr pDeviceMemA, pDeviceMemB, pDeviceMemC;
cuMemAlloc(&pDeviceMemA, cnDimension * sizeof(float));
cuMemAlloc(&pDeviceMemB, cnDimension * sizeof(float));
cuMemAlloc(&pDeviceMemC, cnDimension * sizeof(float));
cuMemcpyHtoD(pDeviceMemA, pA, cnDimension * sizeof(float));
cuMemcpyHtoD(pDeviceMemB, pB, cnDimension * sizeof(float));
// OpenCL
hDeviceMemA = clCreateBuffer(hContext, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, cnDimension * sizeof(cl_float), pA, 0);
hDeviceMemB = clCreateBuffer(hContext, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, cnDimension * sizeof(cl_float), pA, 0);
hDeviceMemC = clCreateBuffer(hContext, CL_MEM_WRITE_ONLY, cnDimension * sizeof(cl_float), 0, 0);

  • Kernel Parameter Specification

The next step in preparing the kernels for launch is to establish a mapping between the kernels’
parameters, essentially pointers to the three vectors A, B and C, to the three device memory regions,
which were allocated in the previous section.
Parameter setting in both APIs is a pretty low-level affair. It requires knowledge of the total number
, order, and types of a given kernel’s parameters. The order and types of the parameters are used to
determine a specific parameters offset inside the data block made up of all parameters. The offset in
bytes for the n-th parameter is essentially the sum of the sizes of all (n-1) preceding parameters.
Using the CUDA Driver API:
In CUDA device pointers are represented as unsigned int and the CUDA Driver API has a
dedicated method for setting that type. Here’s the code for setting the three parameters. Note how
the offset is incrementally computed as the sum of the previous parameters’ sizes.
cuParamSeti(cuFunction, 0, pDeviceMemA);
cuParamSeti(cuFunction, 4, pDeviceMemB);
cuParamSeti(cuFunction, 8, pDeviceMemC);
cuParamSetSize(cuFunction, 12);
Using OpenCL:
In OpenCL parameter setting is done via a single function that takes a pointer to the location of the
parameter to be set.
clSetKernelArg(hKernel, 0, sizeof(cl_mem), (void *)&hDeviceMemA);
clSetKernelArg(hKernel, 1, sizeof(cl_mem), (void *)&hDeviceMemB);
clSetKernelArg(hKernel, 2, sizeof(cl_mem), (void *)&hDeviceMemC);

相關推薦

OpenCLCUDA的使用比較

OpenCL和CUDA雖然不是同一個平級的東西,但是也可以橫向比較! 對OpenCL和CUDA的異同做比較:         指標遍歷OpenCL不支援CUDA那樣的指標遍歷方式, 你只能用下標方式間接實現指標遍歷. 例子程式碼如下:// CUDA struct Node

OpenCLCUDA簡單比較

OpenCL和CUDA是兩種異構計算的程式設計模型。 NVIDIA在2007年正式釋出CUDA之後,一直大力推廣這種程式設計模型,主要集中在科學計算這一塊,原因是這個領域的很多應用程式屬於資料並行型別,因此利用CUDA在NVIDIA自家的GPU上加速原來單執行緒的程式一般

OpenCV3 比較CPU, OpenCLcuda效能

#include <iostream> #include <opencv2/opencv.hpp> #include <opencv2/core/ocl.hpp> #include <opencv2/core/cuda.hpp&g

關系數據庫NOSQL比較

2個 二級 需求 主鍵 比較 無法 需要 strong ron 關系數據庫 NOSQL 功能: NOSQL 功能簡單 基本只支持主鍵查詢,有的NOSQL支持非主鍵查詢(不過非主鍵查詢時,其性能也很慢),很少有NOSQL支

Java中Integerint比較大小出現的錯誤

最好 裏的 pan 轉換 als 範圍 urn 返回 錯誤 Java在某一處維護著一個常量池,(我記得)在小於128的範圍內,直接用 1 Integer i = 100; 2 int j = 100; 3 return i == j;//true 這裏返回的是true.

C# 的 String.CompareTo Equals==的比較

urn 比較 我們 name pos return www 字母 string String.CompareTo 語法 public int CompareTo( string strB) 返回值 小於 0,實例小於參數 strB; 0,實例等於參數 strB; 大

string中的equals == 的比較

div println new 重寫 logs void 控制臺 static ack 1 package com.pang.string_demo; 2 3 public class Demo01 { 4 public static void main

【轉載】Java中ComparableComparator比較

import 比較器 todo itl 復制代碼 ack div array open 【本文轉自】http://www.cnblogs.com/skywang12345/p/3324788.html Comparable 簡介 Comparable 是排序接口。 若一

Oracle字符時間比較

知識 etime nbsp 間隔 to_date ember 位數 不一致 -m 數據庫中的字段 2017-07-11 13:37:51 類型是char 或者varchar 要進件與 ‘20170625‘ 比較,格式不一致,需要將他轉換成:yyyyMMdd 字符串 1、先

MemcachedRedis比較

計數 select work key-value 網絡io io操作 htm 系統設計 chunk 一、存儲 Memcached基本只支持簡單的key-value存儲方式。Redis除key-value之外,還支持list,set,sorted set,hash等數據結構

JAVA學習(二) String使用equals方法==分別比較的是什麽?(轉)

找到 基礎上 stirng print 大小 obj lis 分配 ret String使用的equals方法和==的區別 equals方法和==的區別 首先大家知道,String既可以作為一個對象來使用,又可以作為一個基本類型來使用。這裏指的作為一個基本類型來使用只是

TCPUDP比較

雙工 tty 才幹 來看 電話 系統 那不 文件 pin 一、TCP/IP協議 TCP/IP協議,你一定常常聽說吧,當中TCP(Transmission Control Protocol)稱為傳輸控制協議,IP(Internet Protocol)稱為

JAXBXStream比較

XML cti unmarshal order add emp 標準 ida 優勢 這兩東東本質上是有差別的,JAXB稱為OX binding工具,XStream應該算序列化工具,但OX binding工具也會marshall和unmarshall,所以包含了序列化這一部分

Java中ComparableComparator比較

collect clas bold 數據 let 排序類 height webkit tom 1、Comparable 介紹 Comparable 是一個排序接口,如果一個類實現了該接口,說明該類本身是可以進行排序的。註意,除了基本數據類型(八大基本數據類型) 的數組或

memcached redis比較

一致性 lis 為什麽 現在 問題 rdb osql dict 比較 同屬於NOSQL存儲,網上流傳很多memcached能做的是redis都可以做,為什麽基本現在兩種都火,原因他們有各自擅長的地方。 memcahed內部采用多核模式,單列運行很快。memcached采用的

ubuntu 16.04安裝nVidia顯卡驅動cuda/cudnn踩坑過程

頭文件 技術 mode black ubun 沖突 bash 更新 linu 安裝深度學習框架需要使用cuda/cudnn(GPU)來加速計算,而安裝cuda/cudnn,首先需要安裝nvidia的顯卡驅動。 我在安裝的整個過程中碰到了驅動沖突,循環登錄兩個問題,以至於

Java-IO 字節流的使用效率比較

操作 mp4 tran 方法 區別 讀寫文件 read 內容 ddr 打算做一個系列,前面講了基本的字符流的用法,這篇博客介紹一下字節流的基本用法: 一、基本使用: 基本字節流: FileInputStream FileOutputStream BufferedInpu

python2python3比較好的共存方法

python3 col 很多 和數 由於 log 多人 naconda packages 文章根據網絡資料編寫,只為個人學習使用。青山。。。 ---------------------------------------------------- 由於工作學習的需求,大家都

Java集合--IteratorEnumeration比較

table vector str wan rgs map.entry main 今天 fast 轉載請註明出處:http://www.cnblogs.com/skywang12345/admin/EditPosts.aspx?postid=3311275 第1部分 It

Java中 equals == 的比較

ron 博客 自動裝箱 color bsp target net adf log 先來看這樣一個題目,假設有以下代碼 下列選項中返回false的語句是? String s = "hello"; String t = “hello”; cha