StencilStream v3.0.0
SYCL-based Stencil Simulation Framework Targeting FPGAs
Loading...
Searching...
No Matches
Grid.hpp
Go to the documentation of this file.
1/*
2 * Copyright © 2020-2024 Jan-Oliver Opdenhövel, Paderborn Center for Parallel Computing, Paderborn
3 * University
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
6 * associated documentation files (the “Software”), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
8 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in all copies or
12 * substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
15 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
17 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 */
20#pragma once
21#include "../AccessorSubscript.hpp"
22#include "../Concepts.hpp"
23#include "../GenericID.hpp"
24#include <memory>
25#include <numeric>
26#include <vector>
27
28namespace stencil {
29namespace tiling {
30
72template <typename Cell, uindex_t tile_width = 1024, uindex_t tile_height = 1024,
73 uindex_t halo_radius = 1>
74class Grid {
75 static_assert(2 * halo_radius < tile_height && 2 * halo_radius < tile_width);
76
77 public:
83 static constexpr uindex_t dimensions = 2;
84
92 Grid(uindex_t grid_width, uindex_t grid_height)
93 : grid_buffer(sycl::range<2>(grid_width, grid_height)) {}
94
101 Grid(sycl::range<2> range) : grid_buffer(range) {}
102
111 Grid(sycl::buffer<Cell, 2> input_buffer) : grid_buffer(input_buffer.get_range()) {
112 copy_from_buffer(input_buffer);
113 }
114
124 Grid(Grid const &other_grid) : grid_buffer(other_grid.grid_buffer) {}
125
135 template <sycl::access::mode access_mode> class GridAccessor {
136 public:
141
145 GridAccessor(Grid &grid) : accessor(grid.grid_buffer) {}
146
151
160
167 Cell const &operator[](sycl::id<2> id)
168 requires(access_mode == sycl::access::mode::read)
169 {
170 return accessor[id];
171 }
172
179 Cell &operator[](sycl::id<2> id)
180 requires(access_mode != sycl::access::mode::read)
181 {
182 return accessor[id];
183 }
184
185 private:
186 sycl::host_accessor<Cell, 2, access_mode> accessor;
187 };
188
199 void copy_from_buffer(sycl::buffer<Cell, 2> input_buffer) {
200 if (input_buffer.get_range() != grid_buffer.get_range()) {
201 throw std::out_of_range("The target buffer has not the same size as the grid");
202 }
203
204 sycl::host_accessor grid_ac{grid_buffer, sycl::write_only};
205 sycl::host_accessor input_ac{input_buffer, sycl::read_only};
206 for (uindex_t c = 0; c < get_grid_width(); c++) {
207 for (uindex_t r = 0; r < get_grid_height(); r++) {
208 grid_ac[c][r] = input_ac[c][r];
209 }
210 }
211 }
212
222 void copy_to_buffer(sycl::buffer<Cell, 2> output_buffer) {
223 if (output_buffer.get_range() != grid_buffer.get_range()) {
224 throw std::out_of_range("The target buffer has not the same size as the grid");
225 }
226
227 sycl::host_accessor grid_ac{grid_buffer, sycl::read_only};
228 sycl::host_accessor output_ac{output_buffer, sycl::write_only};
229 for (uindex_t c = 0; c < get_grid_width(); c++) {
230 for (uindex_t r = 0; r < get_grid_height(); r++) {
231 output_ac[c][r] = grid_ac[c][r];
232 }
233 }
234 }
235
239 Grid make_similar() const { return Grid(grid_buffer.get_range()); }
240
244 uindex_t get_grid_width() const { return grid_buffer.get_range()[0]; }
245
249 uindex_t get_grid_height() const { return grid_buffer.get_range()[1]; }
250
261 return GenericID<uindex_t>(std::ceil(float(get_grid_width()) / float(tile_width)),
262 std::ceil(float(get_grid_height()) / float(tile_height)));
263 }
264
294 template <typename in_pipe>
295 sycl::event submit_read(sycl::queue &queue, uindex_t tile_c, uindex_t tile_r, Cell halo_value) {
296 if (tile_c >= get_tile_range().c || tile_r >= get_tile_range().r) {
297 throw std::out_of_range("Tile index out of range!");
298 }
299
300 constexpr uindex_t column_bits = 1 + std::bit_width(tile_width + halo_radius);
301 constexpr uindex_t row_bits = 1 + std::bit_width(tile_height + halo_radius);
302 using index_c_t = ac_int<column_bits, true>;
303 using index_r_t = ac_int<row_bits, true>;
304
305 return queue.submit([&](sycl::handler &cgh) {
306 sycl::accessor grid_ac{grid_buffer, cgh, sycl::read_only};
307 index_t grid_width = this->get_grid_width();
308 index_t grid_height = this->get_grid_height();
309
310 cgh.single_task([=]() {
311 index_t c_offset = tile_c * tile_width;
312 index_c_t start_tile_c = -halo_radius;
313 index_c_t end_tile_c =
314 index_c_t(std::min(grid_width - tile_c * tile_width, tile_width)) + halo_radius;
315
316 index_t r_offset = tile_r * tile_height;
317 index_r_t start_tile_r = -halo_radius;
318 index_r_t end_tile_r =
319 index_r_t(std::min(grid_height - tile_r * tile_height, tile_height)) +
320 halo_radius;
321
322 [[intel::loop_coalesce(2)]] for (index_c_t tile_c = start_tile_c;
323 tile_c < end_tile_c; tile_c++) {
324 for (index_r_t tile_r = start_tile_r; tile_r < end_tile_r; tile_r++) {
325 index_t c = c_offset + tile_c.to_long();
326 index_t r = r_offset + tile_r.to_long();
327
328 Cell value;
329 if (c >= 0 && r >= 0 && c < grid_width && r < grid_height) {
330 value = grid_ac[c][r];
331 } else {
332 value = halo_value;
333 }
334 in_pipe::write(value);
335 }
336 }
337 });
338 });
339 }
340
369 template <typename out_pipe>
370 sycl::event submit_write(sycl::queue queue, uindex_t tile_c, uindex_t tile_r) {
371 if (tile_c >= get_tile_range().c || tile_r >= get_tile_range().r) {
372 throw std::out_of_range("Tile index out of range!");
373 }
374
375 constexpr uindex_t column_bits = std::bit_width(tile_width);
376 constexpr uindex_t row_bits = std::bit_width(tile_height);
377 using uindex_c_t = ac_int<column_bits, false>;
378 using uindex_r_t = ac_int<row_bits, false>;
379
380 return queue.submit([&](sycl::handler &cgh) {
381 sycl::accessor grid_ac{grid_buffer, cgh, sycl::read_write};
382 uindex_t grid_width = this->get_grid_width();
383 uindex_t grid_height = this->get_grid_height();
384
385 cgh.single_task([=]() {
386 uindex_t c_offset = tile_c * tile_width;
387 uindex_c_t end_tile_c =
388 uindex_c_t(std::min(grid_width - tile_c * tile_width, tile_width));
389
390 uindex_t r_offset = tile_r * tile_height;
391 uindex_r_t end_tile_r =
392 uindex_r_t(std::min(grid_height - tile_r * tile_height, tile_height));
393
394 [[intel::loop_coalesce(2)]] for (uindex_c_t tile_c = 0; tile_c < end_tile_c;
395 tile_c++) {
396 for (uindex_r_t tile_r = 0; tile_r < end_tile_r; tile_r++) {
397 grid_ac[c_offset + tile_c.to_long()][r_offset + tile_r.to_long()] =
398 out_pipe::read();
399 }
400 }
401 });
402 });
403 }
404
405 private:
406 sycl::buffer<Cell, 2> grid_buffer;
407};
408
409} // namespace tiling
410} // namespace stencil
T value
Definition Helpers.hpp:0
A helper class to support the double-subscript idiom for GridAccessors.
Definition AccessorSubscript.hpp:49
A generic, two-dimensional index.
Definition GenericID.hpp:32
An accessor for the monotile grid.
Definition Grid.hpp:135
BaseSubscript operator[](uindex_t i)
Access/Dereference the first dimension.
Definition Grid.hpp:159
Cell & operator[](sycl::id< 2 > id)
Access a cell of the grid.
Definition Grid.hpp:179
Cell const & operator[](sycl::id< 2 > id)
Access a cell of the grid.
Definition Grid.hpp:167
AccessorSubscript< Cell, GridAccessor, access_mode > BaseSubscript
Shorthand for the used subscript type.
Definition Grid.hpp:150
static constexpr uindex_t dimensions
The number of dimensions of the underlying grid.
Definition Grid.hpp:140
GridAccessor(Grid &grid)
Create a new accessor to the given grid.
Definition Grid.hpp:145
A grid class for the tiling architecture.
Definition Grid.hpp:74
void copy_to_buffer(sycl::buffer< Cell, 2 > output_buffer)
Copy the contents of the grid into the SYCL buffer.
Definition Grid.hpp:222
static constexpr uindex_t dimensions
The number of dimensions of the grid.
Definition Grid.hpp:83
uindex_t get_grid_width() const
Return the width, or number of columns, of the grid.
Definition Grid.hpp:244
void copy_from_buffer(sycl::buffer< Cell, 2 > input_buffer)
Copy the contents of the SYCL buffer into the grid.
Definition Grid.hpp:199
GenericID< uindex_t > get_tile_range() const
Return the range of (central) tiles of the grid.
Definition Grid.hpp:260
sycl::event submit_write(sycl::queue queue, uindex_t tile_c, uindex_t tile_r)
Submit a kernel that receives cells from the pipe and writes them to the grid.
Definition Grid.hpp:370
sycl::event submit_read(sycl::queue &queue, uindex_t tile_c, uindex_t tile_r, Cell halo_value)
Submit a kernel that sends a tile of the grid into a pipe.
Definition Grid.hpp:295
Grid make_similar() const
Create an new, uninitialized grid with the same size as the current one.
Definition Grid.hpp:239
Grid(sycl::buffer< Cell, 2 > input_buffer)
Create a new grid with the same size and contents as the given SYCL buffer.
Definition Grid.hpp:111
Grid(uindex_t grid_width, uindex_t grid_height)
Create a new, uninitialized grid with the given dimensions.
Definition Grid.hpp:92
uindex_t get_grid_height() const
Return the height, or number of rows, of the grid.
Definition Grid.hpp:249
Grid(Grid const &other_grid)
Create a new reference to the given grid.
Definition Grid.hpp:124
Grid(sycl::range< 2 > range)
Create a new, uninitialized grid with the given dimensions.
Definition Grid.hpp:101
Definition AccessorSubscript.hpp:24
BOOST_PP_CAT(BOOST_PP_CAT(uint, STENCIL_INDEX_WIDTH), _t) uindex_t
An unsigned integer of configurable width.
Definition Index.hpp:42
BOOST_PP_CAT(BOOST_PP_CAT(int, STENCIL_INDEX_WIDTH), _t) index_t
A signed integer of configurable width.
Definition Index.hpp:56