(git:374b731)
Loading...
Searching...
No Matches
opencl_utils.c
Go to the documentation of this file.
1/*----------------------------------------------------------------------------*/
2/* CP2K: A general program to perform molecular dynamics simulations */
3/* Copyright 2000-2024 CP2K developers group <https://cp2k.org> */
4/* */
5/* SPDX-License-Identifier: GPL-2.0-or-later */
6/*----------------------------------------------------------------------------*/
7
8/*******************************************************************************
9 * /author Arjun Ramaswami
10 ******************************************************************************/
11
12#if defined(__PW_FPGA)
13
14// global dependencies
15#include <math.h>
16#include <stdio.h>
17#include <stdlib.h>
18#define _USE_MATH_DEFINES
19#include "ctype.h"
20#include <stdarg.h>
21#include <string.h>
22#include <unistd.h> // access in fileExists()
23
24// common dependencies
25#include "CL/opencl.h"
26
27// function prototype
28static void tolowercase(char *p, char *q);
29static int getFolderPath(char **path, int N[3]);
30static size_t loadBinary(char *binary_path, char **buf);
31void cleanup();
32void queue_cleanup();
33
34// --- CODE -------------------------------------------------------------------
35
36/*******************************************************************************
37 * \brief return the first platform id with the name passed as argument
38 * \param platform_name : search string
39 * \retval din : platform id
40 ******************************************************************************/
41cl_platform_id findPlatform(char *platform_name) {
42 unsigned int i;
43 cl_uint status;
44
45 // Check if there are any platforms available
46 cl_uint num_platforms;
47 status = clGetPlatformIDs(0, NULL, &num_platforms);
48 if (status != CL_SUCCESS) {
49 printf("Query for number of platforms failed\n");
50 exit(1);
51 }
52
53 // Get ids of platforms available
54 cl_platform_id *pids =
55 (cl_platform_id *)malloc(sizeof(cl_platform_id) * num_platforms);
56 status = clGetPlatformIDs(num_platforms, pids, NULL);
57 if (status != CL_SUCCESS) {
58 printf("Query for platform ids failed\n");
59 free(pids);
60 exit(1);
61 }
62
63 // Convert argument string to lowercase to compare platform names
64 size_t pl_len = strlen(platform_name);
65 char name_search[pl_len + 1];
66 tolowercase(platform_name, name_search);
67
68 // Search the platforms for the platform name passed as argument
69 size_t sz;
70 for (i = 0; i < num_platforms; i++) {
71 // Get the size of the platform name referred to by the id
72 status = clGetPlatformInfo(pids[i], CL_PLATFORM_NAME, 0, NULL, &sz);
73 if (status != CL_SUCCESS) {
74 printf("Query for platform info failed\n");
75 free(pids);
76 exit(1);
77 }
78
79 char pl_name[sz];
80 char plat_name[sz];
81
82 // Store the name of string size
83 status = clGetPlatformInfo(pids[i], CL_PLATFORM_NAME, sz, pl_name, NULL);
84 if (status != CL_SUCCESS) {
85 printf("Query for platform info failed\n");
86 free(pids);
87 exit(1);
88 }
89
90 tolowercase(pl_name, plat_name);
91 if (strstr(plat_name, name_search)) {
92 cl_platform_id pid = pids[i];
93 free(pids);
94 return pid;
95 }
96 }
97 free(pids);
98 return NULL;
99}
100
101/*******************************************************************************
102 * \brief returns the list of all devices for the specific platform
103 * \param platform id to search for devices
104 * \param specific type of device to search for
105 * \param total number of devices found for the given platform
106 * \retval array of device ids
107 ******************************************************************************/
108cl_device_id *getDevices(cl_platform_id pid, cl_device_type device_type,
109 cl_uint *num_devices) {
110 cl_int status;
111
112 // Query for number of devices
113 status = clGetDeviceIDs(pid, device_type, 0, NULL, num_devices);
114 if (status != CL_SUCCESS) {
115 printf("Query for number of devices failed\n");
116 exit(1);
117 }
118
119 // Based on the number of devices get their device ids
120 cl_device_id *dev_ids =
121 (cl_device_id *)malloc(sizeof(cl_device_id) * (*num_devices));
122 status = clGetDeviceIDs(pid, device_type, *num_devices, dev_ids, NULL);
123 if (status != CL_SUCCESS) {
124 printf("Query for device ids failed\n");
125 free(dev_ids);
126 exit(1);
127 }
128 return dev_ids;
129}
130
131static int fileExists(char *filename) {
132 if (access(filename, R_OK) != -1) {
133 return 1;
134 } else {
135 return 0;
136 }
137}
138
139/*******************************************************************************
140 * \brief returns the list of all devices for the specific platform
141 * \param context created using device
142 * \param array of devices
143 * \param number of devices found
144 * \param size of FFT3d
145 * \retval created program or NULL if unsuccessful
146 ******************************************************************************/
147cl_program getProgramWithBinary(cl_context context, const cl_device_id *devices,
148 unsigned num_device, int N[3],
149 char *data_path) {
150 const int len_bin_path = 1000;
151 char bin_path[len_bin_path];
152 char *binary;
153 char *binaries[num_device];
154
155 size_t bin_size;
156 cl_int bin_status, status;
157
158#ifdef __PW_FPGA_SP
159 const char *subpath = "/../fpgabitstream/fft3d/synthesis_sp/";
160#else
161 const char *subpath = "/../fpgabitstream/fft3d/synthesis_dp/";
162#endif
163 char *foldername;
164 const char *filename = "fft3d.aocx";
165
166 if (!getFolderPath(&foldername, N)) {
167 printf("Path not found for the size (%d,%d,%d)", N[0], N[1], N[2]);
168 return NULL;
169 }
170
171 int num_bytes = snprintf(bin_path, len_bin_path, "%s%s%s%s", data_path,
172 subpath, foldername, filename);
173 if (num_bytes > len_bin_path) {
174 printf("Insufficient buffer size to store path to binary\n");
175 free(foldername);
176 return NULL;
177 }
178
179 if (!fileExists(bin_path)) {
180 printf("File not found in path %s\n", bin_path);
181 free(foldername);
182 return NULL;
183 }
184
185 // Load binary to character array
186 bin_size = loadBinary(bin_path, &binary);
187 if (bin_size == 0) {
188 printf("Could not load binary\n");
189 free(foldername);
190 return NULL;
191 }
192
193 binaries[0] = binary;
194
195 // Create the program.
196 cl_program program = clCreateProgramWithBinary(
197 context, 1, devices, &bin_size, (const unsigned char **)binaries,
198 &bin_status, &status);
199 if (status != CL_SUCCESS) {
200 printf("Query to create program with binary failed\n");
201 free(binary);
202 free(foldername);
203 return NULL;
204 }
205 free(binary);
206 free(foldername);
207 return program;
208}
209
210int getFolderPath(char **folderPath, int N[3]) {
211 if (N[0] == 16 && N[1] == 16 && N[2] == 16) {
212 char folder[] = "syn16/";
213 *folderPath = malloc(strlen(folder) + 1);
214 strncpy(*folderPath, folder, strlen(folder));
215 } else if (N[0] == 32 && N[1] == 32 && N[2] == 32) {
216 char folder[] = "syn32/";
217 *folderPath = malloc(strlen(folder) + 1);
218 strncpy(*folderPath, folder, strlen(folder));
219 } else if (N[0] == 64 && N[1] == 64 && N[2] == 64) {
220 char folder[] = "syn64/";
221 *folderPath = malloc(strlen(folder) + 1);
222 strncpy(*folderPath, folder, strlen(folder));
223 } else {
224 return 0;
225 }
226 return 1;
227}
228
229static size_t loadBinary(char *binary_path, char **buf) {
230
231 FILE *fp;
232
233 // Open file and check if it exists
234 fp = fopen(binary_path, "rb");
235 if (fp == 0) {
236 return 0;
237 }
238
239 // Find the size of the file
240 fseek(fp, 0L, SEEK_END);
241 size_t bin_size = ftell(fp);
242
243 *buf = (char *)malloc(bin_size);
244 rewind(fp); // point to beginning of file
245
246 if (fread((void *)*buf, bin_size, 1, fp) == 0) {
247 free(*buf);
248 fclose(fp);
249 return 0;
250 }
251
252 fclose(fp);
253 return bin_size;
254}
255
256/*******************************************************************************
257 * \brief Allocate host side buffers to be 64-byte aligned to make use of DMA
258 * transfer between host and global memory
259 * \param size in bytes : allocate size bytes multiples of 64
260 * \retval pointer to allocated memory on successful allocation otherwise NULL
261 ******************************************************************************/
262const unsigned OPENCL_ALIGNMENT = 64;
263void *alignedMalloc(size_t size) {
264 void *memptr = NULL;
265 int ret = posix_memalign(&memptr, OPENCL_ALIGNMENT, size);
266 if (ret != 0) {
267 return NULL;
268 }
269 return memptr;
270}
271
272void openCLContextCallBackFxn(const char *errinfo, const void *private_info,
273 size_t cb, void *user_data) {
274 printf("Context Callback - %s\n", errinfo);
275}
276
277void printError(cl_int error) {
278
279 switch (error) {
280 case CL_INVALID_PLATFORM:
281 printf("CL_PLATFORM NOT FOUND OR INVALID ");
282 break;
283 case CL_INVALID_DEVICE:
284 printf("CL_DEVICE NOT FOUND OR INVALID OR DOESN'T MATCH THE PLATFORM ");
285 break;
286 case CL_INVALID_CONTEXT:
287 printf("CL_CONTEXT INVALID ");
288 break;
289 case CL_OUT_OF_HOST_MEMORY:
290 printf("FAILURE TO ALLOCATE RESOURCES BY OPENCL");
291 break;
292 case CL_DEVICE_NOT_AVAILABLE:
293 printf("CL_DEVICE NOT AVAILABLE ALTHOUGH FOUND");
294 break;
295 case CL_INVALID_QUEUE_PROPERTIES:
296 printf("CL_QUEUE PROPERTIES INVALID");
297 break;
298 case CL_INVALID_PROGRAM:
299 printf("CL_PROGRAM INVALID");
300 break;
301 case CL_INVALID_BINARY:
302 printf("CL_BINARY INVALID");
303 break;
304 case CL_INVALID_KERNEL_NAME:
305 printf("CL_KERNEL_NAME INVALID");
306 break;
307 case CL_INVALID_KERNEL_DEFINITION:
308 printf("CL_KERNEL_DEFN INVALID");
309 break;
310 case CL_INVALID_VALUE:
311 printf("CL_VALUE INVALID");
312 break;
313 case CL_INVALID_BUFFER_SIZE:
314 printf("CL_BUFFER_SIZE INVALID");
315 break;
316 case CL_INVALID_HOST_PTR:
317 printf("CL_HOST_PTR INVALID");
318 break;
319 case CL_INVALID_COMMAND_QUEUE:
320 printf("CL_COMMAND_QUEUE INVALID");
321 break;
322 case CL_INVALID_MEM_OBJECT:
323 printf("CL_MEM_OBJECT INVALID");
324 break;
325 case CL_MEM_OBJECT_ALLOCATION_FAILURE:
326 printf("CL_MEM_OBJECT_ALLOCATION INVALID");
327 break;
328 case CL_INVALID_ARG_INDEX:
329 printf("CL_ARG_INDEX INVALID");
330 break;
331 case CL_INVALID_ARG_VALUE:
332 printf("CL_ARG_VALUE INVALID");
333 break;
334 case CL_INVALID_ARG_SIZE:
335 printf("CL_ARG_SIZE INVALID");
336 break;
337 case CL_INVALID_PROGRAM_EXECUTABLE:
338 printf("CL_PROGRAM_EXEC INVALID");
339 break;
340 case CL_INVALID_KERNEL:
341 printf("CL_KERNEL INVALID");
342 break;
343 case CL_INVALID_KERNEL_ARGS:
344 printf("CL_KERNEL_ARG INVALID");
345 break;
346 case CL_INVALID_WORK_GROUP_SIZE:
347 printf("CL_WORK_GROUP_SIZE INVALID");
348 break;
349
350 default:
351 printf("UNKNOWN ERROR %d\n", error);
352 }
353}
354
355void _checkError(const char *file, int line, const char *func, cl_int err,
356 const char *msg, ...) {
357
358 if (err != CL_SUCCESS) {
359 printf("ERROR: ");
360 printError(err);
361 printf("\nError Location: %s:%d:%s\n", file, line, func);
362
363 // custom message
364 va_list vl;
365 va_start(vl, msg);
366 vprintf(msg, vl);
367 printf("\n");
368 va_end(vl);
369
370 queue_cleanup();
371 cleanup();
372 exit(err);
373 }
374}
375
376/*******************************************************************************
377 * \brief converts a given null-terminated string to lowercase and stores in q
378 * \param p : null-terminated string
379 * \param q : string with (strlen(p)+1) length
380 ******************************************************************************/
381static void tolowercase(char *p, char *q) {
382 int i;
383 char a;
384 for (i = 0; i < strlen(p); i++) {
385 a = tolower(p[i]);
386 q[i] = a;
387 }
388 q[strlen(p)] = '\0';
389}
390
391#endif
static void const int const int i
real(dp), dimension(3) a
real(dp), dimension(3) q