All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
opencl_device_selection.h
Go to the documentation of this file.
1 #ifdef USE_OPENCL
2 #ifndef DEVICE_SELECTION_H
3 #define DEVICE_SELECTION_H
4 
5 
6 #ifdef _MSC_VER
7 #define _CRT_SECURE_NO_WARNINGS
8 #endif
9 
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
13 
14 #ifdef __APPLE__
15 #include <OpenCL/cl.h>
16 #else
17 #include <CL/cl.h>
18 #endif
19 
20 #define DS_DEVICE_NAME_LENGTH 256
21 
22 typedef enum {
23  DS_SUCCESS = 0,
24  DS_INVALID_PROFILE = 1000,
25  DS_MEMORY_ERROR,
26  DS_INVALID_PERF_EVALUATOR_TYPE,
27  DS_INVALID_PERF_EVALUATOR,
28  DS_PERF_EVALUATOR_ERROR,
29  DS_FILE_ERROR,
30  DS_UNKNOWN_DEVICE_TYPE,
31  DS_PROFILE_FILE_ERROR,
32  DS_SCORE_SERIALIZER_ERROR,
33  DS_SCORE_DESERIALIZER_ERROR
34 } ds_status;
35 
36 // device type
37 typedef enum {
38  DS_DEVICE_NATIVE_CPU = 0,
39  DS_DEVICE_OPENCL_DEVICE
40 } ds_device_type;
41 
42 
43 typedef struct {
44  ds_device_type type;
45  cl_device_id oclDeviceID;
46  char* oclDeviceName;
47  char* oclDriverVersion;
48  // a pointer to the score data, the content/format is application defined.
49  void* score;
50 } ds_device;
51 
52 typedef struct {
53  unsigned int numDevices;
54  ds_device* devices;
55  const char* version;
56 } ds_profile;
57 
58 // deallocate memory used by score
59 typedef ds_status (*ds_score_release)(void* score);
60 static ds_status releaseDSProfile(ds_profile* profile, ds_score_release sr) {
61  ds_status status = DS_SUCCESS;
62  if (profile!=NULL) {
63  if (profile->devices!=NULL && sr!=NULL) {
64  unsigned int i;
65  for (i = 0; i < profile->numDevices; i++) {
66  status = sr(profile->devices[i].score);
67  if (status != DS_SUCCESS)
68  break;
69  }
70  free(profile->devices);
71  }
72  free(profile);
73  }
74  return status;
75 }
76 
77 
78 static ds_status initDSProfile(ds_profile** p, const char* version) {
79  int numDevices;
80  cl_uint numPlatforms;
81  cl_platform_id* platforms = NULL;
82  cl_device_id* devices = NULL;
83  ds_status status = DS_SUCCESS;
84  ds_profile* profile = NULL;
85  unsigned int next;
86  unsigned int i;
87 
88  if (p == NULL)
89  return DS_INVALID_PROFILE;
90 
91  profile = (ds_profile*)malloc(sizeof(ds_profile));
92  if (profile == NULL)
93  return DS_MEMORY_ERROR;
94 
95  memset(profile, 0, sizeof(ds_profile));
96 
97  clGetPlatformIDs(0, NULL, &numPlatforms);
98  if (numPlatforms == 0)
99  goto cleanup;
100 
101  platforms = (cl_platform_id*)malloc(numPlatforms*sizeof(cl_platform_id));
102  if (platforms == NULL) {
103  status = DS_MEMORY_ERROR;
104  goto cleanup;
105  }
106  clGetPlatformIDs(numPlatforms, platforms, NULL);
107 
108  numDevices = 0;
109  for (i = 0; i < (unsigned int)numPlatforms; i++) {
110  cl_uint num;
111  clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_ALL, 0, NULL, &num);
112  numDevices+=num;
113  }
114  if (numDevices == 0)
115  goto cleanup;
116 
117  devices = (cl_device_id*)malloc(numDevices*sizeof(cl_device_id));
118  if (devices == NULL) {
119  status = DS_MEMORY_ERROR;
120  goto cleanup;
121  }
122 
123  profile->numDevices = numDevices+1; // +1 to numDevices to include the native CPU
124  profile->devices = (ds_device*)malloc(profile->numDevices*sizeof(ds_device));
125  if (profile->devices == NULL) {
126  profile->numDevices = 0;
127  status = DS_MEMORY_ERROR;
128  goto cleanup;
129  }
130  memset(profile->devices, 0, profile->numDevices*sizeof(ds_device));
131 
132  next = 0;
133  for (i = 0; i < (unsigned int)numPlatforms; i++) {
134  cl_uint num;
135  unsigned j;
136  clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_ALL, numDevices, devices, &num);
137  for (j = 0; j < num; j++, next++) {
138  char buffer[DS_DEVICE_NAME_LENGTH];
139  size_t length;
140 
141  profile->devices[next].type = DS_DEVICE_OPENCL_DEVICE;
142  profile->devices[next].oclDeviceID = devices[j];
143 
144  clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME
145  , DS_DEVICE_NAME_LENGTH, &buffer, NULL);
146  length = strlen(buffer);
147  profile->devices[next].oclDeviceName = (char*)malloc(length+1);
148  memcpy(profile->devices[next].oclDeviceName, buffer, length+1);
149 
150  clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION
151  , DS_DEVICE_NAME_LENGTH, &buffer, NULL);
152  length = strlen(buffer);
153  profile->devices[next].oclDriverVersion = (char*)malloc(length+1);
154  memcpy(profile->devices[next].oclDriverVersion, buffer, length+1);
155  }
156  }
157  profile->devices[next].type = DS_DEVICE_NATIVE_CPU;
158  profile->version = version;
159 
160 cleanup:
161  if (platforms) free(platforms);
162  if (devices) free(devices);
163  if (status == DS_SUCCESS) {
164  *p = profile;
165  }
166  else {
167  if (profile) {
168  if (profile->devices)
169  free(profile->devices);
170  free(profile);
171  }
172  }
173  return status;
174 }
175 
176 // Pointer to a function that calculates the score of a device (ex:
177 // device->score) update the data size of score. The encoding and the format
178 // of the score data is implementation defined. The function should return
179 // DS_SUCCESS if there's no error to be reported.
180 typedef ds_status (*ds_perf_evaluator)(ds_device* device, void* data);
181 
182 typedef enum {
183  DS_EVALUATE_ALL
184  ,DS_EVALUATE_NEW_ONLY
185 } ds_evaluation_type;
186 
187 static ds_status profileDevices(ds_profile* profile,
188  const ds_evaluation_type type,
189  ds_perf_evaluator evaluator,
190  void* evaluatorData, unsigned int* numUpdates) {
191  ds_status status = DS_SUCCESS;
192  unsigned int i;
193  unsigned int updates = 0;
194 
195  if (profile == NULL) {
196  return DS_INVALID_PROFILE;
197  }
198  if (evaluator == NULL) {
199  return DS_INVALID_PERF_EVALUATOR;
200  }
201 
202  for (i = 0; i < profile->numDevices; i++) {
203  ds_status evaluatorStatus;
204 
205  switch (type) {
206  case DS_EVALUATE_NEW_ONLY:
207  if (profile->devices[i].score != NULL)
208  break;
209  // else fall through
210  case DS_EVALUATE_ALL:
211  evaluatorStatus = evaluator(profile->devices+i, evaluatorData);
212  if (evaluatorStatus != DS_SUCCESS) {
213  status = evaluatorStatus;
214  return status;
215  }
216  updates++;
217  break;
218  default:
219  return DS_INVALID_PERF_EVALUATOR_TYPE;
220  break;
221  };
222  }
223  if (numUpdates)
224  *numUpdates = updates;
225  return status;
226 }
227 
228 
229 #define DS_TAG_VERSION "<version>"
230 #define DS_TAG_VERSION_END "</version>"
231 #define DS_TAG_DEVICE "<device>"
232 #define DS_TAG_DEVICE_END "</device>"
233 #define DS_TAG_SCORE "<score>"
234 #define DS_TAG_SCORE_END "</score>"
235 #define DS_TAG_DEVICE_TYPE "<type>"
236 #define DS_TAG_DEVICE_TYPE_END "</type>"
237 #define DS_TAG_DEVICE_NAME "<name>"
238 #define DS_TAG_DEVICE_NAME_END "</name>"
239 #define DS_TAG_DEVICE_DRIVER_VERSION "<driver>"
240 #define DS_TAG_DEVICE_DRIVER_VERSION_END "</driver>"
241 
242 #define DS_DEVICE_NATIVE_CPU_STRING "native_cpu"
243 
244 
245 
246 typedef ds_status (*ds_score_serializer)(ds_device* device,
247  void** serializedScore,
248  unsigned int* serializedScoreSize);
249 static ds_status writeProfileToFile(ds_profile* profile,
250  ds_score_serializer serializer,
251  const char* file) {
252  ds_status status = DS_SUCCESS;
253  FILE* profileFile = NULL;
254 
255 
256  if (profile == NULL)
257  return DS_INVALID_PROFILE;
258 
259  profileFile = fopen(file, "wb");
260  if (profileFile==NULL) {
261  status = DS_FILE_ERROR;
262  }
263  else {
264  unsigned int i;
265 
266  // write version string
267  fwrite(DS_TAG_VERSION, sizeof(char), strlen(DS_TAG_VERSION), profileFile);
268  fwrite(profile->version, sizeof(char), strlen(profile->version), profileFile);
269  fwrite(DS_TAG_VERSION_END, sizeof(char), strlen(DS_TAG_VERSION_END), profileFile);
270  fwrite("\n", sizeof(char), 1, profileFile);
271 
272  for (i = 0; i < profile->numDevices && status == DS_SUCCESS; i++) {
273  void* serializedScore;
274  unsigned int serializedScoreSize;
275 
276  fwrite(DS_TAG_DEVICE, sizeof(char), strlen(DS_TAG_DEVICE), profileFile);
277 
278  fwrite(DS_TAG_DEVICE_TYPE, sizeof(char), strlen(DS_TAG_DEVICE_TYPE),
279  profileFile);
280  fwrite(&profile->devices[i].type,sizeof(ds_device_type),1, profileFile);
281  fwrite(DS_TAG_DEVICE_TYPE_END, sizeof(char),
282  strlen(DS_TAG_DEVICE_TYPE_END), profileFile);
283 
284  switch(profile->devices[i].type) {
285  case DS_DEVICE_NATIVE_CPU:
286  {
287  // There's no need to emit a device name for the native CPU device.
288  /*
289  fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME),
290  profileFile);
291  fwrite(DS_DEVICE_NATIVE_CPU_STRING,sizeof(char),
292  strlen(DS_DEVICE_NATIVE_CPU_STRING), profileFile);
293  fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char),
294  strlen(DS_TAG_DEVICE_NAME_END), profileFile);
295  */
296  }
297  break;
298  case DS_DEVICE_OPENCL_DEVICE:
299  {
300  fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME),
301  profileFile);
302  fwrite(profile->devices[i].oclDeviceName,
303  sizeof(char),strlen(profile->devices[i].oclDeviceName), profileFile);
304  fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char),
305  strlen(DS_TAG_DEVICE_NAME_END), profileFile);
306 
307  fwrite(DS_TAG_DEVICE_DRIVER_VERSION, sizeof(char),
308  strlen(DS_TAG_DEVICE_DRIVER_VERSION), profileFile);
309  fwrite(profile->devices[i].oclDriverVersion, sizeof(char),
310  strlen(profile->devices[i].oclDriverVersion), profileFile);
311  fwrite(DS_TAG_DEVICE_DRIVER_VERSION_END, sizeof(char),
312  strlen(DS_TAG_DEVICE_DRIVER_VERSION_END), profileFile);
313  }
314  break;
315  default:
316  status = DS_UNKNOWN_DEVICE_TYPE;
317  break;
318  };
319 
320  fwrite(DS_TAG_SCORE, sizeof(char), strlen(DS_TAG_SCORE), profileFile);
321  status = serializer(profile->devices+i, &serializedScore,
322  &serializedScoreSize);
323  if (status == DS_SUCCESS && serializedScore!=NULL && serializedScoreSize > 0) {
324  fwrite(serializedScore, sizeof(char), serializedScoreSize, profileFile);
325  free(serializedScore);
326  }
327  fwrite(DS_TAG_SCORE_END, sizeof(char), strlen(DS_TAG_SCORE_END), profileFile);
328  fwrite(DS_TAG_DEVICE_END, sizeof(char), strlen(DS_TAG_DEVICE_END), profileFile);
329  fwrite("\n",sizeof(char),1,profileFile);
330  }
331  fclose(profileFile);
332  }
333  return status;
334 }
335 
336 
337 static ds_status readProFile(const char* fileName, char** content,
338  size_t* contentSize) {
339  FILE * input = NULL;
340  size_t size = 0;
341  char* binary = NULL;
342 
343  *contentSize = 0;
344  *content = NULL;
345 
346  input = fopen(fileName, "rb");
347  if(input == NULL) {
348  return DS_FILE_ERROR;
349  }
350 
351  fseek(input, 0L, SEEK_END);
352  size = ftell(input);
353  rewind(input);
354  binary = (char*)malloc(size);
355  if(binary == NULL) {
356  fclose(input);
357  return DS_FILE_ERROR;
358  }
359  fread(binary, sizeof(char), size, input);
360  fclose(input);
361 
362  *contentSize = size;
363  *content = binary;
364  return DS_SUCCESS;
365 }
366 
367 
368 static const char* findString(const char* contentStart, const char* contentEnd,
369  const char* string) {
370  size_t stringLength;
371  const char* currentPosition;
372  const char* found;
373  found = NULL;
374  stringLength = strlen(string);
375  currentPosition = contentStart;
376  for(currentPosition = contentStart; currentPosition < contentEnd; currentPosition++) {
377  if (*currentPosition == string[0]) {
378  if (currentPosition+stringLength < contentEnd) {
379  if (strncmp(currentPosition, string, stringLength) == 0) {
380  found = currentPosition;
381  break;
382  }
383  }
384  }
385  }
386  return found;
387 }
388 
389 
390 typedef ds_status (*ds_score_deserializer)(ds_device* device,
391  const unsigned char* serializedScore,
392  unsigned int serializedScoreSize);
393 static ds_status readProfileFromFile(ds_profile* profile,
394  ds_score_deserializer deserializer,
395  const char* file) {
396 
397  ds_status status = DS_SUCCESS;
398  char* contentStart = NULL;
399  const char* contentEnd = NULL;
400  size_t contentSize;
401 
402  if (profile==NULL)
403  return DS_INVALID_PROFILE;
404 
405  status = readProFile(file, &contentStart, &contentSize);
406  if (status == DS_SUCCESS) {
407  const char* currentPosition;
408  const char* dataStart;
409  const char* dataEnd;
410  size_t versionStringLength;
411 
412  contentEnd = contentStart + contentSize;
413  currentPosition = contentStart;
414 
415 
416  // parse the version string
417  dataStart = findString(currentPosition, contentEnd, DS_TAG_VERSION);
418  if (dataStart == NULL) {
419  status = DS_PROFILE_FILE_ERROR;
420  goto cleanup;
421  }
422  dataStart += strlen(DS_TAG_VERSION);
423 
424  dataEnd = findString(dataStart, contentEnd, DS_TAG_VERSION_END);
425  if (dataEnd==NULL) {
426  status = DS_PROFILE_FILE_ERROR;
427  goto cleanup;
428  }
429 
430  versionStringLength = strlen(profile->version);
431  if (versionStringLength!=(dataEnd-dataStart)
432  || strncmp(profile->version, dataStart, versionStringLength)!=0) {
433  // version mismatch
434  status = DS_PROFILE_FILE_ERROR;
435  goto cleanup;
436  }
437  currentPosition = dataEnd+strlen(DS_TAG_VERSION_END);
438 
439  // parse the device information
440  while (1) {
441  unsigned int i;
442 
443  const char* deviceTypeStart;
444  const char* deviceTypeEnd;
445  ds_device_type deviceType;
446 
447  const char* deviceNameStart;
448  const char* deviceNameEnd;
449 
450  const char* deviceScoreStart;
451  const char* deviceScoreEnd;
452 
453  const char* deviceDriverStart;
454  const char* deviceDriverEnd;
455 
456  dataStart = findString(currentPosition, contentEnd, DS_TAG_DEVICE);
457  if (dataStart==NULL) {
458  // nothing useful remain, quit...
459  break;
460  }
461  dataStart+=strlen(DS_TAG_DEVICE);
462  dataEnd = findString(dataStart, contentEnd, DS_TAG_DEVICE_END);
463  if (dataEnd==NULL) {
464  status = DS_PROFILE_FILE_ERROR;
465  goto cleanup;
466  }
467 
468  // parse the device type
469  deviceTypeStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_TYPE);
470  if (deviceTypeStart==NULL) {
471  status = DS_PROFILE_FILE_ERROR;
472  goto cleanup;
473  }
474  deviceTypeStart+=strlen(DS_TAG_DEVICE_TYPE);
475  deviceTypeEnd = findString(deviceTypeStart, contentEnd,
476  DS_TAG_DEVICE_TYPE_END);
477  if (deviceTypeEnd==NULL) {
478  status = DS_PROFILE_FILE_ERROR;
479  goto cleanup;
480  }
481  memcpy(&deviceType, deviceTypeStart, sizeof(ds_device_type));
482 
483 
484  // parse the device name
485  if (deviceType == DS_DEVICE_OPENCL_DEVICE) {
486 
487  deviceNameStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_NAME);
488  if (deviceNameStart==NULL) {
489  status = DS_PROFILE_FILE_ERROR;
490  goto cleanup;
491  }
492  deviceNameStart+=strlen(DS_TAG_DEVICE_NAME);
493  deviceNameEnd = findString(deviceNameStart, contentEnd,
494  DS_TAG_DEVICE_NAME_END);
495  if (deviceNameEnd==NULL) {
496  status = DS_PROFILE_FILE_ERROR;
497  goto cleanup;
498  }
499 
500 
501  deviceDriverStart = findString(dataStart, contentEnd,
502  DS_TAG_DEVICE_DRIVER_VERSION);
503  if (deviceDriverStart==NULL) {
504  status = DS_PROFILE_FILE_ERROR;
505  goto cleanup;
506  }
507  deviceDriverStart+=strlen(DS_TAG_DEVICE_DRIVER_VERSION);
508  deviceDriverEnd = findString(deviceDriverStart, contentEnd,
509  DS_TAG_DEVICE_DRIVER_VERSION_END);
510  if (deviceDriverEnd ==NULL) {
511  status = DS_PROFILE_FILE_ERROR;
512  goto cleanup;
513  }
514 
515 
516  // check if this device is on the system
517  for (i = 0; i < profile->numDevices; i++) {
518  if (profile->devices[i].type == DS_DEVICE_OPENCL_DEVICE) {
519  size_t actualDeviceNameLength;
520  size_t driverVersionLength;
521 
522  actualDeviceNameLength = strlen(profile->devices[i].oclDeviceName);
523  driverVersionLength = strlen(profile->devices[i].oclDriverVersion);
524  if (actualDeviceNameLength == (deviceNameEnd - deviceNameStart)
525  && driverVersionLength == (deviceDriverEnd - deviceDriverStart)
526  && strncmp(profile->devices[i].oclDeviceName, deviceNameStart,
527  actualDeviceNameLength)==0
528  && strncmp(profile->devices[i].oclDriverVersion, deviceDriverStart,
529  driverVersionLength)==0) {
530  deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
531  if (deviceNameStart==NULL) {
532  status = DS_PROFILE_FILE_ERROR;
533  goto cleanup;
534  }
535  deviceScoreStart+=strlen(DS_TAG_SCORE);
536  deviceScoreEnd = findString(deviceScoreStart, contentEnd,
537  DS_TAG_SCORE_END);
538  status = deserializer(profile->devices+i,
539  (const unsigned char*)deviceScoreStart,
540  deviceScoreEnd-deviceScoreStart);
541  if (status != DS_SUCCESS) {
542  goto cleanup;
543  }
544  }
545  }
546  }
547 
548  }
549  else if (deviceType == DS_DEVICE_NATIVE_CPU) {
550  for (i = 0; i < profile->numDevices; i++) {
551  if (profile->devices[i].type == DS_DEVICE_NATIVE_CPU) {
552  deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
553  if (deviceScoreStart==NULL) {
554  status = DS_PROFILE_FILE_ERROR;
555  goto cleanup;
556  }
557  deviceScoreStart+=strlen(DS_TAG_SCORE);
558  deviceScoreEnd = findString(deviceScoreStart, contentEnd,
559  DS_TAG_SCORE_END);
560  status = deserializer(profile->devices+i,
561  (const unsigned char*)deviceScoreStart,
562  deviceScoreEnd-deviceScoreStart);
563  if (status != DS_SUCCESS) {
564  goto cleanup;
565  }
566  }
567  }
568  }
569 
570  // skip over the current one to find the next device
571  currentPosition = dataEnd+strlen(DS_TAG_DEVICE_END);
572  }
573  }
574 cleanup:
575  if (contentStart!=NULL) free(contentStart);
576  return status;
577 }
578 
579 static ds_status getNumDeviceWithEmptyScore(ds_profile* profile,
580  unsigned int* num) {
581  unsigned int i;
582  if (profile == NULL || num==NULL)
583  return DS_MEMORY_ERROR;
584  *num=0;
585  for (i = 0; i < profile->numDevices; i++) {
586  if (profile->devices[i].score == NULL) {
587  *num++;
588  }
589  }
590  return DS_SUCCESS;
591 }
592 
593 #endif
594 #endif
#define NULL
Definition: host.h:144