1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #ifndef SC_DEVICE_SELECTION_H
11 #define SC_DEVICE_SELECTION_H
15 #define _CRT_SECURE_NO_WARNINGS
21 #include "clcc/clew.h"
23 #define DS_DEVICE_NAME_LENGTH 256
28 ,DS_INVALID_PROFILE
= 1000
30 , DS_INVALID_PERF_EVALUATOR_TYPE
31 , DS_INVALID_PERF_EVALUATOR
32 , DS_PERF_EVALUATOR_ERROR
34 , DS_UNKNOWN_DEVICE_TYPE
35 , DS_PROFILE_FILE_ERROR
36 , DS_SCORE_SERIALIZER_ERROR
37 , DS_SCORE_DESERIALIZER_ERROR
43 DS_DEVICE_NATIVE_CPU
= 0
44 ,DS_DEVICE_OPENCL_DEVICE
51 cl_device_id oclDeviceID
;
53 char* oclDriverVersion
;
54 void* score
; // a pointer to the score data, the content/format is application defined
59 unsigned int numDevices
;
64 // deallocate memory used by score
65 typedef ds_status(* ds_score_release
)(void* score
);
66 inline ds_status
releaseDSProfile(ds_profile
* profile
, ds_score_release sr
)
68 ds_status status
= DS_SUCCESS
;
71 if (profile
->devices
!= NULL
&& sr
!= NULL
)
74 for (i
= 0; i
< profile
->numDevices
; i
++)
76 free(profile
->devices
[i
].oclDeviceName
);
77 free(profile
->devices
[i
].oclDriverVersion
);
78 status
= sr(profile
->devices
[i
].score
);
79 if (status
!= DS_SUCCESS
) break;
81 free(profile
->devices
);
89 inline ds_status
initDSProfile(ds_profile
** p
, const char* version
)
93 cl_platform_id
* platforms
= NULL
;
94 cl_device_id
* devices
= NULL
;
95 ds_status status
= DS_SUCCESS
;
96 ds_profile
* profile
= NULL
;
100 if (p
== NULL
) return DS_INVALID_PROFILE
;
102 profile
= (ds_profile
*)malloc(sizeof(ds_profile
));
103 if (profile
== NULL
) return DS_MEMORY_ERROR
;
105 memset(profile
, 0, sizeof(ds_profile
));
107 clGetPlatformIDs(0, NULL
, &numPlatforms
);
108 if (numPlatforms
!= 0)
110 platforms
= (cl_platform_id
*)malloc(numPlatforms
* sizeof(cl_platform_id
));
111 if (platforms
== NULL
)
113 status
= DS_MEMORY_ERROR
;
116 clGetPlatformIDs(numPlatforms
, platforms
, NULL
);
120 for (i
= 0; i
< (unsigned int)numPlatforms
; i
++)
123 clGetDeviceIDs(platforms
[i
], CL_DEVICE_TYPE_ALL
, 0, NULL
, &num
);
128 devices
= (cl_device_id
*)malloc(numDevices
* sizeof(cl_device_id
));
131 status
= DS_MEMORY_ERROR
;
136 profile
->numDevices
= numDevices
+ 1; // +1 to numDevices to include the native CPU
137 profile
->devices
= (ds_device
*)malloc(profile
->numDevices
* sizeof(ds_device
));
138 if (profile
->devices
== NULL
)
140 profile
->numDevices
= 0;
141 status
= DS_MEMORY_ERROR
;
144 memset(profile
->devices
, 0, profile
->numDevices
* sizeof(ds_device
));
147 for (i
= 0; i
< (unsigned int)numPlatforms
; i
++)
151 clGetDeviceIDs(platforms
[i
], CL_DEVICE_TYPE_ALL
, numDevices
, devices
, &num
);
152 for (j
= 0; j
< num
; j
++, next
++)
154 char buffer
[DS_DEVICE_NAME_LENGTH
];
157 profile
->devices
[next
].type
= DS_DEVICE_OPENCL_DEVICE
;
158 profile
->devices
[next
].oclDeviceID
= devices
[j
];
160 clGetDeviceInfo(profile
->devices
[next
].oclDeviceID
, CL_DEVICE_NAME
161 , DS_DEVICE_NAME_LENGTH
, &buffer
, NULL
);
162 length
= strlen(buffer
);
163 profile
->devices
[next
].oclDeviceName
= (char*)malloc(length
+ 1);
164 memcpy(profile
->devices
[next
].oclDeviceName
, buffer
, length
+ 1);
166 clGetDeviceInfo(profile
->devices
[next
].oclDeviceID
, CL_DRIVER_VERSION
167 , DS_DEVICE_NAME_LENGTH
, &buffer
, NULL
);
168 length
= strlen(buffer
);
169 profile
->devices
[next
].oclDriverVersion
= (char*)malloc(length
+ 1);
170 memcpy(profile
->devices
[next
].oclDriverVersion
, buffer
, length
+ 1);
173 profile
->devices
[next
].type
= DS_DEVICE_NATIVE_CPU
;
174 profile
->version
= version
;
177 if (platforms
) free(platforms
);
178 if (devices
) free(devices
);
179 if (status
== DS_SUCCESS
)
187 if (profile
->devices
) free(profile
->devices
);
194 // Pointer to a function that calculates the score of a device (ex: device->score)
195 // update the data size of score. The encoding and the format of the score data
196 // is implementation defined. The function should return DS_SUCCESS if there's no error to be reported.
197 typedef ds_status(* ds_perf_evaluator
)(ds_device
* device
, void* data
);
201 , DS_EVALUATE_NEW_ONLY
202 } ds_evaluation_type
;
204 inline ds_status
profileDevices(ds_profile
* profile
, const ds_evaluation_type type
,
205 ds_perf_evaluator evaluator
, void* evaluatorData
, unsigned int* numUpdates
)
207 ds_status status
= DS_SUCCESS
;
209 unsigned int updates
= 0;
213 return DS_INVALID_PROFILE
;
215 if (evaluator
== NULL
)
217 return DS_INVALID_PERF_EVALUATOR
;
220 for (i
= 0; i
< profile
->numDevices
; i
++)
222 ds_status evaluatorStatus
;
226 case DS_EVALUATE_NEW_ONLY
:
227 if (profile
->devices
[i
].score
!= NULL
) break;
229 case DS_EVALUATE_ALL
:
230 evaluatorStatus
= evaluator(profile
->devices
+ i
, evaluatorData
);
231 if (evaluatorStatus
!= DS_SUCCESS
)
233 status
= evaluatorStatus
;
239 return DS_INVALID_PERF_EVALUATOR_TYPE
;
243 if (numUpdates
) *numUpdates
= updates
;
248 #define DS_TAG_VERSION "<version>"
249 #define DS_TAG_VERSION_END "</version>"
250 #define DS_TAG_DEVICE "<device>"
251 #define DS_TAG_DEVICE_END "</device>"
252 #define DS_TAG_SCORE "<score>"
253 #define DS_TAG_SCORE_END "</score>"
254 #define DS_TAG_DEVICE_TYPE "<type>"
255 #define DS_TAG_DEVICE_TYPE_END "</type>"
256 #define DS_TAG_DEVICE_NAME "<name>"
257 #define DS_TAG_DEVICE_NAME_END "</name>"
258 #define DS_TAG_DEVICE_DRIVER_VERSION "<driver>"
259 #define DS_TAG_DEVICE_DRIVER_VERSION_END "</driver>"
261 #define DS_DEVICE_NATIVE_CPU_STRING "native_cpu"
265 typedef ds_status(* ds_score_serializer
)(ds_device
* device
, void** serializedScore
, unsigned int* serializedScoreSize
);
266 inline ds_status
writeProfileToFile(ds_profile
* profile
, ds_score_serializer serializer
, const char* file
)
268 ds_status status
= DS_SUCCESS
;
269 FILE* profileFile
= NULL
;
272 if (profile
== NULL
) return DS_INVALID_PROFILE
;
274 profileFile
= fopen(file
, "wb");
275 if (profileFile
== NULL
)
277 status
= DS_FILE_ERROR
;
283 // write version string
284 fwrite(DS_TAG_VERSION
, sizeof(char), strlen(DS_TAG_VERSION
), profileFile
);
285 fwrite(profile
->version
, sizeof(char), strlen(profile
->version
), profileFile
);
286 fwrite(DS_TAG_VERSION_END
, sizeof(char), strlen(DS_TAG_VERSION_END
), profileFile
);
287 fwrite("\n", sizeof(char), 1, profileFile
);
289 for (i
= 0; i
< profile
->numDevices
&& status
== DS_SUCCESS
; i
++)
291 void* serializedScore
;
292 unsigned int serializedScoreSize
;
294 fwrite(DS_TAG_DEVICE
, sizeof(char), strlen(DS_TAG_DEVICE
), profileFile
);
296 fwrite(DS_TAG_DEVICE_TYPE
, sizeof(char), strlen(DS_TAG_DEVICE_TYPE
), profileFile
);
297 fwrite(&profile
->devices
[i
].type
, sizeof(ds_device_type
), 1, profileFile
);
298 fwrite(DS_TAG_DEVICE_TYPE_END
, sizeof(char), strlen(DS_TAG_DEVICE_TYPE_END
), profileFile
);
300 switch (profile
->devices
[i
].type
)
302 case DS_DEVICE_NATIVE_CPU
:
304 // There's no need to emit a device name for the native CPU device.
306 fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile);
307 fwrite(DS_DEVICE_NATIVE_CPU_STRING,sizeof(char),strlen(DS_DEVICE_NATIVE_CPU_STRING), profileFile);
308 fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile);
312 case DS_DEVICE_OPENCL_DEVICE
:
314 fwrite(DS_TAG_DEVICE_NAME
, sizeof(char), strlen(DS_TAG_DEVICE_NAME
), profileFile
);
315 fwrite(profile
->devices
[i
].oclDeviceName
, sizeof(char), strlen(profile
->devices
[i
].oclDeviceName
), profileFile
);
316 fwrite(DS_TAG_DEVICE_NAME_END
, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END
), profileFile
);
318 fwrite(DS_TAG_DEVICE_DRIVER_VERSION
, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION
), profileFile
);
319 fwrite(profile
->devices
[i
].oclDriverVersion
, sizeof(char), strlen(profile
->devices
[i
].oclDriverVersion
), profileFile
);
320 fwrite(DS_TAG_DEVICE_DRIVER_VERSION_END
, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION_END
), profileFile
);
324 status
= DS_UNKNOWN_DEVICE_TYPE
;
328 fwrite(DS_TAG_SCORE
, sizeof(char), strlen(DS_TAG_SCORE
), profileFile
);
329 status
= serializer(profile
->devices
+ i
, &serializedScore
, &serializedScoreSize
);
330 if (status
== DS_SUCCESS
&& serializedScore
!= NULL
&& serializedScoreSize
> 0)
332 fwrite(serializedScore
, sizeof(char), serializedScoreSize
, profileFile
);
333 free(serializedScore
);
335 fwrite(DS_TAG_SCORE_END
, sizeof(char), strlen(DS_TAG_SCORE_END
), profileFile
);
336 fwrite(DS_TAG_DEVICE_END
, sizeof(char), strlen(DS_TAG_DEVICE_END
), profileFile
);
337 fwrite("\n", sizeof(char), 1, profileFile
);
345 inline ds_status
readProFile(const char* fileName
, char** content
, size_t* contentSize
)
354 input
= fopen(fileName
, "rb");
357 return DS_FILE_ERROR
;
360 fseek(input
, 0L, SEEK_END
);
363 binary
= (char*)malloc(size
);
366 return DS_FILE_ERROR
;
368 size_t bytesRead
= fread(binary
, sizeof(char), size
, input
);
369 (void) bytesRead
; // avoid warning
378 inline const char* findString(const char* contentStart
, const char* contentEnd
, const char* string
)
381 const char* currentPosition
;
384 stringLength
= strlen(string
);
385 currentPosition
= contentStart
;
386 for (currentPosition
= contentStart
; currentPosition
< contentEnd
; currentPosition
++)
388 if (*currentPosition
== string
[0])
390 if (currentPosition
+ stringLength
< contentEnd
)
392 if (strncmp(currentPosition
, string
, stringLength
) == 0)
394 found
= currentPosition
;
404 typedef ds_status(* ds_score_deserializer
)(ds_device
* device
, const unsigned char* serializedScore
, unsigned int serializedScoreSize
);
405 inline ds_status
readProfileFromFile(ds_profile
* profile
, ds_score_deserializer deserializer
, const char* file
)
408 ds_status status
= DS_SUCCESS
;
409 char* contentStart
= NULL
;
410 const char* contentEnd
= NULL
;
413 if (profile
== NULL
) return DS_INVALID_PROFILE
;
415 status
= readProFile(file
, &contentStart
, &contentSize
);
416 if (status
== DS_SUCCESS
)
418 const char* currentPosition
;
419 const char* dataStart
;
421 size_t versionStringLength
;
423 contentEnd
= contentStart
+ contentSize
;
424 currentPosition
= contentStart
;
427 // parse the version string
428 dataStart
= findString(currentPosition
, contentEnd
, DS_TAG_VERSION
);
429 if (dataStart
== NULL
)
431 status
= DS_PROFILE_FILE_ERROR
;
434 dataStart
+= strlen(DS_TAG_VERSION
);
436 dataEnd
= findString(dataStart
, contentEnd
, DS_TAG_VERSION_END
);
439 status
= DS_PROFILE_FILE_ERROR
;
443 versionStringLength
= strlen(profile
->version
);
444 if (versionStringLength
!= static_cast<size_t>(dataEnd
- dataStart
)
445 || strncmp(profile
->version
, dataStart
, versionStringLength
) != 0)
448 status
= DS_PROFILE_FILE_ERROR
;
451 currentPosition
= dataEnd
+ strlen(DS_TAG_VERSION_END
);
453 // parse the device information
458 const char* deviceTypeStart
;
459 const char* deviceTypeEnd
;
460 ds_device_type deviceType
;
462 const char* deviceNameStart
;
463 const char* deviceNameEnd
;
465 const char* deviceScoreStart
;
466 const char* deviceScoreEnd
;
468 const char* deviceDriverStart
;
469 const char* deviceDriverEnd
;
471 dataStart
= findString(currentPosition
, contentEnd
, DS_TAG_DEVICE
);
472 if (dataStart
== NULL
)
474 // nothing useful remain, quit...
477 dataStart
+= strlen(DS_TAG_DEVICE
);
478 dataEnd
= findString(dataStart
, contentEnd
, DS_TAG_DEVICE_END
);
481 status
= DS_PROFILE_FILE_ERROR
;
485 // parse the device type
486 deviceTypeStart
= findString(dataStart
, contentEnd
, DS_TAG_DEVICE_TYPE
);
487 if (deviceTypeStart
== NULL
)
489 status
= DS_PROFILE_FILE_ERROR
;
492 deviceTypeStart
+= strlen(DS_TAG_DEVICE_TYPE
);
493 deviceTypeEnd
= findString(deviceTypeStart
, contentEnd
, DS_TAG_DEVICE_TYPE_END
);
494 if (deviceTypeEnd
== NULL
)
496 status
= DS_PROFILE_FILE_ERROR
;
499 memcpy(&deviceType
, deviceTypeStart
, sizeof(ds_device_type
));
502 // parse the device name
503 if (deviceType
== DS_DEVICE_OPENCL_DEVICE
)
506 deviceNameStart
= findString(dataStart
, contentEnd
, DS_TAG_DEVICE_NAME
);
507 if (deviceNameStart
== NULL
)
509 status
= DS_PROFILE_FILE_ERROR
;
512 deviceNameStart
+= strlen(DS_TAG_DEVICE_NAME
);
513 deviceNameEnd
= findString(deviceNameStart
, contentEnd
, DS_TAG_DEVICE_NAME_END
);
514 if (deviceNameEnd
== NULL
)
516 status
= DS_PROFILE_FILE_ERROR
;
521 deviceDriverStart
= findString(dataStart
, contentEnd
, DS_TAG_DEVICE_DRIVER_VERSION
);
522 if (deviceDriverStart
== NULL
)
524 status
= DS_PROFILE_FILE_ERROR
;
527 deviceDriverStart
+= strlen(DS_TAG_DEVICE_DRIVER_VERSION
);
528 deviceDriverEnd
= findString(deviceDriverStart
, contentEnd
, DS_TAG_DEVICE_DRIVER_VERSION_END
);
529 if (deviceDriverEnd
== NULL
)
531 status
= DS_PROFILE_FILE_ERROR
;
536 // check if this device is on the system
537 for (i
= 0; i
< profile
->numDevices
; i
++)
539 if (profile
->devices
[i
].type
== DS_DEVICE_OPENCL_DEVICE
)
541 size_t actualDeviceNameLength
;
542 size_t driverVersionLength
;
544 actualDeviceNameLength
= strlen(profile
->devices
[i
].oclDeviceName
);
545 driverVersionLength
= strlen(profile
->devices
[i
].oclDriverVersion
);
546 if (actualDeviceNameLength
== static_cast<size_t>(deviceNameEnd
- deviceNameStart
)
547 && driverVersionLength
== static_cast<size_t>(deviceDriverEnd
- deviceDriverStart
)
548 && strncmp(profile
->devices
[i
].oclDeviceName
, deviceNameStart
, actualDeviceNameLength
) == 0
549 && strncmp(profile
->devices
[i
].oclDriverVersion
, deviceDriverStart
, driverVersionLength
) == 0)
552 deviceScoreStart
= findString(dataStart
, contentEnd
, DS_TAG_SCORE
);
553 if (deviceNameStart
== NULL
)
555 status
= DS_PROFILE_FILE_ERROR
;
558 deviceScoreStart
+= strlen(DS_TAG_SCORE
);
559 deviceScoreEnd
= findString(deviceScoreStart
, contentEnd
, DS_TAG_SCORE_END
);
560 status
= deserializer(profile
->devices
+ i
, (const unsigned char*)deviceScoreStart
, deviceScoreEnd
- deviceScoreStart
);
561 if (status
!= DS_SUCCESS
)
570 else if (deviceType
== DS_DEVICE_NATIVE_CPU
)
572 for (i
= 0; i
< profile
->numDevices
; i
++)
574 if (profile
->devices
[i
].type
== DS_DEVICE_NATIVE_CPU
)
576 deviceScoreStart
= findString(dataStart
, contentEnd
, DS_TAG_SCORE
);
577 if (deviceScoreStart
== NULL
)
579 status
= DS_PROFILE_FILE_ERROR
;
582 deviceScoreStart
+= strlen(DS_TAG_SCORE
);
583 deviceScoreEnd
= findString(deviceScoreStart
, contentEnd
, DS_TAG_SCORE_END
);
584 status
= deserializer(profile
->devices
+ i
, (const unsigned char*)deviceScoreStart
, deviceScoreEnd
- deviceScoreStart
);
585 if (status
!= DS_SUCCESS
)
593 // skip over the current one to find the next device
594 currentPosition
= dataEnd
+ strlen(DS_TAG_DEVICE_END
);
598 if (contentStart
!= NULL
) free(contentStart
);
602 inline ds_status
getNumDeviceWithEmptyScore(ds_profile
* profile
, unsigned int* num
)
605 if (profile
== NULL
|| num
== NULL
) return DS_MEMORY_ERROR
;
607 for (i
= 0; i
< profile
->numDevices
; i
++)
609 if (profile
->devices
[i
].score
== NULL
)
619 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */