Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
gpu_core_timeline.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
19
26#include "shamcomm/logs.hpp"
27#include <shambackends/sycl.hpp>
28#include <unordered_map>
29#include <fstream>
30#include <iostream>
31#include <vector>
32
33#if __has_include(<nlohmann/json.hpp>)
34 #include "nlohmann/json.hpp"
35#endif
36
37namespace sham {
38
41 unsigned long long start;
42 unsigned long long first_end;
43 unsigned long long last_end;
44 uint lane;
45 uint color;
46 };
47
48} // namespace sham
49
50#if __has_include(<nlohmann/json.hpp>)
51
52NLOHMANN_JSON_NAMESPACE_BEGIN
53template<>
54struct adl_serializer<sham::TimelineEvent> {
55 static void to_json(json &j, const sham::TimelineEvent &e) {
56 j
57 = {{"start", e.start},
58 {"first_end", e.first_end},
59 {"last_end", e.last_end},
60 {"color", e.color},
61 {"lane", e.lane}};
62 }
63};
64NLOHMANN_JSON_NAMESPACE_END
65#endif
66
67namespace sham {
68
80 sham::DeviceScheduler_ptr dev_sched;
81 sham::DeviceBuffer<u64> frame_start_clock;
82
84 sham::DeviceBuffer<u64> event_count;
85
86 public:
89 const sham::DeviceScheduler_ptr &dev_sched, u32 max_event_count)
90 : dev_sched(dev_sched), frame_start_clock(1, dev_sched),
91 events(max_event_count, dev_sched), event_count(1, dev_sched) {
92 event_count.set_val_at_idx(0, 0);
94 }
95
108
109 static std::unordered_map<DeviceScheduler *, bool> cache;
110 auto it = cache.find(dev_sched.get());
111 if (it == cache.end()) {
112
113 sham::DeviceBuffer<u64> tmp(1, dev_sched);
114
116 dev_sched->get_queue(),
118 sham::MultiRef{tmp},
119 1,
120 [](u32 i, u64 *out) {
121#if defined(SHAMROCK_INTRISICS_GET_DEVICE_CLOCK_AVAILABLE) \
122 && defined(SHAMROCK_INTRISICS_GET_SMID_AVAILABLE)
123 *out = 1;
124#else
125 *out = 0;
126#endif
127 });
128
129 cache[dev_sched.get()] = tmp.get_val_at_idx(0);
130
131 if (!cache[dev_sched.get()]) {
133 "Backend", "gpu_core_timeline_profilier is not available on the device");
134 }
135 }
136
137 return cache[dev_sched.get()];
138 }
139
140 // base clock val
141
145 inline void setFrameStartClock() {
147 dev_sched->get_queue(),
149 sham::MultiRef{frame_start_clock},
150 1,
151 [](u32 i, u64 *clock) {
152#ifdef SHAMROCK_INTRISICS_GET_DEVICE_CLOCK_AVAILABLE
153 *clock = sham::get_device_clock();
154#else
155 *clock = 0;
156#endif
157 });
158 }
159
160 inline u64 get_base_clock_value() { return frame_start_clock.get_val_at_idx(0); }
161
162 struct local_access_t {
163 sycl::local_accessor<uint> _index;
164 sycl::local_accessor<bool> _valid;
165
166 local_access_t(sycl::handler &cgh) : _index(1, cgh), _valid(1, cgh) {}
167 };
168
169 // Kernel access section
170 struct acc {
171 TimelineEvent *events;
172 u64 *event_count;
173 u64 max_event_count;
174
192 sycl::nd_item<1> item, const local_access_t &acc) const {
193 if (item.get_local_id(0) == 0) {
194 sycl::atomic_ref<
195 u64,
196 sycl::memory_order_relaxed,
197 sycl::memory_scope_device,
198 sycl::access::address_space::global_space>
199 ev_cnt_ref(event_count[0]);
200
201 acc._index[0] = ev_cnt_ref.fetch_add(1_u64);
202 acc._valid[0] = acc._index[0] < max_event_count;
203
204 if (acc._valid[0]) {
205#ifdef SHAMROCK_INTRISICS_GET_SMID_AVAILABLE
206 events[acc._index[0]]
207 = {.start = u64_max,
208 .first_end = u64_max,
209 .last_end = 0,
210 .lane = sham::get_sm_id(),
211 .color = 0};
212#else
213 events[acc._index[0]] = {u64_max, u64_max, 0, 0, 0};
214#endif
215 }
216 }
217 item.barrier(); // equivalent to __syncthreads
218 }
219
228 inline void start_timeline_event(const local_access_t &acc) const {
229 if (acc._valid[0]) {
230
231 sycl::atomic_ref<
232 unsigned long long,
233 sycl::memory_order_relaxed,
234 sycl::memory_scope_device,
235 sycl::access::address_space::global_space>
236 start_val(events[acc._index[0]].start);
237
238 using ull = unsigned long long;
239
240#ifdef SHAMROCK_INTRISICS_GET_DEVICE_CLOCK_AVAILABLE
241 ull clock = sham::get_device_clock();
242#else
243 ull clock = 0;
244#endif
245
246 start_val.fetch_min(clock);
247 }
248 }
249
258 inline void end_timeline_event(const local_access_t &acc) const {
259 if (acc._valid[0]) {
260 sycl::atomic_ref<
261 unsigned long long,
262 sycl::memory_order_relaxed,
263 sycl::memory_scope_device,
264 sycl::access::address_space::global_space>
265 first_end(events[acc._index[0]].first_end);
266
267 sycl::atomic_ref<
268 unsigned long long,
269 sycl::memory_order_relaxed,
270 sycl::memory_scope_device,
271 sycl::access::address_space::global_space>
272 last_end(events[acc._index[0]].last_end);
273
274 using ull = unsigned long long;
275
276#ifdef SHAMROCK_INTRISICS_GET_DEVICE_CLOCK_AVAILABLE
277 ull clock = sham::get_device_clock();
278#else
279 ull clock = 0;
280#endif
281
282 first_end.fetch_min(clock);
283 last_end.fetch_max(clock);
284 }
285 }
286 };
287
296 return {
297 .events = events.get_write_access(deps),
298 .event_count = event_count.get_write_access(deps),
299 .max_event_count = events.get_size()};
300 }
301
309 inline void complete_event_state(sycl::event e) {
310 events.complete_event_state(e);
311 event_count.complete_event_state(e);
312 }
313
314#if __has_include(<nlohmann/json.hpp>)
335 inline void dump_to_file(const std::string &filename) {
336
337 u32 sz = event_count.get_val_at_idx(0);
338
339 std::cout << "dumping to " << filename << " size = " << sz << std::endl;
340
341 std::vector<TimelineEvent> events = this->events.copy_to_stdvec_idx_range(0, sz);
342
343 u64 base_clock = get_base_clock_value();
344
345 for (auto &t : events) {
346 t.start -= base_clock;
347 t.first_end -= base_clock;
348 t.last_end -= base_clock;
349 }
350
351 std::ofstream file(filename);
352 file << nlohmann::json(events).dump(4) << std::endl;
353 }
354#endif
355
356 // inline void open_file(const std::string &filename) {
357 // std::string cmd = "python3 ../buildbot/gpu_core_timeline_read.py ";
358 // cmd += filename + " -b 4";
359 // std::system(cmd.c_str());
360 // }
361 };
362
363} // namespace sham
void to_json(nlohmann::json &j, const PatchSchedulerConfig &p)
Converts a PatchSchedulerConfig object to a JSON object.
std::uint32_t u32
32 bit unsigned integer
std::uint64_t u64
64 bit unsigned integer
A buffer allocated in USM (Unified Shared Memory).
T get_val_at_idx(size_t idx) const
Get the value at a given index in the buffer.
Class to manage a list of SYCL events.
Definition EventList.hpp:32
void setFrameStartClock()
Recover the current device time in the frame_start_clock buffer.
gpu_core_timeline_profilier(const sham::DeviceScheduler_ptr &dev_sched, u32 max_event_count)
CTOR.
acc get_write_access(sham::EventList &deps)
Get a write access to the timeline events and the event count.
bool is_available_on_device()
Check if gpu_core_timeline_profilier is available on the device.
This file implement the GPU core timeline tool from A. Richermoz, F. Neyret 2024.
namespace for backends this one is named only sham since shambackends is too long to write
u32 get_sm_id()
Return the SM (Streaming Multiprocessor) ID of the calling thread, or equivalent if implemented.
void kernel_call(sham::DeviceQueue &q, RefIn in, RefOut in_out, u32 n, Functor &&func, SourceLocation &&callsite=SourceLocation{})
Submit a kernel to a SYCL queue.
u64 get_device_clock()
Return the number of clock cycles elapsed since an arbitrary starting point on the device.
constexpr u64 u64_max
u64 max value
void warn_ln(std::string module_name, Types... var2)
Prints a log message with multiple arguments followed by a newline.
Definition logs.hpp:132
A class that references multiple buffers or similar objects.
Definition MultiRef.hpp:33
A timeline event for the gpu core timeline.
void start_timeline_event(const local_access_t &acc) const
Start a timeline event.
void init_timeline_event(sycl::nd_item< 1 > item, const local_access_t &acc) const
Initialize a timeline event.
void end_timeline_event(const local_access_t &acc) const
Finish a timeline event.