Memory Operations
After allocating buffers, the next step is moving or initializing data inside them.
One of the most commonly used memory operations is the copy operation, which copies data from one buffer to another.
All memory operations support any dimension >=1.
alpaka::onHost::memcpy()always works with the entire buffer unless you specify the extent. The extent defines the number of elements, not the size in bytes.// copy the data to the host to the device onHost::memcpy(asyncComputeQueue, hostBuffer, computeBuffer);
The next snippet copies only the first four elements.
onHost::memcpy(asyncComputeQueue, hostBuffer, computeBuffer, Vec{4u});
You can also set all values of a buffer to a specific value using
alpaka::onHost::fill().onHost::fill(asyncComputeQueue, computeBuffer, 42);
With
alpaka::onHost::memset(), all bytes of a buffer can be set to a specific byte value. This is typically used to set all bytes to zero. Attention: The optional extent still defines the number of elements and not the size in bytes.onHost::memset(hostQueue, hostBuffer, 0);
The
value_typeisint, and we want to set the bytes of the first four elements to 0. On x86_64, aninthas the size of 4 bytes. So in the example, the first 16 bytes of the buffer are set to 0.// the value type of the buffer is int, which has size of 4 bytes on an x86_64 architecture static_assert(std::same_as<typename ALPAKA_TYPEOF(hostBuffer)::value_type, int>); onHost::memset(hostQueue, hostBuffer, 0, Vec{4u});
alpaka also supports
std::vectorfor memory operations; during the call, a view to the vector data is created automatically.// use std::vector instead of an alpaka view std::vector stdVec = std::vector<int>(10, 0); onHost::fill(asyncComputeQueue, computeBuffer, 42); onHost::memcpy(asyncComputeQueue, stdVec, computeBuffer);
Complete Source File
041_memoryOperations.cpp
1/* Copyright 2025 René Widera
2 * SPDX-License-Identifier: ISC
3 */
4
5#include "docsTest.hpp"
6
7#include <alpaka/alpaka.hpp>
8
9#include <catch2/catch_template_test_macros.hpp>
10#include <catch2/catch_test_macros.hpp>
11
12#include <vector>
13
14using namespace alpaka;
15
16TEMPLATE_LIST_TEST_CASE("memory", "[docs]", docs::test::TestBackends)
17{
18 auto computeDevSelector = alpaka::onHost::makeDeviceSelector(TestType::makeDict());
19 if(!computeDevSelector.isAvailable())
20 return;
21
22 // using the typed interface and not concept + auto
23 onHost::Device computeDev = computeDevSelector.makeDevice(0);
24 onHost::Queue asyncComputeQueue = computeDev.makeQueue();
25
26 onHost::Queue hostQueue = onHost::makeHostDevice().makeQueue();
27
28 // Allocate a memory view on the compute device.
29 // The memory will be freed automatically when the view goes out of scope.
30 onHost::SharedBuffer computeBuffer = onHost::alloc<int>(computeDev, 10);
31 // Derive the properties except the location.
32 onHost::SharedBuffer hostBuffer = onHost::allocHostLike(computeBuffer);
33
34 // To operate on host memory views, we need a host queue. Sett all bytes to zero.
35 onHost::memset(hostQueue, hostBuffer, 0);
36 onHost::wait(hostQueue);
37
38 // Both memory views are not filled with valid data yet, so let us assign a value to each element and copy it to
39 // the host. note: currently you cannot use a compute queue of a GPU device to fill a host memory view. @todo add
40 // host task execution to any compute queue
41 onHost::fill(asyncComputeQueue, computeBuffer, 42);
42
43 // copy the data to the host to the device
44 onHost::memcpy(asyncComputeQueue, hostBuffer, computeBuffer);
45
46 // wait because all previous operations are asynchronous
47 onHost::wait(asyncComputeQueue);
48
49 // check that the data is valid
50 for(auto const& v : hostBuffer)
51 CHECK(v == 42);
52
53 onHost::memset(hostQueue, hostBuffer, 0);
54 onHost::wait(hostQueue);
55
56 onHost::memcpy(asyncComputeQueue, hostBuffer, computeBuffer, Vec{4u});
57 onHost::wait(asyncComputeQueue);
58
59 CHECK(hostBuffer[0] == 42);
60 CHECK(hostBuffer[1] == 42);
61 CHECK(hostBuffer[2] == 42);
62 CHECK(hostBuffer[3] == 42);
63 CHECK(hostBuffer[4] == 0);
64 CHECK(hostBuffer[5] == 0);
65
66 onHost::fill(hostQueue, hostBuffer, 42);
67 onHost::wait(hostQueue);
68
69 // the value type of the buffer is int, which has size of 4 bytes on an x86_64 architecture
70 static_assert(std::same_as<typename ALPAKA_TYPEOF(hostBuffer)::value_type, int>);
71 onHost::memset(hostQueue, hostBuffer, 0, Vec{4u});
72 onHost::wait(hostQueue);
73
74 CHECK(hostBuffer[0] == 0);
75 CHECK(hostBuffer[1] == 0);
76 CHECK(hostBuffer[2] == 0);
77 CHECK(hostBuffer[3] == 0);
78 CHECK(hostBuffer[4] == 42);
79 CHECK(hostBuffer[5] == 42);
80}
81
82TEMPLATE_LIST_TEST_CASE("memory using std::vector", "[docs]", docs::test::TestBackends)
83{
84 auto computeDevSpec = alpaka::onHost::DeviceSpec{TestType::makeDict()};
85 auto computeDevSelector = alpaka::onHost::makeDeviceSelector(computeDevSpec);
86 if(!computeDevSelector.isAvailable())
87 return;
88
89 onHost::Device computeDev = computeDevSelector.makeDevice(0);
90 onHost::Queue asyncComputeQueue = computeDev.makeQueue();
91
92 onHost::SharedBuffer computeBuffer = onHost::alloc<int>(computeDev, 10);
93
94 // use std::vector instead of an alpaka view
95 std::vector stdVec = std::vector<int>(10, 0);
96
97 onHost::fill(asyncComputeQueue, computeBuffer, 42);
98 onHost::memcpy(asyncComputeQueue, stdVec, computeBuffer);
99 onHost::wait(asyncComputeQueue);
100
101 // check that the data is valid
102 for(auto const& v : stdVec)
103 CHECK(v == 42);
104}