tesseract  3.05.00
 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 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 // http://www.apache.org/licenses/LICENSE-2.0
5 // Unless required by applicable law or agreed to in writing, software
6 // distributed under the License is distributed on an "AS IS" BASIS,
7 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8 // See the License for the specific language governing permissions and
9 // limitations under the License.
10 #ifdef USE_OPENCL
11 #ifndef DEVICE_SELECTION_H
12 #define DEVICE_SELECTION_H
13 
14 
15 #ifdef _MSC_VER
16 #define _CRT_SECURE_NO_WARNINGS
17 #endif
18 
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22 
23 #ifdef __APPLE__
24 #include <OpenCL/cl.h>
25 #else
26 #include <CL/cl.h>
27 #endif
28 
29 #define DS_DEVICE_NAME_LENGTH 256
30 
31 typedef enum {
32  DS_SUCCESS = 0,
33  DS_INVALID_PROFILE = 1000,
34  DS_MEMORY_ERROR,
35  DS_INVALID_PERF_EVALUATOR_TYPE,
36  DS_INVALID_PERF_EVALUATOR,
37  DS_PERF_EVALUATOR_ERROR,
38  DS_FILE_ERROR,
39  DS_UNKNOWN_DEVICE_TYPE,
40  DS_PROFILE_FILE_ERROR,
41  DS_SCORE_SERIALIZER_ERROR,
42  DS_SCORE_DESERIALIZER_ERROR
43 } ds_status;
44 
45 // device type
46 typedef enum {
47  DS_DEVICE_NATIVE_CPU = 0,
48  DS_DEVICE_OPENCL_DEVICE
49 } ds_device_type;
50 
51 
52 typedef struct {
53  ds_device_type type;
54  cl_device_id oclDeviceID;
55  char* oclDeviceName;
56  char* oclDriverVersion;
57  // a pointer to the score data, the content/format is application defined.
58  void* score;
59 } ds_device;
60 
61 typedef struct {
62  unsigned int numDevices;
63  ds_device* devices;
64  const char* version;
65 } ds_profile;
66 
67 // deallocate memory used by score
68 typedef ds_status (*ds_score_release)(void* score);
69 static ds_status releaseDSProfile(ds_profile* profile, ds_score_release sr) {
70  ds_status status = DS_SUCCESS;
71  if (profile != NULL) {
72  if (profile->devices != NULL && sr != NULL) {
73  unsigned int i;
74  for (i = 0; i < profile->numDevices; i++) {
75  free(profile->devices[i].oclDeviceName);
76  free(profile->devices[i].oclDriverVersion);
77  status = sr(profile->devices[i].score);
78  if (status != DS_SUCCESS)
79  break;
80  }
81  free(profile->devices);
82  }
83  free(profile);
84  }
85  return status;
86 }
87 
88 
89 static ds_status initDSProfile(ds_profile** p, const char* version) {
90  int numDevices;
91  cl_uint numPlatforms;
92  cl_platform_id* platforms = NULL;
93  cl_device_id* devices = NULL;
94  ds_status status = DS_SUCCESS;
95  unsigned int next;
96  unsigned int i;
97 
98  if (p == NULL) return DS_INVALID_PROFILE;
99  ds_profile* profile = (ds_profile*)malloc(sizeof(ds_profile));
100  if (profile == NULL) return DS_MEMORY_ERROR;
101 
102  memset(profile, 0, sizeof(ds_profile));
103 
104  clGetPlatformIDs(0, NULL, &numPlatforms);
105  if (numPlatforms == 0)
106  goto cleanup;
107 
108  platforms = (cl_platform_id*)malloc(numPlatforms*sizeof(cl_platform_id));
109  if (platforms == NULL) {
110  status = DS_MEMORY_ERROR;
111  goto cleanup;
112  }
113  clGetPlatformIDs(numPlatforms, platforms, NULL);
114 
115  numDevices = 0;
116  for (i = 0; i < (unsigned int)numPlatforms; i++) {
117  cl_uint num;
118  clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_ALL, 0, NULL, &num);
119  numDevices+=num;
120  }
121  if (numDevices == 0)
122  goto cleanup;
123 
124  devices = (cl_device_id*)malloc(numDevices*sizeof(cl_device_id));
125  if (devices == NULL) {
126  status = DS_MEMORY_ERROR;
127  goto cleanup;
128  }
129 
130  profile->numDevices = numDevices+1; // +1 to numDevices to include the native CPU
131  profile->devices =
132  (ds_device*)malloc(profile->numDevices * sizeof(ds_device));
133  if (profile->devices == NULL) {
134  profile->numDevices = 0;
135  status = DS_MEMORY_ERROR;
136  goto cleanup;
137  }
138  memset(profile->devices, 0, profile->numDevices*sizeof(ds_device));
139 
140  next = 0;
141  for (i = 0; i < (unsigned int)numPlatforms; i++) {
142  cl_uint num;
143  unsigned j;
144  clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_ALL, numDevices, devices, &num);
145  for (j = 0; j < num; j++, next++) {
146  char buffer[DS_DEVICE_NAME_LENGTH];
147  size_t length;
148 
149  profile->devices[next].type = DS_DEVICE_OPENCL_DEVICE;
150  profile->devices[next].oclDeviceID = devices[j];
151 
152  clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME,
153  DS_DEVICE_NAME_LENGTH, &buffer, NULL);
154  length = strlen(buffer);
155  profile->devices[next].oclDeviceName = (char*)malloc(length+1);
156  memcpy(profile->devices[next].oclDeviceName, buffer, length+1);
157 
158  clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION,
159  DS_DEVICE_NAME_LENGTH, &buffer, NULL);
160  length = strlen(buffer);
161  profile->devices[next].oclDriverVersion = (char*)malloc(length+1);
162  memcpy(profile->devices[next].oclDriverVersion, buffer, length+1);
163  }
164  }
165  profile->devices[next].type = DS_DEVICE_NATIVE_CPU;
166  profile->version = version;
167 
168 cleanup:
169  free(platforms);
170  free(devices);
171  if (status == DS_SUCCESS) {
172  *p = profile;
173  }
174  else {
175  if (profile) {
176  free(profile->devices);
177  free(profile);
178  }
179  }
180  return status;
181 }
182 
183 // Pointer to a function that calculates the score of a device (ex:
184 // device->score) update the data size of score. The encoding and the format
185 // of the score data is implementation defined. The function should return
186 // DS_SUCCESS if there's no error to be reported.
187 typedef ds_status (*ds_perf_evaluator)(ds_device* device, void* data);
188 
189 typedef enum {
190  DS_EVALUATE_ALL
191  ,DS_EVALUATE_NEW_ONLY
192 } ds_evaluation_type;
193 
194 static ds_status profileDevices(ds_profile* profile,
195  const ds_evaluation_type type,
196  ds_perf_evaluator evaluator,
197  void* evaluatorData, unsigned int* numUpdates) {
198  ds_status status = DS_SUCCESS;
199  unsigned int i;
200  unsigned int updates = 0;
201 
202  if (profile == NULL) {
203  return DS_INVALID_PROFILE;
204  }
205  if (evaluator == NULL) {
206  return DS_INVALID_PERF_EVALUATOR;
207  }
208 
209  for (i = 0; i < profile->numDevices; i++) {
210  ds_status evaluatorStatus;
211 
212  switch (type) {
213  case DS_EVALUATE_NEW_ONLY:
214  if (profile->devices[i].score != NULL) break;
215  // else fall through
216  case DS_EVALUATE_ALL:
217  evaluatorStatus = evaluator(profile->devices+i, evaluatorData);
218  if (evaluatorStatus != DS_SUCCESS) {
219  status = evaluatorStatus;
220  return status;
221  }
222  updates++;
223  break;
224  default:
225  return DS_INVALID_PERF_EVALUATOR_TYPE;
226  break;
227  };
228  }
229  if (numUpdates)
230  *numUpdates = updates;
231  return status;
232 }
233 
234 
235 #define DS_TAG_VERSION "<version>"
236 #define DS_TAG_VERSION_END "</version>"
237 #define DS_TAG_DEVICE "<device>"
238 #define DS_TAG_DEVICE_END "</device>"
239 #define DS_TAG_SCORE "<score>"
240 #define DS_TAG_SCORE_END "</score>"
241 #define DS_TAG_DEVICE_TYPE "<type>"
242 #define DS_TAG_DEVICE_TYPE_END "</type>"
243 #define DS_TAG_DEVICE_NAME "<name>"
244 #define DS_TAG_DEVICE_NAME_END "</name>"
245 #define DS_TAG_DEVICE_DRIVER_VERSION "<driver>"
246 #define DS_TAG_DEVICE_DRIVER_VERSION_END "</driver>"
247 
248 #define DS_DEVICE_NATIVE_CPU_STRING "native_cpu"
249 
250 
251 
252 typedef ds_status (*ds_score_serializer)(ds_device* device,
253  void** serializedScore,
254  unsigned int* serializedScoreSize);
255 static ds_status writeProfileToFile(ds_profile* profile,
256  ds_score_serializer serializer,
257  const char* file) {
258  ds_status status = DS_SUCCESS;
259 
260  if (profile == NULL) return DS_INVALID_PROFILE;
261 
262  FILE* profileFile = fopen(file, "wb");
263  if (profileFile == NULL) {
264  status = DS_FILE_ERROR;
265  }
266  else {
267  unsigned int i;
268 
269  // write version string
270  fwrite(DS_TAG_VERSION, sizeof(char), strlen(DS_TAG_VERSION), profileFile);
271  fwrite(profile->version, sizeof(char), strlen(profile->version), profileFile);
272  fwrite(DS_TAG_VERSION_END, sizeof(char), strlen(DS_TAG_VERSION_END), profileFile);
273  fwrite("\n", sizeof(char), 1, profileFile);
274 
275  for (i = 0; i < profile->numDevices && status == DS_SUCCESS; i++) {
276  void* serializedScore;
277  unsigned int serializedScoreSize;
278 
279  fwrite(DS_TAG_DEVICE, sizeof(char), strlen(DS_TAG_DEVICE), profileFile);
280 
281  fwrite(DS_TAG_DEVICE_TYPE, sizeof(char), strlen(DS_TAG_DEVICE_TYPE),
282  profileFile);
283  fwrite(&profile->devices[i].type,sizeof(ds_device_type),1, profileFile);
284  fwrite(DS_TAG_DEVICE_TYPE_END, sizeof(char),
285  strlen(DS_TAG_DEVICE_TYPE_END), profileFile);
286 
287  switch(profile->devices[i].type) {
288  case DS_DEVICE_NATIVE_CPU:
289  {
290  // There's no need to emit a device name for the native CPU device.
291  /*
292  fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME),
293  profileFile);
294  fwrite(DS_DEVICE_NATIVE_CPU_STRING,sizeof(char),
295  strlen(DS_DEVICE_NATIVE_CPU_STRING), profileFile);
296  fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char),
297  strlen(DS_TAG_DEVICE_NAME_END), profileFile);
298  */
299  }
300  break;
301  case DS_DEVICE_OPENCL_DEVICE:
302  {
303  fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME),
304  profileFile);
305  fwrite(profile->devices[i].oclDeviceName,
306  sizeof(char),strlen(profile->devices[i].oclDeviceName), profileFile);
307  fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char),
308  strlen(DS_TAG_DEVICE_NAME_END), profileFile);
309 
310  fwrite(DS_TAG_DEVICE_DRIVER_VERSION, sizeof(char),
311  strlen(DS_TAG_DEVICE_DRIVER_VERSION), profileFile);
312  fwrite(profile->devices[i].oclDriverVersion, sizeof(char),
313  strlen(profile->devices[i].oclDriverVersion), profileFile);
314  fwrite(DS_TAG_DEVICE_DRIVER_VERSION_END, sizeof(char),
315  strlen(DS_TAG_DEVICE_DRIVER_VERSION_END), profileFile);
316  }
317  break;
318  default:
319  status = DS_UNKNOWN_DEVICE_TYPE;
320  break;
321  };
322 
323  fwrite(DS_TAG_SCORE, sizeof(char), strlen(DS_TAG_SCORE), profileFile);
324  status = serializer(profile->devices+i, &serializedScore,
325  &serializedScoreSize);
326  if (status == DS_SUCCESS && serializedScore != NULL &&
327  serializedScoreSize > 0) {
328  fwrite(serializedScore, sizeof(char), serializedScoreSize, profileFile);
329  free(serializedScore);
330  }
331  fwrite(DS_TAG_SCORE_END, sizeof(char), strlen(DS_TAG_SCORE_END), profileFile);
332  fwrite(DS_TAG_DEVICE_END, sizeof(char), strlen(DS_TAG_DEVICE_END), profileFile);
333  fwrite("\n",sizeof(char),1,profileFile);
334  }
335  fclose(profileFile);
336  }
337  return status;
338 }
339 
340 
341 static ds_status readProFile(const char* fileName, char** content,
342  size_t* contentSize) {
343  size_t size = 0;
344 
345  *contentSize = 0;
346  *content = NULL;
347 
348  FILE* 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  char* 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) return DS_INVALID_PROFILE;
405 
406  status = readProFile(file, &contentStart, &contentSize);
407  if (status == DS_SUCCESS) {
408  const char* currentPosition;
409  const char* dataStart;
410  const char* dataEnd;
411  size_t versionStringLength;
412 
413  contentEnd = contentStart + contentSize;
414  currentPosition = contentStart;
415 
416 
417  // parse the version string
418  dataStart = findString(currentPosition, contentEnd, DS_TAG_VERSION);
419  if (dataStart == NULL) {
420  status = DS_PROFILE_FILE_ERROR;
421  goto cleanup;
422  }
423  dataStart += strlen(DS_TAG_VERSION);
424 
425  dataEnd = findString(dataStart, contentEnd, DS_TAG_VERSION_END);
426  if (dataEnd == NULL) {
427  status = DS_PROFILE_FILE_ERROR;
428  goto cleanup;
429  }
430 
431  versionStringLength = strlen(profile->version);
432  if (versionStringLength!=(dataEnd-dataStart)
433  || strncmp(profile->version, dataStart, versionStringLength)!=0) {
434  // version mismatch
435  status = DS_PROFILE_FILE_ERROR;
436  goto cleanup;
437  }
438  currentPosition = dataEnd+strlen(DS_TAG_VERSION_END);
439 
440  // parse the device information
441  while (1) {
442  unsigned int i;
443 
444  const char* deviceTypeStart;
445  const char* deviceTypeEnd;
446  ds_device_type deviceType;
447 
448  const char* deviceNameStart;
449  const char* deviceNameEnd;
450 
451  const char* deviceScoreStart;
452  const char* deviceScoreEnd;
453 
454  const char* deviceDriverStart;
455  const char* deviceDriverEnd;
456 
457  dataStart = findString(currentPosition, contentEnd, DS_TAG_DEVICE);
458  if (dataStart == NULL) {
459  // nothing useful remain, quit...
460  break;
461  }
462  dataStart+=strlen(DS_TAG_DEVICE);
463  dataEnd = findString(dataStart, contentEnd, DS_TAG_DEVICE_END);
464  if (dataEnd == NULL) {
465  status = DS_PROFILE_FILE_ERROR;
466  goto cleanup;
467  }
468 
469  // parse the device type
470  deviceTypeStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_TYPE);
471  if (deviceTypeStart == NULL) {
472  status = DS_PROFILE_FILE_ERROR;
473  goto cleanup;
474  }
475  deviceTypeStart+=strlen(DS_TAG_DEVICE_TYPE);
476  deviceTypeEnd = findString(deviceTypeStart, contentEnd,
477  DS_TAG_DEVICE_TYPE_END);
478  if (deviceTypeEnd == NULL) {
479  status = DS_PROFILE_FILE_ERROR;
480  goto cleanup;
481  }
482  memcpy(&deviceType, deviceTypeStart, sizeof(ds_device_type));
483 
484 
485  // parse the device name
486  if (deviceType == DS_DEVICE_OPENCL_DEVICE) {
487 
488  deviceNameStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_NAME);
489  if (deviceNameStart == NULL) {
490  status = DS_PROFILE_FILE_ERROR;
491  goto cleanup;
492  }
493  deviceNameStart+=strlen(DS_TAG_DEVICE_NAME);
494  deviceNameEnd = findString(deviceNameStart, contentEnd,
495  DS_TAG_DEVICE_NAME_END);
496  if (deviceNameEnd == NULL) {
497  status = DS_PROFILE_FILE_ERROR;
498  goto cleanup;
499  }
500 
501 
502  deviceDriverStart = findString(dataStart, contentEnd,
503  DS_TAG_DEVICE_DRIVER_VERSION);
504  if (deviceDriverStart == NULL) {
505  status = DS_PROFILE_FILE_ERROR;
506  goto cleanup;
507  }
508  deviceDriverStart+=strlen(DS_TAG_DEVICE_DRIVER_VERSION);
509  deviceDriverEnd = findString(deviceDriverStart, contentEnd,
510  DS_TAG_DEVICE_DRIVER_VERSION_END);
511  if (deviceDriverEnd == NULL) {
512  status = DS_PROFILE_FILE_ERROR;
513  goto cleanup;
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  free(contentStart);
576  return status;
577 }
578 
579 #endif
580 #endif