def benchmark(self, func, gpu_args, threads, grid, times):
        """runs the kernel and measures time repeatedly, returns average time

        Runs the kernel and measures kernel execution time repeatedly, number of
        iterations is set during the creation of OpenCLFunctions. Benchmark returns
        a robust average, from all measurements the fastest and slowest runs are
        discarded and the rest is included in the returned average. The reason for
        this is to be robust against initialization artifacts and other exceptional
        cases.

        :param func: A PyOpenCL kernel compiled for this specific kernel configuration
        :type func: pyopencl.Kernel

        :param gpu_args: A list of arguments to the kernel, order should match the
            order in the code. Allowed values are either variables in global memory
            or single values passed by value.
        :type gpu_args: list( pyopencl.Buffer, numpy.int32, ...)

        :param threads: A tuple listing the number of work items in each dimension of
            the work group.
        :type threads: tuple(int, int, int)

        :param grid: A tuple listing the number of work groups in each dimension
            of the NDRange.
        :type grid: tuple(int, int)

        :param times: Return the execution time of all iterations.
        :type times: bool

        :returns: All execution times, if times=True, or a robust average for the
            kernel execution time.
        :rtype: float
        """
        global_size = (grid[0]*threads[0], grid[1]*threads[1], grid[2]*threads[2])
        local_size = threads
        time = []
        for _ in range(self.iterations):
            event = func(self.queue, global_size, local_size, *gpu_args)
            event.wait()
            time.append((event.profile.end - event.profile.start)*1e-6)
        time = sorted(time)
        if times:
            return time
        else:
            if self.iterations > 4:
                return numpy.mean(time[1:-1])
            else:
                return numpy.mean(time)
runs the kernel and measures time repeatedly, returns average time

        Runs the kernel and measures kernel execution time repeatedly, number of
        iterations is set during the creation of OpenCLFunctions. Benchmark returns
        a robust average, from all measurements the fastest and slowest runs are
        discarded and the rest is included in the returned average. The reason for
        this is to be robust against initialization artifacts and other exceptional
        cases.

        :param func: A PyOpenCL kernel compiled for this specific kernel configuration
        :type func: pyopencl.Kernel

        :param gpu_args: A list of arguments to the kernel, order should match the
            order in the code. Allowed values are either variables in global memory
            or single values passed by value.
        :type gpu_args: list( pyopencl.Buffer, numpy.int32, ...)

        :param threads: A tuple listing the number of work items in each dimension of
            the work group.
        :type threads: tuple(int, int, int)

        :param grid: A tuple listing the number of work groups in each dimension
            of the NDRange.
        :type grid: tuple(int, int)

        :param times: Return the execution time of all iterations.
        :type times: bool

        :returns: All execution times, if times=True, or a robust average for the
            kernel execution time.
        :rtype: float