### Example of using sycl::gpu_selector_v Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/device-selector.rst This example demonstrates how to use `sycl::gpu_selector_v` to select a GPU device. It includes error handling for cases where no GPU is found. ```cpp #include #include int main() { try { // Construct a queue using the GPU selector sycl::queue q(sycl::gpu_selector_v, [](sycl::exception_list exceptions) { for (auto const& e : exceptions) { std::rethrow_exception(e); } }); std::cout << "Selected device: " << q.get_device().get_info>().name() << std::endl; } catch (sycl::exception const& e) { // Handle exceptions, e.g., if no GPU is found std::cerr << "SYCL exception caught: " << e.what() << std::endl; return 1; } return 0; } ``` -------------------------------- ### Enumerate SYCL Platforms and Devices Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/platform.rst This C++ snippet shows how to get a list of available SYCL platforms and then iterate through the devices on each platform. Ensure SYCL runtime is installed and accessible. ```cpp #include #include #include int main() { try { std::vector platforms; platforms = sycl::platform::get_platforms(); if (platforms.empty()) { std::cout << "No SYCL platforms found." << std::endl; return 1; } for (const auto& p : platforms) { std::cout << "Platform: " << p.get_info() << std::endl; std::vector devices = p.get_devices(); if (devices.empty()) { std::cout << " No devices found on this platform." << std::endl; } else { for (const auto& d : devices) { std::cout << " Device: " << d.get_info() << std::endl; } } } } catch (sycl::exception const& e) { std::cerr << "SYCL exception caught: " << e.what() << std::endl; return 1; } return 0; } ``` -------------------------------- ### Example: Work-group reduce using group algorithms library Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/group-algorithms-library.rst This example demonstrates how to use the group algorithms library to perform a work-group reduce operation. It includes both the C++ code and its corresponding output. ```cpp #include #include #include #include int main() { std::vector v(100); std::fill(v.begin(), v.end(), 1); sycl::queue q; sycl::buffer buf(v.data(), sycl::range<1>(v.size())); q.submit([&](sycl::handler &cgh) { auto acc = buf.get_access(cgh); auto group_size = sycl::uniform_group_size(100, q.get_device()); sycl::range<1> item_range{group_size}; cgh.parallel_for(item_range, [=](sycl::item<1> item) { auto group = item.get_group(); auto id = item.get_id(); auto reduce_result = sycl::reduce_over_group( group, acc[id], 0, std::plus()); if (id.get(0) == 0) { acc[id] = reduce_result; } }); }); q.wait_and_throw(); auto host_acc = buf.get_access(); std::cout << "Reduce result: " << host_acc[0] << std::endl; return 0; } ``` ```output Reduce result: 100 ``` -------------------------------- ### Example: Convolution with Specialization Constants Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/specialization-constants.rst This example demonstrates using specialization constants to set coefficient values for a convolution operation within a SYCL kernel. ```cpp #include #include #include // Define specialization constants namespace { auto kernel_tile_size = sycl::ext::oneapi::experimental::property::value< class kernel_tile_size_tag, int>(16); auto kernel_iterations = sycl::ext::oneapi::experimental::property::value< class kernel_iterations_tag, int>(10); } // Kernel function void convolution_kernel( sycl::handler& cgh, const std::vector& input, std::vector& output, int width, int height, const std::vector& kernel_weights) { // Set specialization constants for the command group cgh.set_specialization_constant(32); cgh.set_specialization_constant(20); auto in_buf = sycl::buffer(input.data(), sycl::range<1>(width * height)); auto out_buf = sycl::buffer(output.data(), sycl::range<1>(width * height)); auto kernel_weights_buf = sycl::buffer(kernel_weights.data(), sycl::range<1>(9)); cgh.parallel_for(sycl::range<2>(height, width), [=](sycl::item<2> item) { // Get specialization constants within the kernel auto tile_size = sycl::get_specialization_constant(); auto iterations = sycl::get_specialization_constant(); int r = item.get_id(0); int c = item.get_id(1); float sum = 0.0f; // Simplified convolution logic using specialization constants for (int i = 0; i < tile_size; ++i) { for (int j = 0; j < iterations; ++j) { // Accessing input, output, and kernel_weights using buffers // ... (actual convolution calculation would go here) } } // Store result out_buf.get_access( sycl::range<1>(width * height))[r * width + c] = sum; }); } int main() { // Example usage: std::vector input_data(100 * 100); std::vector output_data(100 * 100); std::vector kernel_weights = { -1, -1, -1, -1, 8, -1, -1, -1, -1 }; // Example weights // Initialize input data for (size_t i = 0; i < input_data.size(); ++i) { input_data[i] = static_cast(i % 10); } try { sycl::queue q; sycl::buffer input_buf(input_data.data(), sycl::range<1>(input_data.size())); sycl::buffer output_buf(output_data.data(), sycl::range<1>(output_data.size())); sycl::buffer kernel_weights_buf(kernel_weights.data(), sycl::range<1>(kernel_weights.size())); q.submit([&](sycl::handler& cgh) { convolution_kernel(cgh, input_data, output_data, 100, 100, kernel_weights); }); q.wait_and_throw(); // Output results or verify std::cout << "Convolution completed successfully." << std::endl; } catch (sycl::exception const& e) { std::cerr << "SYCL exception caught: " << e.what() << std::endl; return -1; } return 0; } ``` -------------------------------- ### SYCL Kernel Submission Examples Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/queue.rst Examples demonstrating the submission of single-task and parallel SYCL kernel functions. ```APIDOC ## Example 1: Single Task Kernel Submission ### Description Submission of a single task SYCL kernel function. ### Code ```cpp // /examples/queue-single-task.cpp // ... (code omitted for brevity) ``` ### Output ``` // /examples/queue-single-task.out // ... (output omitted for brevity) ``` ## Example 2: Parallel Kernel Submission ### Description Submission of a parallel SYCL kernel function. ### Code ```cpp // /examples/queue-parallel.cpp // ... (code omitted for brevity) ``` ### Output ``` // /examples/queue-parallel.out // ... (output omitted for brevity) ``` ``` -------------------------------- ### Example Output for sycl::private_memory Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/private_memory.rst Example output from the sycl::private_memory usage demonstration. It shows the private data values printed for the first work-item of each work-group. ```text Work-group 0: Private data value = 0 Work-group 1: Private data value = 20 Work-group 0: Private data value = 40 Work-group 1: Private data value = 60 ``` -------------------------------- ### Thread-safe push/pop using atomic operations Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/atomic_ref.rst Example demonstrating thread-safe push and pop operations using SYCL atomic operations. This example requires a device supporting `sycl::aspect::atomic64`. ```cpp #include #include #include #include // Define a simple thread-safe queue using atomic operations template class atomic_queue { std::vector data; sycl::atomic_ref head; sycl::atomic_ref tail; public: atomic_queue(size_t capacity) : data(capacity), head(0), tail(0) {} bool push(const T& value) { size_t current_tail = tail.load(); if (current_tail < data.size()) { data[current_tail] = value; tail.store(current_tail + 1); return true; } return false; // Queue is full } bool pop(T& value) { size_t current_head = head.load(); if (current_head < tail.load()) { value = data[current_head]; head.fetch_add(1); return true; } return false; // Queue is empty } }; int main() { // Ensure the device supports atomic64 operations sycl::queue q; if (!q.get_device().has(sycl::aspect::atomic64)) { std::cerr << "Device does not support atomic64 operations. Exiting." << std::endl; return 1; } const size_t queue_capacity = 100; atomic_queue aq(queue_capacity); // Example usage: push and pop operations std::vector threads; const int num_producers = 4; const int num_consumers = 4; const int items_per_producer = 25; // Producers for (int i = 0; i < num_producers; ++i) { threads.emplace_back([&aq, i, items_per_producer]() { for (int j = 0; j < items_per_producer; ++j) { int value = i * items_per_producer + j; while (!aq.push(value)) { // Spin wait if queue is full std::this_thread::yield(); } // std::cout << "Pushed: " << value << std::endl; } }); } // Consumers std::atomic consumed_count = 0; for (int i = 0; i < num_consumers; ++i) { threads.emplace_back([&aq, &consumed_count, items_per_producer, num_producers]() { int value; while (consumed_count.load() < num_producers * items_per_producer) { if (aq.pop(value)) { consumed_count.fetch_add(1); // std::cout << "Popped: " << value << std::endl; } else { // Spin wait if queue is empty std::this_thread::yield(); } } }); } for (auto& t : threads) { t.join(); } std::cout << "All items produced and consumed." << std::endl; return 0; } ``` ```text All items produced and consumed. ``` -------------------------------- ### SYCL Queue Example Source: https://context7.com/khronosgroup/sycl_reference/llms.txt Demonstrates the creation and usage of a sycl::queue to submit a single task kernel. ```APIDOC ## sycl::queue The `sycl::queue` class connects a host program to a single device and is the primary interface for submitting work. Programs submit tasks to a device via the queue and can monitor the queue for completion. A queue can be created with device selectors, explicit devices, or contexts. ### Request Example ```cpp #include int main() { // Create queue with default device selector auto q = sycl::queue(sycl::default_selector_v); // Submit a single task kernel q.submit([&](sycl::handler &cgh) { auto os = sycl::stream{128, 128, cgh}; cgh.single_task([=] { os << "Hello World!\n"; }); }); q.wait(); // Block until all tasks complete } // Output: Hello World! ``` ``` -------------------------------- ### SYCL Buffer Example Source: https://context7.com/khronosgroup/sycl_reference/llms.txt Demonstrates the creation and usage of a `sycl::buffer` for managing shared data between host and device. ```APIDOC ## sycl::buffer The `sycl::buffer` class defines a shared array of one, two, or three dimensions that can be used by SYCL kernels. Buffers must be accessed using accessor classes and automatically manage data synchronization between host and device. ### Request Example ```cpp #include #include int main() { // Create 2-d buffer with 8x8 ints sycl::buffer parent_buffer{sycl::range<2>{8, 8}}; try { // Create sub-buffer from contiguous region of parent buffer sycl::buffer sub_buf{parent_buffer, /*offset*/ sycl::range<2>{2, 0}, /*size*/ sycl::range<2>{2, 8}}; std::cout << "sub_buf created successfully" << std::endl; } catch (const sycl::exception &e) { std::cerr << "Exception: " << e.what() << std::endl; } return 0; } // Output: sub_buf created successfully ``` ``` -------------------------------- ### Example Usage of sycl::private_memory Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/private_memory.rst Demonstrates the usage of sycl::private_memory to manage per-work-item data within a SYCL kernel. This example shows how to declare, initialize, and access private memory for each work-item. ```cpp #include #include // Define a simple struct to be used with private_memory struct MyData { int value; MyData() : value(0) {} MyData(int v) : value(v) {} }; int main() { // Define the device queue sycl::queue q; // Define the dimensions for the private memory constexpr int dimensions = 1; // Submit a kernel to the queue q.submit([&](sycl::handler& cgh) { // Declare private memory for MyData objects, 1 dimension sycl::private_memory private_data(sycl::range(1)); // Launch a parallel_for_work_group kernel cgh.parallel_for_work_group( sycl::range(4), // Total number of work-groups sycl::range(2), // Work-items per work-group [=](sycl::h_item idx) { // Access the private memory for the current work-item // Initialize the private data with a value based on the work-item ID private_data(idx).value = idx.get_global_id(0) * 10; // Synchronize within the work-group to ensure all private data is written before reading idx.barrier(); // Read the value from private memory int read_value = private_data(idx).value; // Print the value (only for the first work-item in each group for simplicity) if (idx.get_local_id(0) == 0) { std::cout << "Work-group " << idx.get_group_id(0) << ": Private data value = " << read_value << std::endl; } }); }); // Wait for the queue to finish q.wait_and_throw(); return 0; } ``` -------------------------------- ### Example: std::vector with USM Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/usm_allocations.rst Demonstrates the usage of std::vector with USM memory allocation. ```cpp #include #include int main() { sycl::queue q; std::vector> vec(q, 10); return 0; } ``` -------------------------------- ### Measure memcpy Elapsed Time Example Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/event.rst Demonstrates how to measure the elapsed time of a memcpy operation on a SYCL device using event profiling information. This example requires the event to have profiling information enabled. ```cpp #include #include #include int main() { // device and queue setup auto device = sycl::device::get_default(); auto context = sycl::context(device); // Use property::queue::enable_profiling to enable profiling auto q = sycl::queue(context, device, sycl::property::queue::enable_profiling()); // host data std::vector host_data(1024); std::iota(host_data.begin(), host_data.end(), 0); // device data auto device_data = sycl::malloc_shared(host_data.size(), device, context); // copy data to device sycl::event copy_event = q.memcpy(device_data, host_data.data(), host_data.size() * sizeof(int)); // wait for the copy to complete and get profiling info copy_event.wait(); // get profiling timestamps uint64_t start_time = copy_event.get_profiling_info(); uint64_t end_time = copy_event.get_profiling_info(); // calculate elapsed time in nanoseconds uint64_t elapsed_time = end_time - start_time; std::cout << "Elapsed time for memcpy: " << elapsed_time << " ns\n"; // cleanup sycl::free(device_data, context); return 0; } ``` -------------------------------- ### Get Kernel Bundle (with devices) Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/kernel-bundles.rst Obtain a kernel bundle compatible with specified devices. ```APIDOC ## sycl::get_kernel_bundle (devices) ### Description Returns a kernel bundle containing all kernels compatible with at least one of the specified devices. This overload does not include device built-in kernels. Specialization constants will have their default values. ### Method `template sycl::kernel_bundle get_kernel_bundle(const sycl::context& ctxt, const std::vector& devs)` ### Parameters * `ctxt` (sycl::context) - The SYCL context. * `devs` (std::vector) - A vector of devices for which the bundle should be compatible. ### Returns A kernel bundle in the specified `State` compatible with at least one device in `devs`. ### Throws * `sycl::exception` with `sycl::errc::invalid` if any device in `devs` is not part of `ctxt` or is not a descendent device of a device in `ctxt`. * `sycl::exception` with `sycl::errc::invalid` if the `devs` vector is empty. * `sycl::exception` with `sycl::errc::invalid` if `State` is `sycl::bundle_state::input` and any device in `devs` lacks `sycl::aspect::online_compiler`. * `sycl::exception` with `sycl::errc::invalid` if `State` is `sycl::bundle_state::object` and any device in `devs` lacks `sycl::aspect::online_linker`. * `sycl::exception` with `sycl::errc::build` if `State` is `sycl::bundle_state::object` or `sycl::bundle_state::executable`, and an online compile or link fails. ``` -------------------------------- ### Output on a system without a GPU Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/device-selector.rst This is the expected output when the `gpu-selector.cpp` example is run on a system that does not have a SYCL-compatible GPU. ```text SYCL exception caught: runtime_error. Code: -115 (CL_DEVICE_NOT_FOUND). Please check your SYCL environment setup. ``` -------------------------------- ### SYCL Queue Parallel For Example Source: https://context7.com/khronosgroup/sycl_reference/llms.txt Illustrates the use of `sycl::queue::parallel_for` to execute a SYCL kernel in parallel over an N-dimensional index space. ```APIDOC ## sycl::queue::parallel_for The `parallel_for` member function invokes a SYCL kernel function to execute in parallel over an N-dimensional index space. It supports various parameter combinations including ranges, nd_ranges, and can work with reduction variables. ### Request Example ```cpp #include #include constexpr int count = 10; int main() { int data[count] = {0}; // Initialize to zeros auto q = sycl::queue(sycl::default_selector_v); { sycl::buffer data_buffer(data, sycl::range<1>(count)); q.submit([&](sycl::handler &cgh) { sycl::accessor data_accessor{data_buffer, cgh}; cgh.parallel_for(sycl::range<1>(count), [=](sycl::item<1> item) { auto index = item.get_id(0); data_accessor[index] += 5; }); }); q.wait(); } for (auto e : data) std::cout << e << " "; std::cout << std::endl; } // Output: 5 5 5 5 5 5 5 5 5 5 ``` ``` -------------------------------- ### SYCL Accessor Example Source: https://context7.com/khronosgroup/sycl_reference/llms.txt Shows how to use `sycl::accessor` to access and modify data within a SYCL buffer from within a kernel. ```APIDOC ## sycl::accessor The `sycl::accessor` class provides access to data in a buffer from within a SYCL kernel function or host task. Accessors define the access mode (read, write, read_write) and target (device, host_task) for buffer data. ### Request Example ```cpp #include #include int main() { const int N = 10; int data[N]; sycl::queue q; { sycl::buffer buf(data, sycl::range<1>(N)); q.submit([&](sycl::handler &cgh) { // Create accessor with read_write mode for device sycl::accessor acc{buf, cgh, sycl::read_write}; cgh.parallel_for(sycl::range<1>(N), [=](sycl::id<1> idx) { acc[idx] = idx[0] * 2; // Write values using accessor }); }); q.wait(); // Host accessor blocks until device operations complete sycl::host_accessor host_acc{buf, sycl::read_only}; for (int i = 0; i < N; i++) { std::cout << host_acc[i] << " "; } } std::cout << std::endl; } // Output: 0 2 4 6 8 10 12 14 16 18 ``` ``` -------------------------------- ### Queue Get Backend Info Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/queue.rst Queries the sycl::queue for SYCL backend-specific information. ```APIDOC ## template typename Param::return_type get_backend_info() const; ### Description Queries this `sycl::queue` for SYCL backend-specific information requested by the template parameter `Param`. The type alias `Param::return_type` must be defined in accordance with the SYCL backend specification. Must throw an `sycl::exception` with the `sycl::errc::backend_mismatch` error code if the SYCL backend that corresponds with `Param` is different from the SYCL backend that is associated with this `sycl::queue`. ### Method `template typename Param::return_type` ### Endpoint N/A (Method of sycl::queue class) ### Parameters - **Param** (template type) - Specifies the type of backend-specific information to retrieve. ### Request Example N/A ### Response - **return_type** (Param::return_type) - The requested backend-specific information. ### Response Example N/A ``` -------------------------------- ### SYCL Parallel Kernel Submission Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/queue.rst Example demonstrating the submission of a parallel SYCL kernel function to a queue. ```cpp #include #include int main() { sycl::queue q; q.submit([](sycl::handler &h) { h.parallel_for(sycl::range<1>(1024), [=](sycl::id<1> idx) { // Kernel body }); }); q.wait(); return 0; } ``` -------------------------------- ### Example: Catching Asynchronous Exceptions Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/exception.rst Demonstrates how to catch asynchronous exceptions, specifically for incorrect range construction. ```APIDOC ## Example: Catching Asynchronous Exceptions ### Description This example shows how to catch asynchronous exceptions that might occur during SYCL operations, such as incorrect range construction. ### Code Example ```cpp // /examples/exception-handling.cpp // ... (lines 5-) ``` ### Output Example ``` // /examples/exception-handling.out // ... (lines 5-) ``` ``` -------------------------------- ### Get Multi Pointer (`get_multi_ptr`) Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/command-accessor.rst Returns a multi_ptr to the start of the accessor's underlying buffer. This function can only be called from within a command. ```APIDOC ## `get_multi_ptr` ### Description Returns a `multi_ptr` to the start of this accessor’s underlying buffer, even if this is a ranged accessor whose range does not start at the beginning of the buffer. The return value is unspecified if the accessor is empty. ### Template Parameters - **IsDecorated** (access::decorated) - Specifies if the pointer is decorated. ### Usage This function may only be called from within a command. ### Availability Available only when ``(AccessTarget == target::device)``. ``` -------------------------------- ### SYCL Buffer Properties Example Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/properties.rst Illustrates creating SYCL buffers with different properties and checking for specific properties like context binding. Ensure necessary SYCL includes and context are available. ```cpp { sycl::context myContext; std::vector> bufferList { sycl::buffer { ptr, rng }, sycl::buffer { ptr, rng, sycl::property::use_host_ptr {} }, sycl::buffer { ptr, rng, sycl::property::context_bound { myContext } } }; for (auto& buf : bufferList) { if (buf.has_property()) { auto prop = buf.get_property(); assert(myContext == prop.get_context()); } } } ``` -------------------------------- ### Get Device Accessor Multi-Pointer Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/command-accessor.rst Returns a multi_ptr to the start of this accessor’s underlying buffer. Available only when (AccessTarget == target::device). The return value is unspecified if the accessor is empty. This function may only be called from within a command. ```cpp template accessor_ptr get_multi_ptr() const noexcept ``` -------------------------------- ### Get Host Task Accessor Pointer Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/command-accessor.rst Returns a pointer to the start of this accessor’s underlying buffer. Available only when (AccessTarget == target::host_task). The return value is unspecified if the accessor is empty. This function may only be called from within a command. ```cpp template accessor_ptr get_host_ptr() const noexcept ``` -------------------------------- ### SYCL Device Selectors: GPU and Default Source: https://context7.com/khronosgroup/sycl_reference/llms.txt Shows how to use built-in SYCL device selectors (`gpu_selector_v`, `default_selector_v`) to choose a device for queue creation. Includes error handling for cases where a GPU might not be available. ```cpp #include int main() { try { // Try to create queue with GPU selector sycl::queue q(sycl::gpu_selector_v); std::cout << "Running on: " << q.get_device().get_info() << std::endl; } catch (sycl::exception const &e) { std::cout << "Cannot select a GPU: " << e.what() << std::endl; std::cout << "Using default selector instead." << std::endl; // Fall back to default selector sycl::queue q(sycl::default_selector_v); std::cout << "Running on: " << q.get_device().get_info() << std::endl; } } // Output: Running on: Intel(R) UHD Graphics [0x9a49] ``` -------------------------------- ### Print Devices in a SYCL Context Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/context.rst This C++ example demonstrates how to iterate through and print all devices associated with a given SYCL context. It utilizes the `sycl::context` and `sycl::device` classes. ```cpp #include #include #include int main() { std::vector devices; for (const auto &platform : sycl::platform::get_platforms()) { auto devices_on_platform = platform.get_devices(); devices.insert(devices.end(), devices_on_platform.begin(), devices_on_platform.end()); } sycl::context ctx(devices); std::cout << "Devices in context:" << std::endl; for (const auto &dev : ctx.get_devices()) { std::cout << " " << dev.get_info() << std::endl; } return 0; } ``` -------------------------------- ### Example: Implicit Data Movement with USM Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/usm_allocations.rst Illustrates implicit data movement between host and device using USM shared allocations. The runtime handles data availability without explicit programmer intervention. ```cpp #include #include int main() { sycl::queue q; // Host allocation int* hostArray = static_cast(sycl::malloc_host(sizeof(int) * 10, q)); // Shared allocation int* sharedArray = static_cast(sycl::malloc_shared(sizeof(int) * 10, q)); // Initialize host array for (int i = 0; i < 10; ++i) { hostArray[i] = i; } q.submit([&](sycl::handler& h) { h.parallel_for(sycl::range<1>(10), [=](sycl::id<1> i) { // Access shared array directly in kernel sharedArray[i] = hostArray[i] * 2; }); }); q.wait(); // sharedArray is now available on the host for (int i = 0; i < 10; ++i) { // std::cout << sharedArray[i] << " "; } // std::cout << std::endl; sycl::free(hostArray, q); sycl::free(sharedArray, q); return 0; } ``` -------------------------------- ### Install pre-commit hooks Source: https://github.com/khronosgroup/sycl_reference/blob/main/README.rst Install pre-commit hooks to automatically run checks as part of the Git commit process. This helps maintain code quality by catching issues early. ```bash pre-commit install ``` -------------------------------- ### SYCL Handler Copy Operation Example Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/command-group-handler.rst Demonstrates how to perform data copy operations using the sycl::handler::copy() member function. This example copies a portion of a std::vector to the device. ```cpp #include #include int main() { std::vector data(100); // Initialize data... sycl::queue q; sycl::buffer buf(data.data(), sycl::range<1>(data.size())); q.submit([&](sycl::handler& cgh) { auto acc = buf.get_access(cgh); // Copy half of the data to the device cgh.copy(data.data(), acc.get_pointer(), data.size() / 2); }); // Further operations or synchronization... return 0; } ``` -------------------------------- ### SYCL Queue Properties: Profiling and In-Order Source: https://context7.com/khronosgroup/sycl_reference/llms.txt Demonstrates creating a SYCL queue with specific properties, including `enable_profiling` and `in_order`. Shows how to check if a queue is in-order and performs basic operations on shared memory. ```cpp #include int main() { // Create queue with profiling and in-order execution sycl::property_list props{ sycl::property::queue::enable_profiling(), sycl::property::queue::in_order() }; sycl::queue q(sycl::default_selector_v, props); std::cout << "Queue is in-order: " << q.is_in_order() << std::endl; // In-order queues execute commands sequentially int *data = sycl::malloc_shared(10, q); auto e1 = q.fill(data, 0, 10); // No need to specify dependency auto e2 = q.parallel_for(10, [=](sycl::id<1> i) { data[i] += 5; }); q.wait(); std::cout << "First element: " << data[0] << std::endl; sycl::free(data, q); } // Output: // Queue is in-order: 1 // First element: 5 ``` -------------------------------- ### Example: Implement and Use SYCL Async Handler Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/async_handler.rst Demonstrates how to implement an `sycl::async_handler` using a lambda function and pass it to a SYCL queue constructor. This handler will be invoked when asynchronous errors occur. ```cpp #include #include int main() { // Define an asynchronous error handler using a lambda function sycl::async_handler asyncHandler = [](sycl::exception_list exceptions) { std::cerr << "Asynchronous error occurred:" << std::endl; for (const auto& exc : exceptions) { try { std::rethrow_exception(exc); } catch (const sycl::exception& e) { std::cerr << " SYCL exception: " << e.what() << std::endl; } catch (const std::exception& e) { std::cerr << " Standard exception: " << e.what() << std::endl; } catch (...) { std::cerr << " Unknown exception" << std::endl; } } }; // Create a SYCL queue with the asynchronous handler // Replace "gpu" with your desired SYCL device selector if needed sycl::queue q(asyncHandler, "gpu"); // Example of submitting a task that might cause an error // (This is a placeholder; actual error generation depends on the operation) q.submit([&](sycl::handler& cgh) { // In a real scenario, operations here could lead to asynchronous errors // For demonstration, we'll assume an error might be triggered later or by runtime }); // The handler will be invoked if errors occur and are not consumed by wait_and_throw // or other explicit error handling mechanisms before the queue is destroyed. // For explicit testing, one might use q.throw_asynchronous() or simulate an error. std::cout << "Queue created with async handler. Program finished." << " (Check for async errors if any occurred during execution)" << std::endl; return 0; } ``` -------------------------------- ### SYCL Error Handling: Async Handler Source: https://context7.com/khronosgroup/sycl_reference/llms.txt Provides an example of setting up an asynchronous error handler for SYCL exceptions. It demonstrates how to catch and report asynchronous errors using `sycl::exception_list` and `wait_and_throw`. ```cpp #include #include int main() { // Define async handler for asynchronous errors auto async_handler = [](sycl::exception_list exceptions) { for (std::exception_ptr const &e : exceptions) { try { std::rethrow_exception(e); } catch (sycl::exception const &ex) { std::cerr << "Async SYCL exception: " << ex.what() << std::endl; } } }; try { sycl::queue q(sycl::default_selector_v, async_handler); q.submit([&](sycl::handler &cgh) { cgh.single_task([]() { // Kernel code }); }); // wait_and_throw reports both sync and async errors q.wait_and_throw(); std::cout << "Kernel executed successfully" << std::endl; } catch (sycl::exception const &e) { std::cerr << "SYCL exception: " << e.what() << std::endl; return 1; } return 0; } // Output: Kernel executed successfully ``` -------------------------------- ### Setting and Getting Specialization Constants via sycl::handler Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/specialization-constants.rst Allows setting and getting specialization constant values from command group scope using the `sycl::handler` class when not utilizing `sycl::kernel_bundle`. ```APIDOC ## `sycl::set_specialization_constant` ### Description Sets the value of a specialization constant for the current command group. If the value was previously set in the same command group, it is overwritten. This function can be called even if the constant is not used by the kernel, with no effect. ### Method `template void set_specialization_constant( typename std::remove_reference_t::value_type value );` ### Endpoint N/A (Host-side function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```cpp // Assuming 'my_spec_constant' is a specialization_id handler.set_specialization_constant(42); ``` ### Response #### Success Response (200) None (void function) #### Response Example N/A ### Throws `sycl::exception` with `sycl::errc::invalid` if a kernel bundle is bound to the handler. ## `sycl::get_specialization_constant` (handler) ### Description Retrieves the value of a specialization constant for the current command group. Returns the set value if previously set in this command group, otherwise returns the default value. ### Method `template typename std::remove_reference_t::value_type get_specialization_constant();` ### Endpoint N/A (Host-side function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```cpp // Assuming 'my_spec_constant' is a specialization_id auto value = handler.get_specialization_constant(); ``` ### Response #### Success Response (200) - **value** (type of SpecName::value_type) - The current value of the specialization constant. #### Response Example ```json { "value": 42 } ``` ### Throws `sycl::exception` with `sycl::errc::invalid` if a kernel bundle is bound to the handler. ``` -------------------------------- ### SYCL Device Partitioning Parameters and Exceptions Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/device.rst Details the parameters used for device partitioning and the exceptions that can be thrown. ```APIDOC ## SYCL Device Partitioning Parameters and Exceptions ### Template Parameters * **`Prop`**: See `sycl::info::partition_property`. ### Parameters * **`count`** (integer) - Number of compute units per sub-device. * **`counts`** (vector of integers) - Vector with the number of compute units for each sub-device. * **`domain`** (enum) - See `sycl::info::partition_affinity_domain`. ### Exceptions * **`sycl::errc::feature_not_supported`**: Thrown if the SYCL device does not support the `sycl::info::partition_property` specified by the `Prop` template argument. * **`sycl::errc::invalid`**: Thrown in the following cases: * If the `count` parameter is greater than the number of compute units in the device (`sycl::info::device::max_compute_units`). * If the sum of the values in the `counts` vector is greater than the number of compute units in the device (`sycl::info::device::max_compute_units`). * If the number of non-zero elements in the `counts` vector is greater than the maximum number of sub-devices for the device (`sycl::info::device::partition_max_sub_devices`). ``` -------------------------------- ### get_group_linear_id Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/group.rst Gets a linearized version of the work-group ID. ```APIDOC ## get_group_linear_id ### Description Get a linearized version of the work-group id. Calculating a linear work-group id from a multi-dimensional index follows |SYCL_SPEC_LINEARIZATION|. ### Method - size_t get_group_linear_id() const; ``` -------------------------------- ### SYCL single_task() and host_task() Example Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/command-group-handler.rst Illustrates the usage of the sycl::handler::single_task() member function for executing a single task on the device. It also shows the integration with sycl::handler::host_task(). ```cpp #include int main() { sycl::queue q; q.single_task([](){ // Kernel code here }); q.host_task([](){ // Host code here }); return 0; } ``` -------------------------------- ### Get Buffer Allocator Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/buffer.rst Returns the allocator that was provided to the buffer during its construction. ```cpp AllocatorT get_allocator() const ``` -------------------------------- ### Accessor Get Range Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/command-accessor.rst Retrieves the range of elements accessible by the accessor. ```APIDOC ## get_range() ### Description Available only when ``(Dimensions > 0)``. Returns a ``sycl::range`` object which represents the number of elements of ``DataT`` per dimension that this accessor may access. For a buffer accessor this is the range of the underlying buffer, unless it is a ranged accessor in which case it is the range that was specified when the accessor was constructed. ### Method `const` ### Endpoint `accessor::get_range()` ``` -------------------------------- ### Get Raw Undecorated Pointer Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/address-space.rst Returns the underlying pointer, always undecorated. ```cpp std::add_pointer_t get_raw() const; ``` -------------------------------- ### Queue Get Info Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/queue.rst Queries the sycl::queue for information requested by a template parameter. ```APIDOC ## template typename Param::return_type get_info() const; ### Description Queries this `sycl::queue` for information requested by the template parameter `Param`. The type alias `Param::return_type` must be defined in accordance with the info parameters in `sycl::info::queue` to facilitate returning the type associated with the `Param` parameter. ### Method `template typename Param::return_type` ### Endpoint N/A (Method of sycl::queue class) ### Parameters - **Param** (template type) - Specifies the type of information to retrieve. ### Request Example N/A ### Response - **return_type** (Param::return_type) - The requested information. ### Response Example N/A ``` -------------------------------- ### Get All Kernel IDs Source: https://github.com/khronosgroup/sycl_reference/blob/main/source/iface/kernel-bundles.rst Retrieve identifiers for all kernels defined within the SYCL application. ```APIDOC ## sycl::get_kernel_ids ### Description Returns a vector containing the identifiers for all kernels defined in the SYCL application. This does not include identifiers for any device built-in kernels. ### Method `std::vector get_kernel_ids()` ### Returns A vector with the identifiers for all kernels defined in the SYCL application. ```