void dt_opencl_cleanup(dt_opencl_t *cl) { if(cl->inited) { dt_bilateral_free_cl_global(cl->bilateral); dt_gaussian_free_cl_global(cl->gaussian); for(int i=0; i<cl->num_devs; i++) { dt_pthread_mutex_destroy(&cl->dev[i].lock); for(int k=0; k<DT_OPENCL_MAX_KERNELS; k++) if(cl->dev[i].kernel_used [k]) (cl->dlocl->symbols->dt_clReleaseKernel) (cl->dev[i].kernel [k]); for(int k=0; k<DT_OPENCL_MAX_PROGRAMS; k++) if(cl->dev[i].program_used[k]) (cl->dlocl->symbols->dt_clReleaseProgram)(cl->dev[i].program[k]); (cl->dlocl->symbols->dt_clReleaseCommandQueue)(cl->dev[i].cmd_queue); (cl->dlocl->symbols->dt_clReleaseContext)(cl->dev[i].context); dt_opencl_events_reset(i); if(cl->dev[i].eventlist) free(cl->dev[i].eventlist); if(cl->dev[i].eventtags) free(cl->dev[i].eventtags); } } if(cl->dlocl) { free(cl->dlocl->symbols); free(cl->dlocl); } dt_pthread_mutex_destroy(&cl->lock); }
/** Wait for events in eventlist to terminate, check for return status and profiling info of events. If "reset" is TRUE report summary info (would be CL_COMPLETE or last error code) and print profiling info if needed. If "reset" is FALSE just store info (success value, profiling) from terminated events and release events for re-use by OpenCL driver. */ cl_int dt_opencl_events_flush(const int devid, const int reset) { dt_opencl_t *cl = darktable.opencl; if(!cl->inited || devid < 0) return FALSE; cl_event **eventlist = &(cl->dev[devid].eventlist); dt_opencl_eventtag_t **eventtags = &(cl->dev[devid].eventtags); int *numevents = &(cl->dev[devid].numevents); int *eventsconsolidated = &(cl->dev[devid].eventsconsolidated); int *lostevents = &(cl->dev[devid].lostevents); cl_int *summary = &(cl->dev[devid].summary); if (*eventlist==NULL || *numevents==0) return CL_COMPLETE; // nothing to do, no news is good news // Wait for command queue to terminate (side effect: might adjust *numevents) dt_opencl_events_wait_for(devid); // now check return status and profiling data of all newly terminated events for (int k = *eventsconsolidated; k < *numevents; k++) { cl_int err; char *tag = (*eventtags)[k].tag; cl_int *retval = &((*eventtags)[k].retval); // get return value of event err = (cl->dlocl->symbols->dt_clGetEventInfo)((*eventlist)[k], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(cl_int), retval, NULL); if (err != CL_SUCCESS) { dt_print(DT_DEBUG_OPENCL, "[opencl_events_flush] could not get event info for '%s': %d\n", tag[0] == '\0' ? "<?>" : tag, err); } else if (*retval != CL_COMPLETE) { dt_print(DT_DEBUG_OPENCL, "[opencl_events_flush] execution of '%s' %s: %d\n", tag[0] == '\0' ? "<?>" : tag, *retval == CL_COMPLETE ? "was successful" : "failed", *retval); *summary=*retval; } // get profiling info of event cl_ulong start; cl_ulong end; cl_int errs = (cl->dlocl->symbols->dt_clGetEventProfilingInfo)((*eventlist)[k], CL_PROFILING_COMMAND_START, sizeof(cl_ulong), &start, NULL); cl_int erre = (cl->dlocl->symbols->dt_clGetEventProfilingInfo)((*eventlist)[k], CL_PROFILING_COMMAND_END, sizeof(cl_ulong), &end, NULL); if (errs == CL_SUCCESS && erre == CL_SUCCESS) { (*eventtags)[k].timelapsed = end - start; } else { (*eventtags)[k].timelapsed = 0; (*lostevents)++; } // finally release event to be re-used by driver (cl->dlocl->symbols->dt_clReleaseEvent)((*eventlist)[k]); (*eventsconsolidated)++; } cl_int result = *summary; // do we want to get rid of all stored info? if(reset) { // output profiling info if wanted if (darktable.unmuted & DT_DEBUG_PERF) dt_opencl_events_profiling(devid, 1); // reset eventlist structures to empty state dt_opencl_events_reset(devid); } return result == CL_COMPLETE ? 0 : result; }