OPEN CL LÀ GÌ

  -  

Sau lúc viết chấm dứt bài đầu tiên, bản thân tiếp tục mày mò sâu hơn về ma trận với cảm thấy cần được viết thêm 1 (vài) bài nữa vì có quá nhiều thứ xuất xắc ho khi đi sâu vào.

Bạn đang xem: Open cl là gì

Bạn vẫn xem: Opencl là gì

Trong phần này, mình giới thiệu về phương thức sử dụng GPU để tiến hành phép tính nhân 2 ma trận (GPU Calculation), cầm cho việc dùng CPU truyền thống, để tăng vận tốc tính toán.

Tại sao lại là GPU? gồm cả việc thống kê giám sát trên GPU sao?

Câu vấn đáp là có, thưa các bạn. Chúng ta đều biết GPU là một thành phía bên trong card vật họa, thường xuyên được giới bạn mua về cắn vô cho máy vi tính xử lý bối cảnh nhanh hơn. Vậy thao tác xử lý đồ họa ở đấy là gì?

Để phát âm được chức năng của GPU, hãy thuộc lái chủ đề một tí sang nghành nghề đồ họa thứ tính, viết mang lại đây bản thân thấy tương đối bị máu bởi dù sẽ từ bỏ ngành trò chơi được hơn một năm rồi cơ mà giờ vẫn có cơ hội quay lại viết tiếp về nó, hê hê, lạc đề tí thôi, chúng ta cũng yên ổn tâm bởi mình sẽ không để bài viết này thành bài hướng dẫn làm game gì đâu =)))

Máy tính tạo thành hình hình ảnh như thế nào?

Một hình ảnh trên laptop được cấu trúc thành từng pixel, điều này hẳn ai ai cũng biết, tuy vậy làm cố gắng nào để máy tính xách tay hiểu với vẽ được một hình ảnh thành một nhóm hợp các pixel đưa lên màn hình qua sự chỉ huy của công tác (application)?


*

Trong trường vừa lòng là trò chơi thì những dữ liệu hình ảnh (3d mesh, texture,...) sẽ tiến hành load từ đĩa (hard disk, file,...) cùng truyền vào GPU. Tại đây, GPU sẽ thực hiện phân tích và thực hiện những công việc tính toán cần thiết để chuyển bọn chúng thành tập vừa lòng các px gửi trả về CPU để vẽ ra màn hình laptop (IO devices).

Quá trình giám sát đó ngơi nghỉ trong GPU, được gọi là Rendering Pipeline, vào hình minh họa làm việc trên thì dây chuyền vận chuyển những khối hộp px kia chính là pipeline.

Rendering Pipeline

Một vật dụng thể 3 chiều trong máy vi tính được cấu thành từ không ít đỉnh, điện thoại tư vấn là vertex, mảng những vertex được hotline là vertices array.


*

Hình trên cho biết một khối hộp được sinh sản từ mảng $v$ gồm các đỉnh $v_0, v_1, ldots, v_7$

Trong thiết bị tính, đông đảo hình ảnh từ đơn giản hay phức hợp đều được tạo nên thành từ các vertices như vậy.


*

Render Pipeline là quá trình xảy ra vào GPU, khi nó nhận một tập hợp các vertices, trải qua các bước xử lý kết nối những vertices lại cùng nhau (vertex processing) thành những khối 3 chiều cơ bạn dạng (thường là những khối tam giác, hotline là 3d primitives), kế tiếp phân tích (rasterization) các hình khối 3d này thành từng mảnh nhỏ tuổi (fragments), triển khai việc đo lường và tính toán tô màu, đổ bóng,... Cho các khối này rồi ánh xạ nó thành mảng các pixel tương ứng với màn hình hiển thị máy tính, gửi trả về CPU để đưa lên màn hình.

Vì các bước này ra mắt liên tục cùng với tốc độ rất là cao để bảo vệ cho việc hiển thị hình hình ảnh lên màn hình diễn ra xuyên suốt và mượt mà, nên GPU phải thao tác với một khối lượng các phép tính cực kỳ lớn. Nói do đó thì không tức là CPU không có tác dụng dựng hình ảnh đồ họa trên thiết bị tính, phiên bản thân CPU cũng hoàn toàn có thể làm được nhưng sẽ không còn đạt được performance như GPU, lý do tại sao xin mời các bạn xem tiếp.

GPU vs CPU

Hình sau so sánh kiến trúc của một CPU đối với một GPU:


*

Các chúng ta có thể thấy khối giám sát và đo lường của GPU nhiều hơn thế CPU không hề ít lần, vì thế làm mang lại GPU có khả năng tính toán cao hơn nữa CPU.

Thêm một hình hình ảnh nữa để đối chiếu sự lợi sợ hãi của GPU, nếu như bạn có một laptop có vi giải pháp xử lý 4 nhân thì đấy là sự khác biệt đối cùng với GPU:


*

Nhưng nếu áp dụng GPU lợi hại vì vậy thì lý do người ta không cần sử dụng GPU để sửa chữa CPU luôn? Câu trả lời là rất khó, vì việc debug trên GPU không dễ dàng và đơn giản như với CPU, thêm nữa là GPU code chạy tuy nhiên song (parallel) nên cần phải có các cách thức để phân vùng dữ liệu, liên lạc, đồng bộ hóa giữa những core nên các thuật toán cách xử trí trên GPU cực kỳ phức tạp.

Đoạn đoạn phim sau trên đây minh họa sự khác hoàn toàn về câu hỏi dùng CPU và GPU để vẽ hình ảnh, con robot màu rubi là CPU còn cái máy bự chà bá cơ là sức khỏe thực sự của một GPU.

GPU chỉ cần sử dụng làm đồ dùng họa?

Với sự cách tân và phát triển của lĩnh vực công nghệ thông tin hiện tại nay, những quá trình yêu cầu năng lực tính toán cực kỳ cao đã bắt đầu cần mang đến các khối hệ thống máy tính có công dụng xử lý táo bạo hơn, và bạn ta đã bước đầu tìm đến việc trợ giúp của các GPU trong các bước tính toán, chưa phải chỉ riêng rẽ CPU nữa.

Một ứng dụng thực tế có lẽ rằng nhiều người nghe biết nhất chính là việc áp dụng GPU nhằm "đào" Bitcoin.


Một ứng dụng kì cục thấy nữa là trong nghề Machine Learning, fan ta thường áp dụng GPU để ngày càng tăng tốc độ đo lường và tính toán đối với các vector dữ liệu, vị đây cũng là một trong ngành yêu cầu xử lý với lượng dữ liệu cực kì lớn.

Gói EC2 P2 của AWS cũng cung cấp GPU https://aws.amazon.com/blogs/aws/new-p2-instance-type-for-amazon-ec2-up-to-16-gpus/

Tính toán với GPU bằng phương pháp nào?

Có hết sức nhiều cách để sử dụng GPU làm dụng cụ tính toán, chúng ta có thể khởi sinh sản một áp dụng đồ họa, biến hóa vector tài liệu cần tính toán thành những ma trận texture rồi nạp vào GPU, viết các Shader program (là một dạng chương trình chạy trên GPU, trong quá trình fragment processing của rendering pipeline) để đo lường và trả tài liệu về lại CPU.

Tuy nhiên giải pháp làm trên hơi là phức hợp và dư thừa (phải khởi tạo môi trường xung quanh đồ họa, không phải thiết, cùng đó là phương pháp làm thủ công, không tồn tại gì đảm bảo, với bị số lượng giới hạn bởi kĩ năng của Shader program.

Ngày nay chúng ta có các phương án khác, nói theo cách khác là "native" hơn, sẽ là OpenCLCUDA.

CUDA

Khi mới được ra mắt, CUDA là tên gọi viết tắt của Compute Unified Device Architecture tuy nhiên về sau thì Nvidia bỏ hẳn tên thường gọi này.

CUDA là 1 trong những nền tảng lập trình tuy nhiên song (parallel computing platform), cung ứng cho bọn họ các API trên những ngôn ngữ như C/C++, Fortran, và sau này còn xuất hiện thêm các wrapper cho Java, Ruby, Python, Haskell... để giao tiếp với các GPU của Nvidia với thực hiện quá trình tính toán hệt như trên CPU.

Quy trình buổi giao lưu của một vận dụng CUDA hơi là giống như với rendering pipeline:


Copy dữ liệu từ bộ lưu trữ chính vào bộ lưu trữ GPUCPU chỉ thị cho GPU triển khai tính toánGPU thực hiện giám sát và đo lường song tuy vậy trên những core của nóTính xong GPU gửi trả dữ liệu về lại cho bộ nhớ chính

CUDA gồm một vài điểm yếu nhất định, tuy nhiên điểm yếu lớn nhất của chính nó là được làm ra vày Nvidia phải chỉ cung cấp chạy trên hartware của Nvidia, và không người nào muốn công nghệ mình sử dụng lại bị phụ thuộc vào một nhà phân phối nhất định nào hết (trừ ngôi trường hợp táo khuyết =))) thế cho nên người ta bước đầu tìm đến một giải pháp tổng quát hơn, đó là OpenCL

OpenCL

Open Computing Language viết tắt là OpenCL là 1 trong những framework giúp các lập trình viên phát triển các ứng dụng mà chương trình có thể chạy được trên nhiều cpu như CPU, GPU, FPGA,...


OpenCL là một chuẩn mở được Apple tạo nên và trao quyền cải cách và phát triển cho tổ chức Khronos Group trứ danh (tổ chức đang thay quyền trở nên tân tiến OpenGL). OpenCL được không hề ít hãng phần cứng hỗ trợ như là AMD, Apple, ARM, IBM, Imagination Technologies, Intel, Nvidia, Qualcomm, Samsung,... điều này làm cho OpenCL biến chuyển một tiêu chuẩn chung cho tất cả ngành công nghiệp, giống hệt như OpenGL vậy.

Và trong nội dung bài viết này họ sẽ thực hiện OpenCL nhằm implement thuật toán nhân ma trận trên GPU. Để rất có thể implement được thì trước tiên phải tìm làm rõ hơn về OpenCL và phương pháp lập trình sử dụng OpenCL.

Lập trình GPU với OpenCL

Đầu tiên họ cần hiểu những khái niệm áp dụng trong OpenCL.

Các thuật ngữ vào OpenCL

Các thành phần thâm nhập việc giám sát trong một áp dụng OpenCL là các Compute Device, call là các thiết bị tính toán. Và những thiết bị thống kê giám sát này hoàn toàn có thể là các CPU, GPU hoặc các thiết bị khác có công dụng tương tự phía bên trong máy tính.

Xem thêm: Tải Clash Of Lords 2: Guild Castle Apk, Clash Of Lords 2: Clash Divin



Và trong mỗi Compute Unit (core) ta có tương đối nhiều Processing Element trực tiếp nhận lệnh nhằm tính toán.

Mô hình thao tác trong OpenCL

Mô hình xử trí của OpenCL gồm tất cả một lịch trình Host tất cả nhiệm vụ tinh chỉnh và liên lạc với khá nhiều Compute Device theo sơ trang bị sau:


Khi tiến hành xử lý, Host sẽ khởi tạo trên từng Compute Device một Context chứa các thành phần như là:

Thông tin device đang chạyKernel (là đối chọi vị bé dại nhất của quy trình xử lý, như là 1 hàm)Program Object (là đoạn code implement của Kernel)Command Queues (là queue những lệnh được truyền vào device trường đoản cú host)Memory Object (là đối tượng người dùng chứa dữ liệu sẽ được truyền/nhận qua lại thân device cùng host)

Thao tác copy dữ liệu từ Host tới Compute Device hotline là thao tác làm việc ghi (writing), và thao tác làm việc copy dữ liệu ngược lại từ Compute Device về Host call là đọc (reading).

Đây là flow của một chương trình OpenCL thường xuyên thấy:

Bước 1: chọn device phải dùng (ví dụ như: cục bộ GPU)Bước 2: Khởi chế tạo contextBước 3: Khởi tạo Command Queue cho từng deviceBước 4: Biên dịch chương trìnhBước 5: Tạo những kernel tự chương trìnhBước 6: cấp cho phát bộ nhớ trên từng deviceBước 7: Ghi tài liệu vào memory object bên trên deviceBước 8: thực hiện xử lý những kernel trên deviceBước 9: Gửi dữ liệu về lại hostBước 10: Giải phóng bộ lưu trữ trên device

Có thể thấy mô hình trên có phần phức tạp hơn CUDA. Nhưng thao tác với OpenCL linh hoạt rộng và không xẩy ra giới hạn về mặt lắp thêm như CUDA.

Việc khởi động một kernel khôn xiết tốn kém, chính vì như vậy lời khuyên được chỉ dẫn là nên thi công mỗi kernel có tác dụng nhiều việc nhất bao gồm thể.

Mô hình cai quản lý bộ nhớ lưu trữ của OpenCL

Implement một công tác OpenCL đối chọi giản

Vậy coi như chấm dứt phần lý thuyết, giờ chúng ta đi vào phần thực hành thực tế cơ bản để đọc kĩ hơn về cách lập trình bên trên GPU.

Đề bài xích sẽ là: Implement chương trình tính tổng tự 0 mang lại 100 triệu

Implement bên trên CPU

Với cách này thì không tồn tại gì để bàn rồi, solo giản chúng ta sẽ implement một vòng for rồi cho nó chạy trường đoản cú 0 đến 100 triệu, cứ cố mà cùng số vào.

for (unsigned long long i = 0; i bọn họ sẽ thêm vào một trong những đoạn code để đo thời hạn chương trình bỏ ra để tiến hành phép tính trên.

clock_t begin = clock();// vị somethingclock_t over = clock();double runtime = (double)(end - begin) / CLOCKS_PER_SEC;Hàm clock() lấy thời hạn hiện tại, gồm trong thư viện time.h, mục tiêu của đoạn code trên là lấy thời gian ở vị trí bắt đầu xử lý, với thời gian tại đoạn sau khi dứt xử lý, trừ 2 số đó với nhau ta có được thời hạn cần để chạy chương trình.

Đoạn implement không thiếu sẽ như sau:

#include #include typedef unsigned long long fuckin_large;int main() { clock_t begin = clock(); fuckin_large val = 0; for (fuckin_large j = 0; j kiểm tra chương trình trên, output sẽ có dạng như sau:

Result: 4999999950000000Runtime: 0.225600msDòng đầu là nhỏ số tác dụng sau khi vẫn tính ra, cái thứ 2 cho biết thời gian đề xuất để triển khai chương trình.

Mình bao gồm chạy thử lịch trình này trên những máy táo macbook pro từ 2012 tới 2015, vừa phải mất khoảng 0.2 mili giây để tính ra kết quả.

Tiếp theo hãy thử implement công tác này với giải pháp xử lý tựa như nhưng điều khiển xe trên GPU xem tốc độ được cải thiện như cụ nào nhé.

Implement bên trên GPU

Để implement một chương trình sử dụng OpenCL thì ta bắt buộc implement 2 phần: Host program và Kernel program.


Host là 1 trong những chương trình C/C++ có trọng trách đọc file lịch trình Kernel (đuôi *.cl) và có tác dụng các các bước khác như thể khởi chế tạo ra context, chọn device, build program object, memory object, triển khai kernel,... Như sẽ nói tại đoạn trên.

Host Program

Bước 1: Khởi tạo

Đầu tiên Host buộc phải khởi tạo các biến để chứa các đối tượng cần thiết như là Device, Context, Command Queue,...:

cl_device_id device_id = NULL;cl_context context = NULL;cl_command_queue command_queue = NULL;cl_mem memobj = NULL;cl_program program = NULL;cl_kernel kernel = NULL;cl_platform_id platform_id = NULL;cl_uint ret_num_devices;cl_uint ret_num_platforms;cl_int ret;Bước 2: Đọc Kernel Source

Tiếp theo bọn họ đọc tệp tin Kernel source với lưu vào trong 1 file pointer:

FILE *fp;char fileName = "./sum.cl";char *source_str;size_t source_size;fp = fopen(fileName, "r");if (!fp) fprintf(stderr, "Failed lớn load kernel "); exit(1);source_str = (char*)malloc(MAX_SOURCE_SIZE);source_size = fread(source_str, 1, MAX_SOURCE_SIZE, fp);fclose(fp);Trong lấy ví dụ này thì file Kernel của bọn họ là sum.cl

Bước 3: Khởi sản xuất Context và các thành phần liên quan

Sau lúc đã tất cả source code của Kernel, ta thực hiện chọn device và khởi tạo nên context, biên dịch source code của kernel thành Program Object

ret = clGetPlatformIDs(1, &platform_id, &ret_num_platforms);ret = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, &ret_num_devices);context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &ret);command_queue = clCreateCommandQueue(context, device_id, 0, &ret);program = clCreateProgramWithSource(context, 1, (const char **)&source_str, (const size_t *)&source_size, &ret);ret = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL);kernel = clCreateKernel(program, "hello", &ret);Bước 4: cung cấp phát bộ nhớ lưu trữ trên Compute Device

Sau đó cấp cho phát bộ nhớ lưu trữ cho Compute Device trong Context thông qua hàm clCreateBuffer và clSetKernelArg để chỉ định và hướng dẫn vùng nhớ này tương ứng với tham số nào lúc truyền vào kernel.

memobj = clCreateBuffer(context, CL_MEM_READ_WRITE, sizeof(cl_mem), NULL, &ret);ret = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void*)&memobj);Ngoài ra, bạn cũng có thể truyền cực hiếm vào cho các tham số thông qua hàm clEnqueueWriteBuffer:

ret = clEnqueueWriteBuffer(command_queue, memobj_A, CL_TRUE, 0, MATRIX_SIZE * MATRIX_SIZE * sizeof(cl_mem), A, 0, NULL, NULL);Bước 5: Chạy Kernel cùng Đọc kết quả

Đến cách này chúng ta sử dụng hàm clEnqueueTask để gán Command Queue đã sản xuất vào cho Kernel. Sau khi được gán thì Kernel sẽ khởi động và ban đầu xử lý trên các Processing Elements bên trên Compute Device (ở đây rất có thể là GPU của bọn chúng ta).

ret = clEnqueueTask(command_queue, kernel, 0, NULL, NULL);Để lấy dữ liệu ra sau thời điểm Kernel ngừng việc tính toán, họ dùng hàm clEnqueueReadBuffer:

ret = clEnqueueReadBuffer(command_queue, memobj, CL_TRUE, 0, sizeof(cl_mem), val, 0, NULL, NULL);Giá trị CL_TRUE truyền vào hàm này là cho tham số cl_bool blocking_read, tham số này cho thấy thêm hàm clEnqueueReadBuffer đang block cấm đoán Host program triển khai tiếp cho đến khi nó nhận được giá trị trả về sau khi Kernel hoàn thành.

Đây cũng là cách mà họ cần sử dụng hàm clock() để giám sát và đo lường thời gian cách xử lý của Kernel.

clock_t begin = clock();// vày somethingclock_t kết thúc = clock();double runtime = (double)(end - begin) / CLOCKS_PER_SEC;Bước 6: Giải phóng bộ nhớ

Kết thúc chương trình, bọn họ giải phóng tất cả các đối tượng người sử dụng đã tạo thành để kị bị memory leak.

ret = clFlush(command_queue);ret = clFinish(command_queue);ret = clReleaseKernel(kernel);ret = clReleaseProgram(program);ret = clReleaseMemObject(memobj);ret = clReleaseCommandQueue(command_queue);ret = clReleaseContext(context);free(source_str);Đây là đoạn code implement không hề thiếu của Host program làm các bước tính tổng theo đề bài đã cho:

#include #include #include #include #define MAX_SOURCE_SIZE (0x100000)int main() cl_device_id device_id = NULL; cl_context context = NULL; cl_command_queue command_queue = NULL; cl_mem memobj = NULL; cl_program program = NULL; cl_kernel kernel = NULL; cl_platform_id platform_id = NULL; cl_uint ret_num_devices; cl_uint ret_num_platforms; cl_int ret; cl_ulong val; tệp tin *fp; char fileName = "./sum.cl"; char *source_str; size_t source_size; fp = fopen(fileName, "r"); if (!fp) fprintf(stderr, "Failed to lớn load kernel "); exit(1); source_str = (char*)malloc(MAX_SOURCE_SIZE); source_size = fread(source_str, 1, MAX_SOURCE_SIZE, fp); fclose(fp); ret = clGetPlatformIDs(1, &platform_id, &ret_num_platforms); ret = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, &ret_num_devices); context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &ret); command_queue = clCreateCommandQueue(context, device_id, 0, &ret); memobj = clCreateBuffer(context, CL_MEM_READ_WRITE, sizeof(cl_mem), NULL, &ret); program = clCreateProgramWithSource(context, 1, (const char **)&source_str, (const size_t *)&source_size, &ret); ret = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL); kernel = clCreateKernel(program, "hello", &ret); ret = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void*)&memobj); clock_t begin = clock(); ret = clEnqueueTask(command_queue, kernel, 0, NULL, NULL); ret = clEnqueueReadBuffer(command_queue, memobj, CL_TRUE, 0, sizeof(cl_mem), val, 0, NULL, NULL); clock_t end = clock(); double runtime = (double)(end - begin) / CLOCKS_PER_SEC; ret = clFlush(command_queue); ret = clFinish(command_queue); ret = clReleaseKernel(kernel); ret = clReleaseProgram(program); ret = clReleaseMemObject(memobj); ret = clReleaseCommandQueue(command_queue); ret = clReleaseContext(context); printf("Result: %llu ", val); printf("Runtime: %lfms ", runtime); free(source_str); return 0;Kernel ProgramTiếp đến chúng ta implement Kernel, đấy là đoạn chương trình sẽ được Host nạp vào Program Object để tiến hành xử lý bên trên GPU.

Chương trình này sẽ tiến hành định nghĩa bằng các từ khóa kernel. Ta truyền vào trong 1 biến bé trỏ để mừng đón dữ liệu đầu ra, lịch trình này sử dụng phương pháp tính bằng cách chạy một vòng lặp for, rất có thể implement như sau:

kernel void hello(global ulong *val) { size_t i = get_global_id(0); for (ulong j = 0; j biến đổi i trong lịch trình trên là id của các bước kernel được khởi tạo trong những khi thực thi, chúng ta cần đề xuất lấy đúng mực id này nhằm gửi trả tài liệu về mang lại Host.

Đặc điểm của kernel là những biến, thông số truyền vào phần lớn mutable và họ không phải return dữ liệu (vì ngơi nghỉ host đã gồm một bước đọc dữ liệu từ memory object ra rồi).

Hy vọng qua nội dung bài viết này, các bạn đã nắm được phần nào tư tưởng về việc sử dụng GPU để nâng cấp hiệu quả tính toán, và vì sao tại sao phải dùng GPU.

Xem thêm: Net Realisable Value Là Gì ? Định Nghĩa, Ví Dụ, Giải Thích Lower Of Cost Or Net Realizable Value Là Gì

Xin cảm ơn chúng ta đã theo dõi bài xích viết, cùng hẹn gặp gỡ lại chúng ta trong các bài viết sắp tới.