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