|
tesseract 3.04.01
|
00001 #ifdef USE_OPENCL 00002 #ifndef DEVICE_SELECTION_H 00003 #define DEVICE_SELECTION_H 00004 00005 00006 #ifdef _MSC_VER 00007 #define _CRT_SECURE_NO_WARNINGS 00008 #endif 00009 00010 #include <stdlib.h> 00011 #include <stdio.h> 00012 #include <string.h> 00013 00014 #ifdef __APPLE__ 00015 #include <OpenCL/cl.h> 00016 #else 00017 #include <CL/cl.h> 00018 #endif 00019 00020 #define DS_DEVICE_NAME_LENGTH 256 00021 00022 typedef enum { 00023 DS_SUCCESS = 0, 00024 DS_INVALID_PROFILE = 1000, 00025 DS_MEMORY_ERROR, 00026 DS_INVALID_PERF_EVALUATOR_TYPE, 00027 DS_INVALID_PERF_EVALUATOR, 00028 DS_PERF_EVALUATOR_ERROR, 00029 DS_FILE_ERROR, 00030 DS_UNKNOWN_DEVICE_TYPE, 00031 DS_PROFILE_FILE_ERROR, 00032 DS_SCORE_SERIALIZER_ERROR, 00033 DS_SCORE_DESERIALIZER_ERROR 00034 } ds_status; 00035 00036 // device type 00037 typedef enum { 00038 DS_DEVICE_NATIVE_CPU = 0, 00039 DS_DEVICE_OPENCL_DEVICE 00040 } ds_device_type; 00041 00042 00043 typedef struct { 00044 ds_device_type type; 00045 cl_device_id oclDeviceID; 00046 char* oclDeviceName; 00047 char* oclDriverVersion; 00048 // a pointer to the score data, the content/format is application defined. 00049 void* score; 00050 } ds_device; 00051 00052 typedef struct { 00053 unsigned int numDevices; 00054 ds_device* devices; 00055 const char* version; 00056 } ds_profile; 00057 00058 // deallocate memory used by score 00059 typedef ds_status (*ds_score_release)(void* score); 00060 static ds_status releaseDSProfile(ds_profile* profile, ds_score_release sr) { 00061 ds_status status = DS_SUCCESS; 00062 if (profile!=NULL) { 00063 if (profile->devices!=NULL && sr!=NULL) { 00064 unsigned int i; 00065 for (i = 0; i < profile->numDevices; i++) { 00066 if (profile->devices[i].oclDeviceName) free(profile->devices[i].oclDeviceName); 00067 if (profile->devices[i].oclDriverVersion) free(profile->devices[i].oclDriverVersion); 00068 status = sr(profile->devices[i].score); 00069 if (status != DS_SUCCESS) 00070 break; 00071 } 00072 free(profile->devices); 00073 } 00074 free(profile); 00075 } 00076 return status; 00077 } 00078 00079 00080 static ds_status initDSProfile(ds_profile** p, const char* version) { 00081 int numDevices; 00082 cl_uint numPlatforms; 00083 cl_platform_id* platforms = NULL; 00084 cl_device_id* devices = NULL; 00085 ds_status status = DS_SUCCESS; 00086 ds_profile* profile = NULL; 00087 unsigned int next; 00088 unsigned int i; 00089 00090 if (p == NULL) 00091 return DS_INVALID_PROFILE; 00092 00093 profile = (ds_profile*)malloc(sizeof(ds_profile)); 00094 if (profile == NULL) 00095 return DS_MEMORY_ERROR; 00096 00097 memset(profile, 0, sizeof(ds_profile)); 00098 00099 clGetPlatformIDs(0, NULL, &numPlatforms); 00100 if (numPlatforms == 0) 00101 goto cleanup; 00102 00103 platforms = (cl_platform_id*)malloc(numPlatforms*sizeof(cl_platform_id)); 00104 if (platforms == NULL) { 00105 status = DS_MEMORY_ERROR; 00106 goto cleanup; 00107 } 00108 clGetPlatformIDs(numPlatforms, platforms, NULL); 00109 00110 numDevices = 0; 00111 for (i = 0; i < (unsigned int)numPlatforms; i++) { 00112 cl_uint num; 00113 clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_ALL, 0, NULL, &num); 00114 numDevices+=num; 00115 } 00116 if (numDevices == 0) 00117 goto cleanup; 00118 00119 devices = (cl_device_id*)malloc(numDevices*sizeof(cl_device_id)); 00120 if (devices == NULL) { 00121 status = DS_MEMORY_ERROR; 00122 goto cleanup; 00123 } 00124 00125 profile->numDevices = numDevices+1; // +1 to numDevices to include the native CPU 00126 profile->devices = (ds_device*)malloc(profile->numDevices*sizeof(ds_device)); 00127 if (profile->devices == NULL) { 00128 profile->numDevices = 0; 00129 status = DS_MEMORY_ERROR; 00130 goto cleanup; 00131 } 00132 memset(profile->devices, 0, profile->numDevices*sizeof(ds_device)); 00133 00134 next = 0; 00135 for (i = 0; i < (unsigned int)numPlatforms; i++) { 00136 cl_uint num; 00137 unsigned j; 00138 clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_ALL, numDevices, devices, &num); 00139 for (j = 0; j < num; j++, next++) { 00140 char buffer[DS_DEVICE_NAME_LENGTH]; 00141 size_t length; 00142 00143 profile->devices[next].type = DS_DEVICE_OPENCL_DEVICE; 00144 profile->devices[next].oclDeviceID = devices[j]; 00145 00146 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME 00147 , DS_DEVICE_NAME_LENGTH, &buffer, NULL); 00148 length = strlen(buffer); 00149 profile->devices[next].oclDeviceName = (char*)malloc(length+1); 00150 memcpy(profile->devices[next].oclDeviceName, buffer, length+1); 00151 00152 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION 00153 , DS_DEVICE_NAME_LENGTH, &buffer, NULL); 00154 length = strlen(buffer); 00155 profile->devices[next].oclDriverVersion = (char*)malloc(length+1); 00156 memcpy(profile->devices[next].oclDriverVersion, buffer, length+1); 00157 } 00158 } 00159 profile->devices[next].type = DS_DEVICE_NATIVE_CPU; 00160 profile->version = version; 00161 00162 cleanup: 00163 if (platforms) free(platforms); 00164 if (devices) free(devices); 00165 if (status == DS_SUCCESS) { 00166 *p = profile; 00167 } 00168 else { 00169 if (profile) { 00170 if (profile->devices) 00171 free(profile->devices); 00172 free(profile); 00173 } 00174 } 00175 return status; 00176 } 00177 00178 // Pointer to a function that calculates the score of a device (ex: 00179 // device->score) update the data size of score. The encoding and the format 00180 // of the score data is implementation defined. The function should return 00181 // DS_SUCCESS if there's no error to be reported. 00182 typedef ds_status (*ds_perf_evaluator)(ds_device* device, void* data); 00183 00184 typedef enum { 00185 DS_EVALUATE_ALL 00186 ,DS_EVALUATE_NEW_ONLY 00187 } ds_evaluation_type; 00188 00189 static ds_status profileDevices(ds_profile* profile, 00190 const ds_evaluation_type type, 00191 ds_perf_evaluator evaluator, 00192 void* evaluatorData, unsigned int* numUpdates) { 00193 ds_status status = DS_SUCCESS; 00194 unsigned int i; 00195 unsigned int updates = 0; 00196 00197 if (profile == NULL) { 00198 return DS_INVALID_PROFILE; 00199 } 00200 if (evaluator == NULL) { 00201 return DS_INVALID_PERF_EVALUATOR; 00202 } 00203 00204 for (i = 0; i < profile->numDevices; i++) { 00205 ds_status evaluatorStatus; 00206 00207 switch (type) { 00208 case DS_EVALUATE_NEW_ONLY: 00209 if (profile->devices[i].score != NULL) 00210 break; 00211 // else fall through 00212 case DS_EVALUATE_ALL: 00213 evaluatorStatus = evaluator(profile->devices+i, evaluatorData); 00214 if (evaluatorStatus != DS_SUCCESS) { 00215 status = evaluatorStatus; 00216 return status; 00217 } 00218 updates++; 00219 break; 00220 default: 00221 return DS_INVALID_PERF_EVALUATOR_TYPE; 00222 break; 00223 }; 00224 } 00225 if (numUpdates) 00226 *numUpdates = updates; 00227 return status; 00228 } 00229 00230 00231 #define DS_TAG_VERSION "<version>" 00232 #define DS_TAG_VERSION_END "</version>" 00233 #define DS_TAG_DEVICE "<device>" 00234 #define DS_TAG_DEVICE_END "</device>" 00235 #define DS_TAG_SCORE "<score>" 00236 #define DS_TAG_SCORE_END "</score>" 00237 #define DS_TAG_DEVICE_TYPE "<type>" 00238 #define DS_TAG_DEVICE_TYPE_END "</type>" 00239 #define DS_TAG_DEVICE_NAME "<name>" 00240 #define DS_TAG_DEVICE_NAME_END "</name>" 00241 #define DS_TAG_DEVICE_DRIVER_VERSION "<driver>" 00242 #define DS_TAG_DEVICE_DRIVER_VERSION_END "</driver>" 00243 00244 #define DS_DEVICE_NATIVE_CPU_STRING "native_cpu" 00245 00246 00247 00248 typedef ds_status (*ds_score_serializer)(ds_device* device, 00249 void** serializedScore, 00250 unsigned int* serializedScoreSize); 00251 static ds_status writeProfileToFile(ds_profile* profile, 00252 ds_score_serializer serializer, 00253 const char* file) { 00254 ds_status status = DS_SUCCESS; 00255 FILE* profileFile = NULL; 00256 00257 00258 if (profile == NULL) 00259 return DS_INVALID_PROFILE; 00260 00261 profileFile = fopen(file, "wb"); 00262 if (profileFile==NULL) { 00263 status = DS_FILE_ERROR; 00264 } 00265 else { 00266 unsigned int i; 00267 00268 // write version string 00269 fwrite(DS_TAG_VERSION, sizeof(char), strlen(DS_TAG_VERSION), profileFile); 00270 fwrite(profile->version, sizeof(char), strlen(profile->version), profileFile); 00271 fwrite(DS_TAG_VERSION_END, sizeof(char), strlen(DS_TAG_VERSION_END), profileFile); 00272 fwrite("\n", sizeof(char), 1, profileFile); 00273 00274 for (i = 0; i < profile->numDevices && status == DS_SUCCESS; i++) { 00275 void* serializedScore; 00276 unsigned int serializedScoreSize; 00277 00278 fwrite(DS_TAG_DEVICE, sizeof(char), strlen(DS_TAG_DEVICE), profileFile); 00279 00280 fwrite(DS_TAG_DEVICE_TYPE, sizeof(char), strlen(DS_TAG_DEVICE_TYPE), 00281 profileFile); 00282 fwrite(&profile->devices[i].type,sizeof(ds_device_type),1, profileFile); 00283 fwrite(DS_TAG_DEVICE_TYPE_END, sizeof(char), 00284 strlen(DS_TAG_DEVICE_TYPE_END), profileFile); 00285 00286 switch(profile->devices[i].type) { 00287 case DS_DEVICE_NATIVE_CPU: 00288 { 00289 // There's no need to emit a device name for the native CPU device. 00290 /* 00291 fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), 00292 profileFile); 00293 fwrite(DS_DEVICE_NATIVE_CPU_STRING,sizeof(char), 00294 strlen(DS_DEVICE_NATIVE_CPU_STRING), profileFile); 00295 fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), 00296 strlen(DS_TAG_DEVICE_NAME_END), profileFile); 00297 */ 00298 } 00299 break; 00300 case DS_DEVICE_OPENCL_DEVICE: 00301 { 00302 fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), 00303 profileFile); 00304 fwrite(profile->devices[i].oclDeviceName, 00305 sizeof(char),strlen(profile->devices[i].oclDeviceName), profileFile); 00306 fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), 00307 strlen(DS_TAG_DEVICE_NAME_END), profileFile); 00308 00309 fwrite(DS_TAG_DEVICE_DRIVER_VERSION, sizeof(char), 00310 strlen(DS_TAG_DEVICE_DRIVER_VERSION), profileFile); 00311 fwrite(profile->devices[i].oclDriverVersion, sizeof(char), 00312 strlen(profile->devices[i].oclDriverVersion), profileFile); 00313 fwrite(DS_TAG_DEVICE_DRIVER_VERSION_END, sizeof(char), 00314 strlen(DS_TAG_DEVICE_DRIVER_VERSION_END), profileFile); 00315 } 00316 break; 00317 default: 00318 status = DS_UNKNOWN_DEVICE_TYPE; 00319 break; 00320 }; 00321 00322 fwrite(DS_TAG_SCORE, sizeof(char), strlen(DS_TAG_SCORE), profileFile); 00323 status = serializer(profile->devices+i, &serializedScore, 00324 &serializedScoreSize); 00325 if (status == DS_SUCCESS && serializedScore!=NULL && serializedScoreSize > 0) { 00326 fwrite(serializedScore, sizeof(char), serializedScoreSize, profileFile); 00327 free(serializedScore); 00328 } 00329 fwrite(DS_TAG_SCORE_END, sizeof(char), strlen(DS_TAG_SCORE_END), profileFile); 00330 fwrite(DS_TAG_DEVICE_END, sizeof(char), strlen(DS_TAG_DEVICE_END), profileFile); 00331 fwrite("\n",sizeof(char),1,profileFile); 00332 } 00333 fclose(profileFile); 00334 } 00335 return status; 00336 } 00337 00338 00339 static ds_status readProFile(const char* fileName, char** content, 00340 size_t* contentSize) { 00341 FILE * input = NULL; 00342 size_t size = 0; 00343 char* binary = NULL; 00344 00345 *contentSize = 0; 00346 *content = NULL; 00347 00348 input = fopen(fileName, "rb"); 00349 if(input == NULL) { 00350 return DS_FILE_ERROR; 00351 } 00352 00353 fseek(input, 0L, SEEK_END); 00354 size = ftell(input); 00355 rewind(input); 00356 binary = (char*)malloc(size); 00357 if(binary == NULL) { 00358 fclose(input); 00359 return DS_FILE_ERROR; 00360 } 00361 fread(binary, sizeof(char), size, input); 00362 fclose(input); 00363 00364 *contentSize = size; 00365 *content = binary; 00366 return DS_SUCCESS; 00367 } 00368 00369 00370 static const char* findString(const char* contentStart, const char* contentEnd, 00371 const char* string) { 00372 size_t stringLength; 00373 const char* currentPosition; 00374 const char* found; 00375 found = NULL; 00376 stringLength = strlen(string); 00377 currentPosition = contentStart; 00378 for(currentPosition = contentStart; currentPosition < contentEnd; currentPosition++) { 00379 if (*currentPosition == string[0]) { 00380 if (currentPosition+stringLength < contentEnd) { 00381 if (strncmp(currentPosition, string, stringLength) == 0) { 00382 found = currentPosition; 00383 break; 00384 } 00385 } 00386 } 00387 } 00388 return found; 00389 } 00390 00391 00392 typedef ds_status (*ds_score_deserializer)(ds_device* device, 00393 const unsigned char* serializedScore, 00394 unsigned int serializedScoreSize); 00395 static ds_status readProfileFromFile(ds_profile* profile, 00396 ds_score_deserializer deserializer, 00397 const char* file) { 00398 00399 ds_status status = DS_SUCCESS; 00400 char* contentStart = NULL; 00401 const char* contentEnd = NULL; 00402 size_t contentSize; 00403 00404 if (profile==NULL) 00405 return DS_INVALID_PROFILE; 00406 00407 status = readProFile(file, &contentStart, &contentSize); 00408 if (status == DS_SUCCESS) { 00409 const char* currentPosition; 00410 const char* dataStart; 00411 const char* dataEnd; 00412 size_t versionStringLength; 00413 00414 contentEnd = contentStart + contentSize; 00415 currentPosition = contentStart; 00416 00417 00418 // parse the version string 00419 dataStart = findString(currentPosition, contentEnd, DS_TAG_VERSION); 00420 if (dataStart == NULL) { 00421 status = DS_PROFILE_FILE_ERROR; 00422 goto cleanup; 00423 } 00424 dataStart += strlen(DS_TAG_VERSION); 00425 00426 dataEnd = findString(dataStart, contentEnd, DS_TAG_VERSION_END); 00427 if (dataEnd==NULL) { 00428 status = DS_PROFILE_FILE_ERROR; 00429 goto cleanup; 00430 } 00431 00432 versionStringLength = strlen(profile->version); 00433 if (versionStringLength!=(dataEnd-dataStart) 00434 || strncmp(profile->version, dataStart, versionStringLength)!=0) { 00435 // version mismatch 00436 status = DS_PROFILE_FILE_ERROR; 00437 goto cleanup; 00438 } 00439 currentPosition = dataEnd+strlen(DS_TAG_VERSION_END); 00440 00441 // parse the device information 00442 while (1) { 00443 unsigned int i; 00444 00445 const char* deviceTypeStart; 00446 const char* deviceTypeEnd; 00447 ds_device_type deviceType; 00448 00449 const char* deviceNameStart; 00450 const char* deviceNameEnd; 00451 00452 const char* deviceScoreStart; 00453 const char* deviceScoreEnd; 00454 00455 const char* deviceDriverStart; 00456 const char* deviceDriverEnd; 00457 00458 dataStart = findString(currentPosition, contentEnd, DS_TAG_DEVICE); 00459 if (dataStart==NULL) { 00460 // nothing useful remain, quit... 00461 break; 00462 } 00463 dataStart+=strlen(DS_TAG_DEVICE); 00464 dataEnd = findString(dataStart, contentEnd, DS_TAG_DEVICE_END); 00465 if (dataEnd==NULL) { 00466 status = DS_PROFILE_FILE_ERROR; 00467 goto cleanup; 00468 } 00469 00470 // parse the device type 00471 deviceTypeStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_TYPE); 00472 if (deviceTypeStart==NULL) { 00473 status = DS_PROFILE_FILE_ERROR; 00474 goto cleanup; 00475 } 00476 deviceTypeStart+=strlen(DS_TAG_DEVICE_TYPE); 00477 deviceTypeEnd = findString(deviceTypeStart, contentEnd, 00478 DS_TAG_DEVICE_TYPE_END); 00479 if (deviceTypeEnd==NULL) { 00480 status = DS_PROFILE_FILE_ERROR; 00481 goto cleanup; 00482 } 00483 memcpy(&deviceType, deviceTypeStart, sizeof(ds_device_type)); 00484 00485 00486 // parse the device name 00487 if (deviceType == DS_DEVICE_OPENCL_DEVICE) { 00488 00489 deviceNameStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_NAME); 00490 if (deviceNameStart==NULL) { 00491 status = DS_PROFILE_FILE_ERROR; 00492 goto cleanup; 00493 } 00494 deviceNameStart+=strlen(DS_TAG_DEVICE_NAME); 00495 deviceNameEnd = findString(deviceNameStart, contentEnd, 00496 DS_TAG_DEVICE_NAME_END); 00497 if (deviceNameEnd==NULL) { 00498 status = DS_PROFILE_FILE_ERROR; 00499 goto cleanup; 00500 } 00501 00502 00503 deviceDriverStart = findString(dataStart, contentEnd, 00504 DS_TAG_DEVICE_DRIVER_VERSION); 00505 if (deviceDriverStart==NULL) { 00506 status = DS_PROFILE_FILE_ERROR; 00507 goto cleanup; 00508 } 00509 deviceDriverStart+=strlen(DS_TAG_DEVICE_DRIVER_VERSION); 00510 deviceDriverEnd = findString(deviceDriverStart, contentEnd, 00511 DS_TAG_DEVICE_DRIVER_VERSION_END); 00512 if (deviceDriverEnd ==NULL) { 00513 status = DS_PROFILE_FILE_ERROR; 00514 goto cleanup; 00515 } 00516 00517 00518 // check if this device is on the system 00519 for (i = 0; i < profile->numDevices; i++) { 00520 if (profile->devices[i].type == DS_DEVICE_OPENCL_DEVICE) { 00521 size_t actualDeviceNameLength; 00522 size_t driverVersionLength; 00523 00524 actualDeviceNameLength = strlen(profile->devices[i].oclDeviceName); 00525 driverVersionLength = strlen(profile->devices[i].oclDriverVersion); 00526 if (actualDeviceNameLength == (deviceNameEnd - deviceNameStart) 00527 && driverVersionLength == (deviceDriverEnd - deviceDriverStart) 00528 && strncmp(profile->devices[i].oclDeviceName, deviceNameStart, 00529 actualDeviceNameLength)==0 00530 && strncmp(profile->devices[i].oclDriverVersion, deviceDriverStart, 00531 driverVersionLength)==0) { 00532 deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE); 00533 if (deviceNameStart==NULL) { 00534 status = DS_PROFILE_FILE_ERROR; 00535 goto cleanup; 00536 } 00537 deviceScoreStart+=strlen(DS_TAG_SCORE); 00538 deviceScoreEnd = findString(deviceScoreStart, contentEnd, 00539 DS_TAG_SCORE_END); 00540 status = deserializer(profile->devices+i, 00541 (const unsigned char*)deviceScoreStart, 00542 deviceScoreEnd-deviceScoreStart); 00543 if (status != DS_SUCCESS) { 00544 goto cleanup; 00545 } 00546 } 00547 } 00548 } 00549 00550 } 00551 else if (deviceType == DS_DEVICE_NATIVE_CPU) { 00552 for (i = 0; i < profile->numDevices; i++) { 00553 if (profile->devices[i].type == DS_DEVICE_NATIVE_CPU) { 00554 deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE); 00555 if (deviceScoreStart==NULL) { 00556 status = DS_PROFILE_FILE_ERROR; 00557 goto cleanup; 00558 } 00559 deviceScoreStart+=strlen(DS_TAG_SCORE); 00560 deviceScoreEnd = findString(deviceScoreStart, contentEnd, 00561 DS_TAG_SCORE_END); 00562 status = deserializer(profile->devices+i, 00563 (const unsigned char*)deviceScoreStart, 00564 deviceScoreEnd-deviceScoreStart); 00565 if (status != DS_SUCCESS) { 00566 goto cleanup; 00567 } 00568 } 00569 } 00570 } 00571 00572 // skip over the current one to find the next device 00573 currentPosition = dataEnd+strlen(DS_TAG_DEVICE_END); 00574 } 00575 } 00576 cleanup: 00577 if (contentStart!=NULL) free(contentStart); 00578 return status; 00579 } 00580 00581 static ds_status getNumDeviceWithEmptyScore(ds_profile* profile, 00582 unsigned int* num) { 00583 unsigned int i; 00584 if (profile == NULL || num==NULL) 00585 return DS_MEMORY_ERROR; 00586 *num=0; 00587 for (i = 0; i < profile->numDevices; i++) { 00588 if (profile->devices[i].score == NULL) { 00589 *num++; 00590 } 00591 } 00592 return DS_SUCCESS; 00593 } 00594 00595 #endif 00596 #endif