Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / core / opencl / opencl_device_selection.h
blobd6f775a49722f6755a02d00179f5eab02bf2f27c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #ifndef SC_DEVICE_SELECTION_H
11 #define SC_DEVICE_SELECTION_H
14 #ifdef _MSC_VER
15 #define _CRT_SECURE_NO_WARNINGS
16 #endif
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include "clcc/clew.h"
23 #define DS_DEVICE_NAME_LENGTH 256
25 enum ds_status
27 DS_SUCCESS = 0
28 ,DS_INVALID_PROFILE = 1000
29 ,DS_MEMORY_ERROR
30 , DS_INVALID_PERF_EVALUATOR_TYPE
31 , DS_INVALID_PERF_EVALUATOR
32 , DS_PERF_EVALUATOR_ERROR
33 , DS_FILE_ERROR
34 , DS_UNKNOWN_DEVICE_TYPE
35 , DS_PROFILE_FILE_ERROR
36 , DS_SCORE_SERIALIZER_ERROR
37 , DS_SCORE_DESERIALIZER_ERROR
40 // device type
41 enum ds_device_type
43 DS_DEVICE_NATIVE_CPU = 0
44 ,DS_DEVICE_OPENCL_DEVICE
48 struct ds_device
50 ds_device_type type;
51 cl_device_id oclDeviceID;
52 char* oclDeviceName;
53 char* oclDriverVersion;
54 void* score; // a pointer to the score data, the content/format is application defined
57 struct ds_profile
59 unsigned int numDevices;
60 ds_device* devices;
61 const char* version;
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;
69 if (profile != NULL)
71 if (profile->devices != NULL && sr != NULL)
73 unsigned int i;
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);
83 free(profile);
85 return status;
89 inline ds_status initDSProfile(ds_profile** p, const char* version)
91 int numDevices;
92 cl_uint numPlatforms;
93 cl_platform_id* platforms = NULL;
94 cl_device_id* devices = NULL;
95 ds_status status = DS_SUCCESS;
96 ds_profile* profile = NULL;
97 unsigned int next;
98 unsigned int i;
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;
114 goto cleanup;
116 clGetPlatformIDs(numPlatforms, platforms, NULL);
119 numDevices = 0;
120 for (i = 0; i < (unsigned int)numPlatforms; i++)
122 cl_uint num;
123 clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_ALL, 0, NULL, &num);
124 numDevices += num;
126 if (numDevices != 0)
128 devices = (cl_device_id*)malloc(numDevices * sizeof(cl_device_id));
129 if (devices == NULL)
131 status = DS_MEMORY_ERROR;
132 goto cleanup;
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;
142 goto cleanup;
144 memset(profile->devices, 0, profile->numDevices * sizeof(ds_device));
146 next = 0;
147 for (i = 0; i < (unsigned int)numPlatforms; i++)
149 cl_uint num;
150 unsigned j;
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];
155 size_t 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;
176 cleanup:
177 if (platforms) free(platforms);
178 if (devices) free(devices);
179 if (status == DS_SUCCESS)
181 *p = profile;
183 else
185 if (profile)
187 if (profile->devices) free(profile->devices);
188 free(profile);
191 return status;
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);
199 typedef enum {
200 DS_EVALUATE_ALL
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;
208 unsigned int i;
209 unsigned int updates = 0;
211 if (profile == NULL)
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;
224 switch (type)
226 case DS_EVALUATE_NEW_ONLY:
227 if (profile->devices[i].score != NULL) break;
228 // else fall through
229 case DS_EVALUATE_ALL:
230 evaluatorStatus = evaluator(profile->devices + i, evaluatorData);
231 if (evaluatorStatus != DS_SUCCESS)
233 status = evaluatorStatus;
234 return status;
236 updates++;
237 break;
238 default:
239 return DS_INVALID_PERF_EVALUATOR_TYPE;
240 break;
243 if (numUpdates) *numUpdates = updates;
244 return status;
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;
279 else
281 unsigned int i;
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);
311 break;
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);
322 break;
323 default:
324 status = DS_UNKNOWN_DEVICE_TYPE;
325 break;
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);
339 fclose(profileFile);
341 return status;
345 inline ds_status readProFile(const char* fileName, char** content, size_t* contentSize)
347 FILE* input = NULL;
348 size_t size = 0;
349 char* binary = NULL;
351 *contentSize = 0;
352 *content = NULL;
354 input = fopen(fileName, "rb");
355 if (input == NULL)
357 return DS_FILE_ERROR;
360 fseek(input, 0L, SEEK_END);
361 size = ftell(input);
362 rewind(input);
363 binary = (char*)malloc(size);
364 if (binary == NULL)
366 return DS_FILE_ERROR;
368 size_t bytesRead = fread(binary, sizeof(char), size, input);
369 (void) bytesRead; // avoid warning
370 fclose(input);
372 *contentSize = size;
373 *content = binary;
374 return DS_SUCCESS;
378 inline const char* findString(const char* contentStart, const char* contentEnd, const char* string)
380 size_t stringLength;
381 const char* currentPosition;
382 const char* found;
383 found = NULL;
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;
395 break;
400 return found;
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;
411 size_t contentSize;
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;
420 const char* dataEnd;
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;
432 goto cleanup;
434 dataStart += strlen(DS_TAG_VERSION);
436 dataEnd = findString(dataStart, contentEnd, DS_TAG_VERSION_END);
437 if (dataEnd == NULL)
439 status = DS_PROFILE_FILE_ERROR;
440 goto cleanup;
443 versionStringLength = strlen(profile->version);
444 if (versionStringLength != static_cast<size_t>(dataEnd - dataStart)
445 || strncmp(profile->version, dataStart, versionStringLength) != 0)
447 // version mismatch
448 status = DS_PROFILE_FILE_ERROR;
449 goto cleanup;
451 currentPosition = dataEnd + strlen(DS_TAG_VERSION_END);
453 // parse the device information
454 while (1)
456 unsigned int i;
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...
475 break;
477 dataStart += strlen(DS_TAG_DEVICE);
478 dataEnd = findString(dataStart, contentEnd, DS_TAG_DEVICE_END);
479 if (dataEnd == NULL)
481 status = DS_PROFILE_FILE_ERROR;
482 goto cleanup;
485 // parse the device type
486 deviceTypeStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_TYPE);
487 if (deviceTypeStart == NULL)
489 status = DS_PROFILE_FILE_ERROR;
490 goto cleanup;
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;
497 goto cleanup;
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;
510 goto cleanup;
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;
517 goto cleanup;
521 deviceDriverStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION);
522 if (deviceDriverStart == NULL)
524 status = DS_PROFILE_FILE_ERROR;
525 goto cleanup;
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;
532 goto cleanup;
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;
556 goto cleanup;
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)
563 goto cleanup;
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;
580 goto cleanup;
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)
587 goto cleanup;
593 // skip over the current one to find the next device
594 currentPosition = dataEnd + strlen(DS_TAG_DEVICE_END);
597 cleanup:
598 if (contentStart != NULL) free(contentStart);
599 return status;
602 inline ds_status getNumDeviceWithEmptyScore(ds_profile* profile, unsigned int* num)
604 unsigned int i;
605 if (profile == NULL || num == NULL) return DS_MEMORY_ERROR;
606 *num = 0;
607 for (i = 0; i < profile->numDevices; i++)
609 if (profile->devices[i].score == NULL)
611 (*num)++;
614 return DS_SUCCESS;
617 #endif
619 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */