Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
int_chains.hpp
Go to the documentation of this file.
1// -------------------------------------------------------//
2//
3// SHAMROCK code for hydrodynamics
4// Copyright (c) 2021-2026 Timothée David--Cléris <tim.shamrock@proton.me>
5// SPDX-License-Identifier: CeCILL Free Software License Agreement v2.1
6// Shamrock is licensed under the CeCILL 2.1 License, see LICENSE for more information
7//
8// -------------------------------------------------------//
9
10#pragma once
11
23
24#include "shambase/time.hpp"
27#include <type_traits>
28
29namespace sham::benchmarks {
30
32 enum class IntChainOp {
35 };
36
37// Both blocks issue the same number of ALU operations (32 per rotation), so the
38// rates they produce are directly comparable.
39#define IMAD_4(x, y) \
40 x = y * x + y; \
41 y = x * y + x; \
42 x = y * x + y; \
43 y = x * y + x;
44#define IMAD_16(x, y) \
45 IMAD_4(x, y); \
46 IMAD_4(x, y); \
47 IMAD_4(x, y); \
48 IMAD_4(x, y);
49
50#define IADD_4(x, y) \
51 x = y + x + y; \
52 y = x + y + x; \
53 x = y + x + y; \
54 y = x + y + x;
55#define IADD_16(x, y) \
56 IADD_4(x, y); \
57 IADD_4(x, y); \
58 IADD_4(x, y); \
59 IADD_4(x, y);
60
76 template<class T, IntChainOp op>
77 inline void int_chains(u32 i, int nrotation, T y0, T *__restrict in, T *__restrict out) {
78 static_assert(std::is_unsigned_v<T>, "int_chains requires an unsigned type");
79
80 T x = in[i];
81 T y = y0;
82 for (int j = 0; j < nrotation; j++) {
83 if constexpr (op == IntChainOp::Mul) {
84 IMAD_16(x, y);
85 } else {
86 IADD_16(x, y);
87 }
88 }
89 out[i] = y;
90 }
91
92#undef IMAD_4
93#undef IMAD_16
94#undef IADD_4
95#undef IADD_16
96
104
115 template<class T, IntChainOp op>
117 DeviceScheduler_ptr sched, int N, f64 time_threshold) {
118
119 sham::DeviceQueue &q = sched->get_queue();
120
121 sham::DeviceBuffer<T> x = {size_t(N), sched};
122 sham::DeviceBuffer<T> y = {size_t(N), sched};
123
124 const T x0 = T{3};
125 const T y0 = T{5};
126
127 x.fill(x0);
128 y.fill(y0);
129
130 sham::EventList depends_list;
131
132 auto x_ptr = x.get_write_access(depends_list);
133 auto y_ptr = y.get_write_access(depends_list);
134
135 depends_list.wait();
136
137 u32 nrotation = 8;
138 double sec = 0;
139
140 auto run_bench = [&q, &N, &x_ptr, &y_ptr, y0](u32 nrotation) -> f64 {
141 sham::EventList empty_list{};
142
144 t.start();
145 auto e = q.submit(empty_list, [=](sycl::handler &cgh) {
146 cgh.parallel_for(sycl::range<1>{size_t(N)}, [=](sycl::item<1> item) {
147 int_chains<T, op>(item.get_linear_id(), nrotation, y0, x_ptr, y_ptr);
148 });
149 });
150 e.wait();
151 t.stop();
152
153 return t.elapsed_sec();
154 };
155
156 // warmup kernel
157 run_bench(4);
158
159 double ref = run_bench(0);
160
161 for (;;) {
162
163 sec = run_bench(nrotation);
164
165 if (sec >= time_threshold || nrotation >= 256 * 256 * 4) {
166 break;
167 }
168
169 nrotation *= 2;
170 }
171
172 x.complete_event_state(sycl::event{});
173 y.complete_event_state(sycl::event{});
174
175 sec -= ref;
176
177 u64 op_per_thread = u64(nrotation) * 2_u64 * 16_u64;
178 double op_count = double(N) * double(op_per_thread);
179
180 return {
181 .func_name = SourceLocation{}.loc.function_name(),
182 .seconds = sec,
183 .iops = op_count / sec,
184 .nrotations = nrotation};
185 }
186
187} // namespace sham::benchmarks
double f64
Alias for double.
std::uint32_t u32
32 bit unsigned integer
std::uint64_t u64
64 bit unsigned integer
A buffer allocated in USM (Unified Shared Memory).
void complete_event_state(sycl::event e) const
Complete the event state of the buffer.
T * get_write_access(sham::EventList &depends_list, SourceLocation src_loc=SourceLocation{})
Get a read-write pointer to the buffer's data.
void fill(T value, std::array< size_t, 2 > idx_range)
Fill a subpart of the buffer with a given value.
A SYCL queue associated with a device and a context.
sycl::event submit(Fct &&fct)
Submits a kernel to the SYCL queue.
Class to manage a list of SYCL events.
Definition EventList.hpp:32
void wait()
Wait for all events in the list to be finished.
Definition EventList.hpp:58
Class Timer measures the time elapsed since the timer was started.
Definition Timer.hpp:36
f64 elapsed_sec() const
Converts the stored nanosecond time to a floating point representation in seconds.
Definition Timer.hpp:88
void start()
Starts the timer.
Definition Timer.hpp:51
void stop()
Stops the timer and stores the elapsed time in nanoseconds.
Definition Timer.hpp:65
int_chains_result int_chains_bench(DeviceScheduler_ptr sched, int N, f64 time_threshold)
Run the int_chains benchmark.
void int_chains(u32 i, int nrotation, T y0, T *__restrict in, T *__restrict out)
Kernel for the int_chains benchmark.
IntChainOp
Which integer operation a chain is built from.
@ Mul
multiply-add chains, 16 multiplies + 16 adds per rotation
@ Add
add-only chains, 32 adds per rotation
provide information about the source location
Structure containing the results of an int_chains benchmark.
std::string func_name
Name of the function.
f64 iops
Integer operations per second.
f64 seconds
Computation time in seconds.
u32 nrotations
Number of rotations performed.