From 17d7cb4030ecafd52139c45b91d2f13c3085b15c Mon Sep 17 00:00:00 2001 From: PetroBondar Date: Thu, 16 Nov 2023 14:54:19 +0200 Subject: [PATCH 1/4] Updating DA Host alloc and mem sharing 1 Issue: KHRGA-80 --- source/iface/host-allocation.rst | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/source/iface/host-allocation.rst b/source/iface/host-allocation.rst index d897d5bf..12b773a8 100644 --- a/source/iface/host-allocation.rst +++ b/source/iface/host-allocation.rst @@ -2,6 +2,32 @@ Copyright 2023 The Khronos Group Inc. SPDX-License-Identifier: CC-BY-4.0 -**************** +*********************************** +Host allocations and memory sharing +*********************************** + +.. _host-allocations: + +================ Host allocations -**************** +================ + +A SYCL runtime may need to allocate temporary objects +on the host to handle some operations (such as copying +data from one context to another). +Allocation on the host is managed using an allocator +object, following the standard C++ allocator class +definition. + +The default allocator for memory objects is +implementation-defined, but the user can supply +their own allocator class by passing it as +template parameter. For exaple, this is how to provide +user-defined allocator class to :ref:`buffer`: + +:: + + sycl::buffer> b(d); + + + From c60280c09f485f713ba292df94e97882a76eb01a Mon Sep 17 00:00:00 2001 From: PetroBondar Date: Thu, 16 Nov 2023 15:31:46 +0200 Subject: [PATCH 2/4] Updating Host alloc and mem sharing 2 Issue: KHRGA-80 Comment: finished with Host alloc --- source/conf.py | 1 + source/iface/host-allocation.rst | 87 ++++++++++++++++++++++++++++---- source/spelling_wordlist.txt | 2 + 3 files changed, 81 insertions(+), 9 deletions(-) diff --git a/source/conf.py b/source/conf.py index c5b7d9d2..cb2c444f 100644 --- a/source/conf.py +++ b/source/conf.py @@ -148,6 +148,7 @@ def make_ref(ref_str, ref_view, ref_sufix): "#sec:multi-dim-subscript", ) + make_ref("SYCL_SPEC_BUFFER", "Section 4.7.2", "#subsec:buffers") + + make_ref("SYCL_SPEC_HOST_ALLOC", "Section 4.7.1", "#_host_allocation") + f""" .. _`SYCL Specification`: {sycl_ref_url} .. |true| replace:: ``true`` diff --git a/source/iface/host-allocation.rst b/source/iface/host-allocation.rst index 12b773a8..36748d24 100644 --- a/source/iface/host-allocation.rst +++ b/source/iface/host-allocation.rst @@ -12,22 +12,91 @@ Host allocations and memory sharing Host allocations ================ -A SYCL runtime may need to allocate temporary objects -on the host to handle some operations (such as copying +A SYCL runtime may need to allocate temporary objects +on the host to handle some operations (such as copying data from one context to another). -Allocation on the host is managed using an allocator -object, following the standard C++ allocator class + +Allocation on the host is managed using an allocator +object, following the standard C++ allocator class definition. -The default allocator for memory objects is -implementation-defined, but the user can supply -their own allocator class by passing it as -template parameter. For exaple, this is how to provide +The default allocator for memory objects is +implementation-defined, but the user can supply +their own allocator class by passing it as +template parameter. For example, this is how to provide user-defined allocator class to :ref:`buffer`: :: - sycl::buffer> b(d); + { + sycl::buffer> b(d); + } + +When an allocator returns a ``nullptr``, the runtime +cannot allocate data on the host. Note that in this case +the runtime will raise an error if it requires host memory +but it is not available (e.g when moving data across SYCL +backend contexts). + +In some cases, the implementation may retain a copy of +the allocator object even after the buffer is destroyed. +For example, this can happen when the buffer object is +destroyed before commands using accessors to the buffer +have completed. Therefore, the application must be +prepared for calls to the allocator even after the buffer +is destroyed. + +.. note:: + + If the application needs to know when the implementation + has destroyed all copies of the allocator, it can maintain + a reference count within the allocator. + +The definition of allocators extends the current functionality +of SYCL, ensuring that users can define allocator functions for +specific hardware or certain complex shared memory mechanisms, +and improves interoperability with STL-based libraries. + +.. seealso:: |SYCL_SPEC_HOST_ALLOC| + +Default allocators +================== + +A default allocator is always defined by the implementation. +For allocations greater than size zero, it is guaranteed to +return non-``nullptr`` and new memory positions every call. + +The default allocator for ``const`` buffers will remove the +constantness of the type (therefore, the default allocator +for a buffer of type ``const int`` will be an ``Allocator``). +This implies that host accessors will not synchronize with the +pointer given by the user in the :ref:`buffer`/:ref:`image ` +constructor, but will use the memory returned by the ``Allocator`` +itself for that purpose. + +The user can implement an allocator that returns the same address +as the one passed in the buffer constructor, but it is the +responsibility of the user to handle the potential race conditions. + +The list of SYCL default allocators: + +.. list-table:: + :header-rows: 1 + + * - Allocator + - Description + * - ``template sycl::buffer_allocator`` + - It is the default :ref:`buffer` allocator used by the runtime, + when no allocator is defined by the user. + + Meets the C++ named requirement Allocator. + A buffer of data type ``const T`` uses ``buffer_allocator`` + by default. + * - ``sycl::image_allocator`` + - It is the default allocator used by the runtime for the SYCL `unsampled_image` + and `sampled_image` classes when no allocator is provided by the user. + The ``sycl::image_allocator`` is required to allocate in elements of ``std::byte``. +.. TODO: Add references when images is complete diff --git a/source/spelling_wordlist.txt b/source/spelling_wordlist.txt index 642487c7..4c67c020 100644 --- a/source/spelling_wordlist.txt +++ b/source/spelling_wordlist.txt @@ -46,3 +46,5 @@ linearizes copyable mutex constantness +allocators +STL From a3a93641da2a13ce2d065556da71fb0e87b39d06 Mon Sep 17 00:00:00 2001 From: PetroBondar Date: Mon, 20 Nov 2023 15:35:14 +0200 Subject: [PATCH 3/4] Updating Host alloc and mem sharing 3 Issue: KHRGA-80 Comment: Finished with Memory sharing --- source/conf.py | 5 + source/iface/host-allocation.rst | 154 ++++++++++++++++++++++++++++++- 2 files changed, 156 insertions(+), 3 deletions(-) diff --git a/source/conf.py b/source/conf.py index 22c5afca..2dd63a50 100644 --- a/source/conf.py +++ b/source/conf.py @@ -202,6 +202,11 @@ def make_ref(ref_str, ref_view, ref_sufix): ) + make_ref("SYCL_SYNC_PRIMITIVES", "Section 4.7.5", "#subsec:mutex") + make_ref("SYCL_SPEC_HOST_ALLOC", "Section 4.7.1", "#_host_allocation") + + make_ref( + "SYCL_SPEC_HOST_MEM_SHARING", + "Section 4.7.4", + "#sec:sharing-host-memory-with-dm", + ) + f""" .. _`SYCL Specification`: {sycl_ref_url} .. |true| replace:: ``true`` diff --git a/source/iface/host-allocation.rst b/source/iface/host-allocation.rst index 36748d24..88768f7c 100644 --- a/source/iface/host-allocation.rst +++ b/source/iface/host-allocation.rst @@ -94,9 +94,157 @@ The list of SYCL default allocators: A buffer of data type ``const T`` uses ``buffer_allocator`` by default. * - ``sycl::image_allocator`` - - It is the default allocator used by the runtime for the SYCL `unsampled_image` - and `sampled_image` classes when no allocator is provided by the user. + - It is the default allocator used by the runtime for the SYCL :ref:`unsampled_image` + and :ref:`sampled_image` classes when no allocator is provided by the user. The ``sycl::image_allocator`` is required to allocate in elements of ``std::byte``. -.. TODO: Add references when images is complete + +.. _host_memory_sharing: + +========================================================= +Sharing host memory with the SYCL data management classes +========================================================= + +In order to allow the SYCL runtime to do memory management +and allow for data dependencies, there are :ref:`buffer` +and :ref:`image ` classes defined. + +The default behavior for them is that a “raw” pointer +is given during the construction of the data management +class, with full ownership to use it until the destruction +of the SYCL object. + +Below you can find details on sharing or explicitly not +sharing host memory with the SYCL data classes. The same +rules will apply to :ref:`images ` as well. + +.. seealso:: |SYCL_SPEC_HOST_MEM_SHARING| + + +Default behavior +================ + +When using a :ref:`buffer`, the ownership of the pointer +passed to the constructor of the class is, by default, +passed to SYCL runtime, and that pointer cannot be used +on the host side until the :ref:`buffer` or +:ref:`image ` is destroyed. + +A SYCL application can access the contents of the memory +managed by a SYCL buffer by using a :ref:`host_accessor` +as defined in. However, there is no guarantee that the +host accessor synchronizes with the original host +address used in its constructor. + +The pointer passed in is the one used to copy data back +to the host, if needed, before buffer destruction. +The memory pointed by host pointer will not be deallocated +by the runtime, and the data is copied back from the device +if there is a need for it. + + +SYCL ownership of the host memory +================================= + +In the case where there is host memory to be used for +initialization of data but there is no intention of using +that host memory after the :ref:`buffer` is destroyed, +then the :ref:`buffer` can take full ownership of that +host memory. + +When a :ref:`buffer` owns the host pointer there is no copy back, +by default. In this situation, the SYCL application may pass a +unique pointer to the host data, which will be then used by the +runtime internally to initialize the data in the device. + +For example, the following could be used: + +:: + + { + auto ptr = std::make_unique(-1234); + buffer b { std::move(ptr), range { 1 } }; + // ptr is not valid anymore. + // There is nowhere to copy data back + } + +However, optionally the ``sycl::buffer::set_final_data()`` can be +set to a ``std::weak_ptr`` to enable copying data back, to another +host memory address that is going to be valid after :ref:`buffer` +construction. + +:: + + { + auto ptr = std::make_unique(-42); + buffer b { std::move(ptr), range { 1 } }; + // ptr is not valid anymore. + // There is nowhere to copy data back. + // To get copy back, a location can be specified: + b.set_final_data(std::weak_ptr { .... }) + } + + +Shared SYCL ownership of the host memory +======================================== + +When an instance of ``std::shared_ptr`` is passed to the +:ref:`buffer` constructor, then the :ref:`buffer` object +and the developer's application share the memory region. + +Rules of shared ownership: + +1. If the ``std::shared_ptr`` is not empty, the contents of the + referenced memory are used to initialize the :ref:`buffer`. + + If the ``std::shared_ptr`` is empty, then the :ref:`buffer` + is created with uninitialized memory. + +2. If the ``std::shared_ptr`` is still used on the application's + side then the data will be copied back from the :ref:`buffer` + or :ref:`image ` and will be available to the + application after the :ref:`buffer` or + :ref:`image ` object is destroyed. + +3. When the :ref:`buffer` is destroyed and the data have + potentially been updated, if the number of copies of + the ``std::shared_ptr`` outside the runtime is 0, + there is no user-side shared pointer to read the data. + + Therefore the data is not copied out, and the :ref:`buffer` + destructor does not need to wait for the data processes + to be finished, as the outcome is not needed on the + application's side. + +Example of such behavior: + +:: + + { + std::shared_ptr ptr { data }; + { + buffer b { ptr, range<2>{ 10, 10 } }; + // update the data + [...] + } // Data is copied back because there is an user side shared_ptr + } + +:: + + { + std::shared_ptr ptr { data }; + { + buffer b { ptr, range<2>{ 10, 10 } }; + // update the data + [...] + ptr.reset(); + } // Data is not copied back, there is no user side shared_ptr. + } + +This behavior can be overridden using the +``sycl::buffer::set_final_data()`` member function of the +:ref:`buffer` class, which will by any means force the +:ref:`buffer` destructor to wait until the data is copied to +wherever the ``set_final_data()`` member function has put the +data (or not wait nor copy if set final data is ``nullptr``). From 8340543492127fd20d9e2be029d3f961420617e7 Mon Sep 17 00:00:00 2001 From: PetroBondar Date: Thu, 23 Nov 2023 13:43:56 +0200 Subject: [PATCH 4/4] Updating DA Host alloc and mem sharing PR comm fix Issue: KHRGA-80 --- source/iface/host-allocation.rst | 34 +++++++++++++++++--------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/source/iface/host-allocation.rst b/source/iface/host-allocation.rst index 88768f7c..b2961067 100644 --- a/source/iface/host-allocation.rst +++ b/source/iface/host-allocation.rst @@ -63,8 +63,9 @@ Default allocators ================== A default allocator is always defined by the implementation. -For allocations greater than size zero, it is guaranteed to -return non-``nullptr`` and new memory positions every call. +For allocations greater than size zero, when successful +it is guaranteed to return non-``nullptr`` and new memory +positions every call. The default allocator for ``const`` buffers will remove the constantness of the type (therefore, the default allocator @@ -110,14 +111,14 @@ In order to allow the SYCL runtime to do memory management and allow for data dependencies, there are :ref:`buffer` and :ref:`image ` classes defined. -The default behavior for them is that a “raw” pointer +The default behavior for them is that if a “raw” pointer is given during the construction of the data management -class, with full ownership to use it until the destruction -of the SYCL object. +class, then full ownership to use it is given to the SYCL +runtime until the destruction of the SYCL object. Below you can find details on sharing or explicitly not sharing host memory with the SYCL data classes. The same -rules will apply to :ref:`images ` as well. +rules apply to :ref:`images ` as well. .. seealso:: |SYCL_SPEC_HOST_MEM_SHARING| @@ -125,22 +126,23 @@ rules will apply to :ref:`images ` as well. Default behavior ================ -When using a :ref:`buffer`, the ownership of the pointer +When using a :ref:`buffer`, the ownership of a pointer passed to the constructor of the class is, by default, passed to SYCL runtime, and that pointer cannot be used on the host side until the :ref:`buffer` or :ref:`image ` is destroyed. A SYCL application can access the contents of the memory -managed by a SYCL buffer by using a :ref:`host_accessor` -as defined in. However, there is no guarantee that the +managed by a SYCL buffer by using a :ref:`host_accessor`. +However, there is no guarantee that the host accessor synchronizes with the original host address used in its constructor. The pointer passed in is the one used to copy data back to the host, if needed, before buffer destruction. -The memory pointed by host pointer will not be deallocated -by the runtime, and the data is copied back from the device +The memory pointed to by the host pointer will not be +deallocated by the runtime, and the data is copied back +from the device to the host through the host pointer if there is a need for it. @@ -154,8 +156,8 @@ then the :ref:`buffer` can take full ownership of that host memory. When a :ref:`buffer` owns the host pointer there is no copy back, -by default. In this situation, the SYCL application may pass a -unique pointer to the host data, which will be then used by the +by default. To create this situation, the SYCL application may pass +a unique pointer to the host data, which will be then used by the runtime internally to initialize the data in the device. For example, the following could be used: @@ -170,9 +172,9 @@ For example, the following could be used: } However, optionally the ``sycl::buffer::set_final_data()`` can be -set to a ``std::weak_ptr`` to enable copying data back, to another -host memory address that is going to be valid after :ref:`buffer` -construction. +set to an output iterator (including a “raw” pointer) or to a +``std::weak_ptr`` to enable copying data back, to another host memory +address that is going to be valid after :ref:`buffer` destruction. ::