From 9bb7f6debe8fa2b6f5521cf24273d14e880f09f5 Mon Sep 17 00:00:00 2001 From: Anton Oreskin Date: Tue, 22 Sep 2026 18:53:14 +0200 Subject: [PATCH] Avoid allocations in one-dimensional dispatch --- convenience_test.v | 34 ++++++++++++++++++++++++++++++++++ program.v | 37 +++++++++++++++++++++++++++++++++++-- 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/convenience_test.v b/convenience_test.v index 6721b2f..179a342 100644 --- a/convenience_test.v +++ b/convenience_test.v @@ -23,6 +23,40 @@ fn test_generated_error_name_covers_full_core_range() { assert cl.error_code_name(cl.invalid_event_wait_list) == 'invalid_event_wait_list' } +fn test_enqueue_1d_after_validates_handles_and_global_size_before_opencl_call() { + mut kernel_storage := u8(0) + mut queue_storage := u8(0) + valid_kernel := cl.OwnedKernel{ + handle: cl.Kernel(&kernel_storage) + } + valid_queue := cl.OwnedCommandQueue{ + handle: cl.CommandQueue(&queue_storage) + } + closed_kernel := cl.OwnedKernel{} + closed_queue := cl.OwnedCommandQueue{} + + closed_kernel.enqueue_1d_after(&valid_queue, 1, 0, []) or { + assert err is cl.OpenCLError + if err is cl.OpenCLError { + assert err.status == cl.invalid_kernel + } + valid_kernel.enqueue_1d_after(&closed_queue, 1, 0, []) or { + assert err is cl.OpenCLError + if err is cl.OpenCLError { + assert err.status == cl.invalid_command_queue + } + valid_kernel.enqueue_1d_after(&valid_queue, 0, 0, []) or { + assert err is cl.OpenCLError + if err is cl.OpenCLError { + assert err.status == cl.invalid_global_work_size + } + return + } + } + } + assert false +} + fn test_typed_buffer_rejects_byte_size_overflow_before_opencl_call() { element_size := usize(sizeof(u64)) if usize(max_int) <= ~usize(0) / element_size { diff --git a/program.v b/program.v index 63c4b6a..6544881 100644 --- a/program.v +++ b/program.v @@ -181,8 +181,41 @@ pub fn (kernel &OwnedKernel) enqueue_1d(queue &OwnedCommandQueue, global_size us // returns an owned completion event. A local size of zero lets the runtime choose. pub fn (kernel &OwnedKernel) enqueue_1d_after(queue &OwnedCommandQueue, global_size usize, local_size usize, wait_events []Event) !OwnedEvent { - local_sizes := if local_size > 0 { [local_size] } else { []usize{} } - return kernel.enqueue_nd_after(queue, [global_size], local_sizes, wait_events) + if isnil(kernel.handle) { + return OpenCLError{ + operation: 'enqueue closed OpenCL kernel' + status: invalid_kernel + } + } + if isnil(queue.handle) { + return OpenCLError{ + operation: 'enqueue OpenCL kernel on closed queue' + status: invalid_command_queue + } + } + if global_size == 0 { + return OpenCLError{ + operation: 'enqueue OpenCL kernel with zero global size' + status: invalid_global_work_size + } + } + mut local_pointer := &usize(unsafe { nil }) + mut requested_local_size := local_size + if local_size > 0 { + local_pointer = &requested_local_size + } + mut wait_pointer := &Event(unsafe { nil }) + if wait_events.len > 0 { + wait_pointer = wait_events.data + } + mut event := Event(unsafe { nil }) + mut no_global_offset := &usize(unsafe { nil }) + check(enqueue_nd_range_kernel(queue.handle, kernel.handle, 1, no_global_offset, &global_size, + local_pointer, u32(wait_events.len), wait_pointer, &event), + 'enqueue OpenCL kernel with event')! + return OwnedEvent{ + handle: event + } } // enqueue_nd_after submits a one-, two-, or three-dimensional kernel after