(git:b195825)
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
28 static void tolowercase(char *p, char *q);
29 static int getFolderPath(char **path, int N[3]);
30 static size_t loadBinary(char *binary_path, char **buf);
31 void cleanup();
32 void 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  ******************************************************************************/
41 cl_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  ******************************************************************************/
108 cl_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 
131 static 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  ******************************************************************************/
147 cl_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 
210 int 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 
229 static 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  ******************************************************************************/
262 const unsigned OPENCL_ALIGNMENT = 64;
263 void *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 
272 void openCLContextCallBackFxn(const char *errinfo, const void *private_info,
273  size_t cb, void *user_data) {
274  printf("Context Callback - %s\n", errinfo);
275 }
276 
277 void 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 
355 void _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  ******************************************************************************/
381 static 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
Definition: ai_eri_debug.F:31
real(dp), dimension(3) q
Definition: ai_eri_debug.F:32
real(dp), dimension(3) p
Definition: ai_eri_debug.F:32