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