tesseract 3.04.01

opencl/opencl_device_selection.h

Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines