Beispiel #1
0
/*
 * Muestra por pantalla información sobre todas las plataformas y dispositivos
 * compatibles con OpenCL en el sistema.
 */
void showClInfo () {
	cl_platform_id *ps;
	cl_device_id *ds = NULL;
	cl_uint ps_size, ds_size, i, j;
	char name[STR_BUFFER_SIZE], vendor[STR_BUFFER_SIZE];

	getAllPlatforms(&ps, &ps_size);
	for (i = 0; i < ps_size; i++) {
		clGetPlatformInfo(ps[i], CL_PLATFORM_NAME, STR_BUFFER_SIZE,
			(void*)name, NULL);
		clGetPlatformInfo(ps[i], CL_PLATFORM_VENDOR, STR_BUFFER_SIZE,
			(void*)vendor, NULL);
		printf("Platform #%d - %s (%s)\n", i, name, vendor);
		getAllDevices(ps[i], &ds, &ds_size);
		for (j = 0; j < ds_size; j++) {
			clGetDeviceInfo(ds[j], CL_DEVICE_NAME, STR_BUFFER_SIZE,
				(void*)name, NULL);
			clGetDeviceInfo(ds[j], CL_DEVICE_VENDOR, STR_BUFFER_SIZE,
				(void*)vendor, NULL);
			printf("\tDevice #%d - %s (%s)\n", j, name, vendor);
		}
		free(ds);
	}
	free(ps);
}
Beispiel #2
0
/*
 * Obtiene un contexto a partir de los parámetros introducidos por la línea de
 * comandos.
 * < arg : Cadena que contiene el parámetro que selecciona los dispositvos. Debe
 *         ser de forma: List = p_id-d_id[[;, ]List].
 * > sel_ds : Array con los dispitivos seleccionados.
 */
cl_context createContextFromArgs (char *arg, cl_device_id *sel_ds,
								  cl_uint *sel_ds_size) {
	cl_uint is[BUFFER_SIZE], is_size = 0, ps_size, ds_sizes[BUFFER_SIZE], i,
			props_size = 0;
	char *str, tmp[STR_BUFFER_SIZE];
	cl_platform_id *ps, p;
	cl_device_id *ds[BUFFER_SIZE], d;
	cl_context_properties props[BUFFER_SIZE];

	*sel_ds_size = 0;
	if (arg == NULL || arg[0] == '\0')
		return NULL;

	/* Obtenemos todos indices a partir de la cadena de entrada */
	str = strtok(strcpy(tmp, arg), ",; ");
	do {
		if (sscanf(str, "%u-%u", &is[is_size], &is[is_size + 1]) >= 2)
			is_size += 2;
	} while ((str = strtok(NULL, ",; ")) != NULL);
	if (is_size == 0)
		return NULL;

	/* Obtenemos todas las plataformas y dispositivos del sistema */
	getAllPlatforms(&ps, &ps_size);
	for (i = 0; i < ps_size; i++) {
		getAllDevices(ps[i], &ds[i], &ds_sizes[i]);
	}

	/* Obtenemos los dispositivos seleccionados a partir de los indices */
	for (i = 0; i < is_size; i += 2) {
		if (is[i] >= ps_size || is[i + 1] >= ds_sizes[is[i]]) {
			fprintf(stderr, "ERROR: Device %d-%d does not exist\n",
					is[i], is[i + 1]);
			return NULL;
		}
		else {
			p = ps[is[i]];
			d = ds[is[i]][is[i + 1]];
			props[props_size++] = CL_CONTEXT_PLATFORM;
			props[props_size++] = (cl_context_properties)p;
			sel_ds[(*sel_ds_size)++] = d;
		}
	}
	props[props_size] = (cl_context_properties)NULL;

	/* Liberamos recursos */
	free(ps);
	for (i = 0; i < ps_size; i++)
		free(ds[i]);
	
	/* Creamos y devolvemos el contexto */
	return clCreateContext(props, *sel_ds_size, sel_ds, NULL, NULL, NULL);
}
Beispiel #3
0
/**
 * @brief Prints a list containing the ID of all available OpenCL devices
 * @param mpiRank The MPI process number which is calling the function
 */
void listDevices(const int mpiRank) {

	// OpenCL variables
	auto allDevices = getAllDevices();
	std::string devices = "Process " + std::to_string(mpiRank) + ": ";
	devices += (allDevices.empty()) ? "No OpenCL devices in this node" : "OpenCL Devices in this node:";

	for(int i = 0; i < allDevices.size(); ++i) {
		char nameBuff[128];
		size_t maxWorkitems[3];
		unsigned int maxCU;
		check(clGetDeviceInfo(allDevices[i], CL_DEVICE_NAME, sizeof(nameBuff), nameBuff, NULL) != CL_SUCCESS, "%s\n", CL_ERROR_DEVICE_NAME);
		check(clGetDeviceInfo(allDevices[i], CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(cl_uint), &maxCU, NULL) != CL_SUCCESS, "%s\n", CL_ERROR_DEVICE_MAXCU);
		check(clGetDeviceInfo(allDevices[i], CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(size_t) * 3, maxWorkitems, NULL) != CL_SUCCESS, "%s\n", CL_ERROR_DEVICE_MAXWORKITEMS);
		devices += "\n\tDevice " + std::to_string(i) + " ->  Name: " + nameBuff + ";  Compute units: " + std::to_string(maxCU) + ";  Max Work-items: " + std::to_string(maxWorkitems[0]);
	}
	fprintf(stdout, "%s\n", devices.c_str());
}
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    calib_vs_vision = false;

    sql = new SQLite("../data/main.db", "passwd");

    for(int i = 0 ; i < 8 ; i++){
        colors.push_back(0);
    }

    image = new QCustomLabel();
    image->setMouseTracking(true);
    QObject::connect(image, SIGNAL(Mouse_Pos()), this, SLOT(mouseCurrentPos()));
    QObject::connect(image, SIGNAL(Mouse_Left_Pressed()), this, SLOT(mouseLeftPressed()));
    QObject::connect(image, SIGNAL(Mouse_Right_Pressed()), this, SLOT(mouseRightPressed()));

    ui->layoutH2->addWidget(image);

    QObject::connect(&calib, SIGNAL(finished()), this, SLOT(quit()));
    calib.alloc_label_input(image);
    calib.alloc_calibration(&_calib);

    QObject::connect(&vi, SIGNAL(finished()), this, SLOT(quit()));
    vi.alloc_label_input(image);
    vi.alloc_calibration(&_calib);
    vi.alloc_state(&state);
    vi.alloc_colors(&colors);
    vi.alloc_execution_config(&execConfig);

    calib.start();
    vi.start();

    image->show();


    coordinate_mouse = new QLabel("M(0, 0)");

    mainItem = new QTreeWidgetItem;

    cmbCameraIds = new QComboBox();
    cmbSavedImages = new QComboBox();
    cmbSavedVideos = new QComboBox();

    checkUseCamera = new QCheckBox();
    checkUseImage = new QCheckBox();
    checkUseVideo = new QCheckBox();

    cmbColors = new QComboBox();
    cmbBallColors = new QComboBox();
    cmbMainColors_1 = new QComboBox();
    cmbMainColors_2 = new QComboBox();
    cmbSecColors_1 = new QComboBox();
    cmbSecColors_2 = new QComboBox();
    cmbSecColors_3 = new QComboBox();
    cmbSecColors_4 = new QComboBox();
    cmbSecColors_5 = new QComboBox();
    cmbSecColors_6 = new QComboBox();

    btnDoColorCalib = new QPushButton("Do", this);
    btnRunVision = new QPushButton("Run", this);

    blockdevice = QIcon(":icons/blockdevice.png");
    ksame = QIcon(":icons/ksame.png");
    kdf = QIcon(":icons/kdf.png");
    package = QIcon(":icons/package.png");

    getAllDevices();
    buildTrees();

    if(devices.size() < 1){
        checkUseCamera->setChecked(false);
        checkUseImage->setChecked(true);
        checkUseVideo->setChecked(false);
        cmbCameraIds->setDisabled(true);

    }else{
        checkUseCamera->setChecked(true);
        checkUseImage->setChecked(false);
        checkUseVideo->setChecked(false);
    }

    lblH = new QLabel("H (0 - 180)");
    lblS = new QLabel("S (0 - 255)");
    lblV = new QLabel("V (0 - 255)");

    lbl_val = new QLabel("Pos\nVel\nKPos\nKVel");

    val_ball = new QLabel("Ball");
    val_robot1 = new QLabel("Robot 1");
    val_robot2 = new QLabel("Robot 2");
    val_robot3 = new QLabel("Robot 3");
    val_robot4 = new QLabel("Robot 4");
    val_robot5 = new QLabel("Robot 5");
    val_robot6 = new QLabel("Robot 6");

    h_val_ball = new QLabel("000, 000, 0.00\n000, 000, 0.00\n000, 000, 0.00\n000, 000, 0.00\n");
    h_val_robot1 = new QLabel("000, 000, 0.00\n000, 000, 0.00\n000, 000, 0.00\n000, 000, 0.00\n");
    h_val_robot2 = new QLabel("000, 000, 0.00\n000, 000, 0.00\n000, 000, 0.00\n000, 000, 0.00\n");
    h_val_robot3 = new QLabel("000, 000, 0.00\n000, 000, 0.00\n000, 000, 0.00\n000, 000, 0.00\n");
    h_val_robot4 = new QLabel("000, 000, 0.00\n000, 000, 0.00\n000, 000, 0.00\n000, 000, 0.00\n");
    h_val_robot5 = new QLabel("000, 000, 0.00\n000, 000, 0.00\n000, 000, 0.00\n000, 000, 0.00\n");
    h_val_robot6 = new QLabel("000, 000, 0.00\n000, 000, 0.00\n000, 000, 0.00\n000, 000, 0.00\n");

    lbl_val->setStyleSheet("QLabel {qproperty-alignment: AlignCenter; font-size: 14px; background: white; border: 1px solid #bbb;");

    h_val_ball->setStyleSheet("QLabel {qproperty-alignment: AlignCenter; font-size: 14px; background: white; border: 1px solid #bbb;}");
    h_val_robot1->setStyleSheet("QLabel {qproperty-alignment: AlignCenter; font-size: 14px; background: white; border: 1px solid #bbb;}");
    h_val_robot2->setStyleSheet("QLabel {qproperty-alignment: AlignCenter; font-size: 14px; background: white; border: 1px solid #bbb;}");
    h_val_robot3->setStyleSheet("QLabel {qproperty-alignment: AlignCenter; font-size: 14px; background: white; border: 1px solid #bbb;}");
    h_val_robot4->setStyleSheet("QLabel {qproperty-alignment: AlignCenter; font-size: 14px; background: white; border: 1px solid #bbb;}");
    h_val_robot5->setStyleSheet("QLabel {qproperty-alignment: AlignCenter; font-size: 14px; background: white; border: 1px solid #bbb;}");
    h_val_robot6->setStyleSheet("QLabel {qproperty-alignment: AlignCenter; font-size: 14px; background: white; border: 1px solid #bbb;}");

    sliderHmin = new QSlider(Qt::Orientation(VerticalTabs));
    sliderHmax = new QSlider(Qt::Orientation(VerticalTabs));
    sliderSmin = new QSlider(Qt::Orientation(VerticalTabs));
    sliderSmax = new QSlider(Qt::Orientation(VerticalTabs));
    sliderVmin = new QSlider(Qt::Orientation(VerticalTabs));
    sliderVmax = new QSlider(Qt::Orientation(VerticalTabs));

    sliderHmin->setMaximum(179);
    sliderSmin->setMaximum(254);
    sliderVmin->setMaximum(254);
    sliderHmax->setMaximum(180);
    sliderSmax->setMaximum(255);
    sliderVmax->setMaximum(255);

    sliderHmin->setMinimum(0);
    sliderSmin->setMinimum(0);
    sliderVmin->setMinimum(0);
    sliderHmax->setMinimum(1);
    sliderSmax->setMinimum(1);
    sliderVmax->setMinimum(1);

    sliderHmin->setMinimumHeight(140);
    sliderSmin->setMinimumHeight(140);
    sliderVmin->setMinimumHeight(140);
    sliderHmax->setMinimumHeight(140);
    sliderSmax->setMinimumHeight(140);
    sliderVmax->setMinimumHeight(140);

    sliderHmin->setValue(_calib.colors.at(0).min.rgb[h]);
    sliderSmin->setValue(_calib.colors.at(0).min.rgb[s]);
    sliderVmin->setValue(_calib.colors.at(0).min.rgb[v]);
    sliderHmax->setValue(_calib.colors.at(0).max.rgb[h]);
    sliderSmax->setValue(_calib.colors.at(0).max.rgb[s]);
    sliderVmax->setValue(_calib.colors.at(0).max.rgb[v]);

    connect(sliderHmin, SIGNAL(valueChanged(int)), this, SLOT(updateHmin(int)));
    connect(sliderSmin, SIGNAL(valueChanged(int)), this, SLOT(updateSmin(int)));
    connect(sliderVmin, SIGNAL(valueChanged(int)), this, SLOT(updateVmin(int)));
    connect(sliderHmax, SIGNAL(valueChanged(int)), this, SLOT(updateHmax(int)));
    connect(sliderSmax, SIGNAL(valueChanged(int)), this, SLOT(updateSmax(int)));
    connect(sliderVmax, SIGNAL(valueChanged(int)), this, SLOT(updateVmax(int)));

    updateValuesHSV();
    update_hsv_s();

    lblH->setStyleSheet("QLabel {qproperty-alignment: AlignCenter; font-weight: bold;}");
    lblS->setStyleSheet("QLabel {qproperty-alignment: AlignCenter; font-weight: bold;}");
    lblV->setStyleSheet("QLabel {qproperty-alignment: AlignCenter; font-weight: bold;}");

    sliderHmax->setStyleSheet("QSlider{ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0.0 #00f, stop: 0.167 #f0f, stop: 0.334 #f00, stop: 0.501 #ff0, stop: 0.668 #0f0, stop: 0.835 #0ff, stop: 1.0 #00f)}");
    sliderHmin->setStyleSheet("QSlider{ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0.0 #00f, stop: 0.167 #f0f, stop: 0.334 #f00, stop: 0.501 #ff0, stop: 0.668 #0f0, stop: 0.835 #0ff, stop: 1.0 #00f)}");

    sliderSmin->setStyleSheet(hsv_s.c_str());
    sliderSmax->setStyleSheet(hsv_s.c_str());

    sliderVmin->setStyleSheet("QSlider{ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #fff, stop: 1 #000)}");
    sliderVmax->setStyleSheet("QSlider{ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #fff, stop: 1 #000)}");

    ui->layoutH3->setContentsMargins(2, 0, 2, 0);
    ui->layoutH4->setContentsMargins(2, 0, 2, 0);
    ui->layoutH5->setContentsMargins(2, 0, 2, 0);
    ui->layoutH6->setContentsMargins(2, 0, 2, 0);
    ui->layoutH7->setContentsMargins(2, 0, 2, 0);
    ui->layoutH8->setContentsMargins(2, 0, 2, 0);
    ui->layoutH9->setContentsMargins(2, 0, 2, 0);
    ui->layoutH10->setContentsMargins(2, 0, 2, 0);
}
Beispiel #5
0
/**
 * @brief Creates an array of objects containing the OpenCL variables of each device
 * @param trDataBase The training database which will contain the instances and the features
 * @param selInstances The instances choosen as initial centroids
 * @param transposedTrDataBase The training database already transposed
 * @param conf The structure with all configuration parameters
 * @return A pointer containing the objects
 */
CLDevice *createDevices(const float *const trDataBase, const int *const selInstances, const float *const transposedTrDataBase, Config *const conf) {


	/********** Find the OpenCL devices specified in configuration ***********/

	// OpenCL variables
	cl_uint numPlatformsDevices;
	cl_device_type deviceType;
	cl_program program;
	cl_kernel kernel;
	cl_int status;

	// Others variables
	auto allDevices = getAllDevices();
	CLDevice *devices = new CLDevice[conf -> nDevices + (conf -> ompThreads > 0)];

	for (int dev = 0; dev < conf -> nDevices; ++dev) {

		bool found = false;
		for (int allDev = 0; allDev < allDevices.size() && !found; ++allDev) {

			// Get the specified OpenCL device
			char dbuff[120];
			check(clGetDeviceInfo(allDevices[allDev], CL_DEVICE_NAME, sizeof(dbuff), dbuff, NULL) != CL_SUCCESS, "%s\n", CL_ERROR_DEVICE_NAME);

			// If the device exists...
			if (conf -> devices[dev] == dbuff) {
				devices[dev].device = allDevices[allDev];
				devices[dev].deviceName = dbuff;
				check(clGetDeviceInfo(devices[dev].device, CL_DEVICE_TYPE, sizeof(cl_device_type), &(devices[dev].deviceType), NULL) != CL_SUCCESS, "%s\n", CL_ERROR_DEVICE_TYPE);


				/********** Device local memory usage ***********/

				long int usedMemory = conf -> nFeatures * sizeof(cl_uchar); // Chromosome of the individual
				usedMemory += conf -> trNInstances * sizeof(cl_uchar); // Mapping buffer
				usedMemory += conf -> K * conf -> nFeatures * sizeof(cl_float); // Centroids buffer
				usedMemory += conf -> trNInstances * sizeof(cl_float); // DistCentroids buffer
				usedMemory += conf -> K * sizeof(cl_int); // Samples_in_k buffer

				// Get the maximum local memory size
				long int maxMemory;
				check(clGetDeviceInfo(devices[dev].device, CL_DEVICE_LOCAL_MEM_SIZE, sizeof(long int), &maxMemory, NULL) != CL_SUCCESS, "%s\n", CL_ERROR_DEVICE_MAXMEM);

				// Avoid exceeding the maximum local memory available. 1024 bytes of margin
				check(usedMemory > maxMemory - 1024, "%s:\n\tMax memory: %ld bytes\n\tAllow memory: %ld bytes\n\tUsed memory: %ld bytes\n", CL_ERROR_DEVICE_LOCALMEM, maxMemory, maxMemory - 1024, usedMemory);


				/********** Create context ***********/

				devices[dev].context = clCreateContext(NULL, 1, &(devices[dev].device), 0, 0, &status);
				check(status != CL_SUCCESS, "%s\n", CL_ERROR_DEVICE_CONTEXT);


				/********** Create Command queue ***********/

				devices[dev].commandQueue = clCreateCommandQueue(devices[dev].context, devices[dev].device, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE | CL_QUEUE_PROFILING_ENABLE, &status);
				check(status != CL_SUCCESS, "%s\n", CL_ERROR_DEVICE_QUEUE);


				/********** Create kernel ***********/

				// Open the file containing the kernels
				std::fstream kernels(conf -> kernelsFileName.c_str(), std::fstream::in);
				check(!kernels.is_open(), "%s\n", CL_ERROR_FILE_OPEN);

				// Obtain the size
				kernels.seekg(0, kernels.end);
				size_t fSize = kernels.tellg();
				kernels.seekg(0, kernels.beg);

				char *kernelSource = new char[fSize];
				kernels.read(kernelSource, fSize);
				kernels.close();

				// Create program
				program = clCreateProgramWithSource(devices[dev].context, 1, (const char **) &kernelSource, &fSize, &status);
				check(status != CL_SUCCESS, "%s\n", CL_ERROR_PROGRAM_BUILD);

				// Build program for the device in the context
				char buildOptions[196];
				sprintf(buildOptions, "-I include -D N_INSTANCES=%d -D N_FEATURES=%d -D N_OBJECTIVES=%d -D K=%d -D MAX_ITER_KMEANS=%d", conf -> trNInstances, conf -> nFeatures, conf -> nObjectives, conf -> K, conf -> maxIterKmeans);
				if (clBuildProgram(program, 1, &(devices[dev].device), buildOptions, 0, 0) != CL_SUCCESS) {
					char buffer[4096];
					fprintf(stderr, "Error: Could not build the program\n");
					check(clGetProgramBuildInfo(program, devices[dev].device, CL_PROGRAM_BUILD_LOG, sizeof(buffer), buffer, NULL) != CL_SUCCESS, "%s\n", CL_ERROR_PROGRAM_ERRORS);
					check(true, "%s\n", buffer);
				}

				// Create kernel
				const char *kernelName = (devices[dev].deviceType == CL_DEVICE_TYPE_GPU) ? "kmeansGPU" : "";
				devices[dev].kernel = clCreateKernel(program, kernelName, &status);
				check(status != CL_SUCCESS, "%s\n", CL_ERROR_KERNEL_BUILD);


				/******* Work-items *******/

				devices[dev].computeUnits = atoi(conf -> computeUnits[dev].c_str());
				devices[dev].wiLocal = atoi(conf -> wiLocal[dev].c_str());
				devices[dev].wiGlobal = devices[dev].computeUnits * devices[dev].wiLocal;


				/******* Create and write the databases and centroids buffers. Create the subpopulations buffer. Set kernel arguments *******/

				// Create buffers
				devices[dev].objSubpopulations = clCreateBuffer(devices[dev].context, CL_MEM_READ_WRITE, conf -> familySize * sizeof(Individual), 0, &status);
				check(status != CL_SUCCESS, "%s\n", CL_ERROR_OBJECT_SUBPOPS);

				devices[dev].objTrDataBase = clCreateBuffer(devices[dev].context, CL_MEM_READ_ONLY, conf -> trNInstances * conf -> nFeatures * sizeof(cl_float), 0, &status);
				check(status != CL_SUCCESS, "%s\n", CL_ERROR_OBJECT_TRDB);

				devices[dev].objTransposedTrDataBase = clCreateBuffer(devices[dev].context, CL_MEM_READ_ONLY, conf -> trNInstances * conf -> nFeatures * sizeof(cl_float), 0, &status);
				check(status != CL_SUCCESS, "%s\n", CL_ERROR_OBJECT_TTRDB);

				devices[dev].objSelInstances = clCreateBuffer(devices[dev].context, CL_MEM_READ_ONLY, conf -> K * sizeof(cl_int), 0, &status);
				check(status != CL_SUCCESS, "%s\n", CL_ERROR_OBJECT_CENTROIDS);

				// Sets kernel arguments
				check(clSetKernelArg(devices[dev].kernel, 0, sizeof(cl_mem), (void *)&(devices[dev].objSubpopulations)) != CL_SUCCESS, "%s\n", CL_ERROR_KERNEL_ARGUMENT1);

				check(clSetKernelArg(devices[dev].kernel, 1, sizeof(cl_mem), (void *)&(devices[dev].objSelInstances)) != CL_SUCCESS, "%s\n", CL_ERROR_KERNEL_ARGUMENT2);

				check(clSetKernelArg(devices[dev].kernel, 2, sizeof(cl_mem), (void *)&(devices[dev].objTrDataBase)) != CL_SUCCESS, "%s\n", CL_ERROR_KERNEL_ARGUMENT3);

				check(clSetKernelArg(devices[dev].kernel, 5, sizeof(cl_mem), (void *)&(devices[dev].objTransposedTrDataBase)) != CL_SUCCESS, "%s\n", CL_ERROR_KERNEL_ARGUMENT6);

				// Write buffers
				check(clEnqueueWriteBuffer(devices[dev].commandQueue, devices[dev].objTrDataBase, CL_FALSE, 0, conf -> trNInstances * conf -> nFeatures * sizeof(cl_float), trDataBase, 0, NULL, NULL) != CL_SUCCESS, "%s\n", CL_ERROR_ENQUEUE_TRDB);
				check(clEnqueueWriteBuffer(devices[dev].commandQueue, devices[dev].objSelInstances, CL_FALSE, 0, conf -> K * sizeof(cl_int), selInstances, 0, NULL, NULL) != CL_SUCCESS, "%s\n", CL_ERROR_ENQUEUE_CENTROIDS);
				check(clEnqueueWriteBuffer(devices[dev].commandQueue, devices[dev].objTransposedTrDataBase, CL_FALSE, 0, conf -> trNInstances * conf -> nFeatures * sizeof(cl_float), transposedTrDataBase, 0, NULL, NULL) != CL_SUCCESS, "%s\n", CL_ERROR_ENQUEUE_TTRDB);

				// Resources used are released
				delete[] kernelSource;
				clReleaseProgram(program);

				found = true;
				allDevices.erase(allDevices.begin() + allDev);
			}
		}

		check(!found, "%s\n", CL_ERROR_DEVICE_FOUND);
	}


	/********** Add the CPU if has been enabled in configuration ***********/

	if (conf -> ompThreads > 0) {
		devices[conf -> nDevices].deviceType = CL_DEVICE_TYPE_CPU;
		devices[conf -> nDevices].computeUnits = conf -> ompThreads;
		++(conf -> nDevices);
	}

	return devices;
}