211 float *in = (
float *)malloc(
sizeof(
float) *
NSAMPLES);
212 float *
out = (
float *)malloc(
sizeof(
float) *
NSAMPLES);
213 if(!in || !
out) { fprintf(stderr,
"out of memory\n");
return 1; }
217 printf(
"Ansel OpenCL math accuracy probe\n");
218 printf(
"max relative error against a double-precision reference, x in [%.0f, %.0f]\n"
219 "a correct single-precision implementation scores ~1e-7; anything above %.0e is a\n"
223 printf(
"================ CPU (this tool's own build) ================\n");
225 printf(
"%-46s",
"host libm");
226 for(
int o = 0; o <
N_OPS; o++)
231 printf(
"\n\nRebuild this tool at -O2, at -O3, and at -O3 -ffast-math to compare the CPU path\n"
232 "across optimisation levels; the row above reflects whichever was used.\n");
235 cl_platform_id platforms[16];
236 cl_uint n_platforms = 0;
237 if(clGetPlatformIDs(16, platforms, &n_platforms) != CL_SUCCESS || n_platforms == 0)
239 printf(
"\nNo OpenCL platform found.\n");
244 int device_index = 0;
245 for(cl_uint
p = 0;
p < n_platforms;
p++)
247 cl_device_id devices[8];
248 cl_uint n_devices = 0;
249 if(clGetDeviceIDs(platforms[
p], CL_DEVICE_TYPE_GPU, 8, devices, &n_devices) != CL_SUCCESS)
continue;
251 for(cl_uint
d = 0;
d < n_devices;
d++)
253 char name[256] = { 0 };
254 clGetDeviceInfo(devices[
d], CL_DEVICE_NAME,
sizeof(
name),
name, NULL);
256 cl_int err = CL_SUCCESS;
257 cl_context ctx = clCreateContext(NULL, 1, &devices[
d], NULL, NULL, &err);
258 if(err != CL_SUCCESS) { printf(
"\n%s: cannot create a context (%d), skipping\n",
name, err);
continue; }
259 cl_command_queue queue = clCreateCommandQueueWithProperties(ctx, devices[
d], NULL, &err);
260 cl_mem d_in = clCreateBuffer(ctx, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
261 sizeof(
float) *
NSAMPLES, in, &err);
262 cl_mem d_out = clCreateBuffer(ctx, CL_MEM_WRITE_ONLY,
sizeof(
float) *
NSAMPLES, NULL, &err);
264 printf(
"\n================ device %d: %s ================\n", device_index,
name);
268 int default_fails = 0;
271 cl_program program = clCreateProgramWithSource(ctx, 1, &
KERNEL_SRC, NULL, &err);
272 if(clBuildProgram(program, 1, &devices[
d],
OPTION_SETS[
f].
flags, NULL, NULL) != CL_SUCCESS)
275 clReleaseProgram(program);
278 cl_kernel
kernel = clCreateKernel(program,
"probe", &err);
281 int fails = 0, broken = 0;
282 for(
int o = 0; o <
N_OPS; o++)
284 clSetKernelArg(
kernel, 0,
sizeof(cl_mem), &d_in);
285 clSetKernelArg(
kernel, 1,
sizeof(cl_mem), &d_out);
286 clSetKernelArg(
kernel, 2,
sizeof(
int), &o);
288 clEnqueueNDRangeKernel(queue,
kernel, 1, NULL, &global, NULL, 0, NULL, NULL);
290 clEnqueueReadBuffer(queue, d_out, CL_TRUE, 0,
sizeof(
float) *
NSAMPLES,
out, 0, NULL, NULL);
295 printf(
"%11.2e", rel);
297 printf(
"%s\n", broken ?
" <-- BROKEN" : (fails ?
" <-- degraded" :
""));
299 if(!fails) best_safe =
f;
300 if(
OPTION_SETS[
f].is_ansel_default && broken) default_fails = 1;
303 clReleaseProgram(program);
311 printf(
"VERDICT: this device's math library is NOT accurate under Ansel's legacy default.\n");
312 printf(
"Put this in anselrc (it is per device, and Ansel rewrites it only if absent):\n\n");
313 printf(
" cldevice_v4/%d/%s/building=%s\n\n", device_index, cname,
314 best_safe >= 0 ?
OPTION_SETS[best_safe].
flags :
"-cl-mad-enable -cl-no-signed-zeros");
315 printf(
"then delete %s's cached kernels so they rebuild:\n",
name);
316 printf(
" rm -rf ~/.cache/ansel/cached_kernels_for_*\n");
320 printf(
"VERDICT: accurate under every option set probed; no anselrc change needed.\n");
321 printf(
"Current key would be: cldevice_v4/%d/%s/building=...\n", device_index, cname);
324 clReleaseMemObject(d_in);
325 clReleaseMemObject(d_out);
326 clReleaseCommandQueue(queue);
327 clReleaseContext(ctx);