#define CL_TARGET_OPENCL_VERSION 120
#include "ocl_boiler.h"
#include <stdio.h>
#include <stdlib.h>

void error(const char *err)
{
	fprintf(stderr, "%s\n", err);
	exit(1);
}

cl_event init_array(cl_command_queue que, cl_kernel init_kernel, cl_mem d_array, int nels)
{
	size_t gws[] = { nels };
	cl_int err;
	cl_event ret;

	err = clSetKernelArg(init_kernel, 0, sizeof(d_array), &d_array);
	ocl_check(err, "set init_array arg");

	err = clEnqueueNDRangeKernel(que, init_kernel, 1,
		NULL, gws, NULL,
		0, NULL,  &ret);
	ocl_check(err, "enqueue init");

	return ret;
}

void verify(const int *array, int nels)
{
	for (int i = 0; i < nels; ++i) {
		if (array[i] != i) {
			fprintf(stderr, "mismatch @ %d: %d != %d\n",
				i, array[i], i);
		}
	}
}

int main(int argc, char *argv[])
{
	if (argc != 2) error("please specify number of elements");

	int nels = atoi(argv[1]);

	if (nels <= 0) error("please specify a positive integer");

	cl_platform_id p = select_platform();
	cl_device_id d = select_device(p);
	cl_context ctx = create_context(p, d);
	cl_command_queue que = create_queue(ctx, d);
	cl_program prog = create_program("vecinit.ocl", ctx, d);

	cl_int err;
	cl_kernel init_kernel = clCreateKernel(prog, "init_kernel", &err);
	ocl_check(err, "create init_kernel");

	cl_mem d_array = clCreateBuffer(ctx, CL_MEM_WRITE_ONLY,
		nels*sizeof(int), NULL, &err);
	ocl_check(err, "create d_buffer failed");

	cl_event init_evt = init_array(que, init_kernel, d_array, nels);

	int *h_array = malloc(nels*sizeof(int));

	if (h_array == NULL) error("failled to allocate array");

	cl_event read_evt;

	err = clEnqueueReadBuffer(que, d_array, CL_TRUE,
		0, nels*sizeof(int), h_array,
		1, &init_evt, &read_evt);
	ocl_check(err, "read buffer");

	verify(h_array, nels);

	double init_runtime = runtime_ms(init_evt);
	double read_runtime = runtime_ms(read_evt);

	printf("init: %gms\n", init_runtime);
	printf("read: %gms\n", read_runtime);

	free(h_array);

	clReleaseKernel(init_kernel);
	clReleaseMemObject(d_array);
	clReleaseProgram(prog);
	clReleaseCommandQueue(que);
	clReleaseContext(ctx);
}
