Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
ShamrockDump.cpp
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
16
18#include "shambase/string.hpp"
19#include "shamcmdopt/env.hpp"
20#include "shamcomm/logs.hpp"
22
23namespace shamrock {
24
25 void write_shamrock_dump(std::string fname, std::string metadata_user, PatchScheduler &sched) {
26
27 StackEntry stack_loc{};
28
29 std::string metadata_patch = sched.serialize_patch_metadata().dump(4);
30
31 using namespace shamrock::patch;
32
33 std::vector<u64> pids;
34 std::vector<u64> bytecounts;
35 std::vector<sham::DeviceBuffer<u8>> datas;
36
37 // serialize patchdatas and push them into dat
38 sched.patch_data.for_each_patchdata([&](u64 pid, PatchDataLayer &pdat) {
39 auto ser_sz = pdat.serialize_buf_byte_size();
40 shamalgs::SerializeHelper ser(shamsys::instance::get_compute_scheduler_ptr());
41 ser.allocate(ser_sz, true);
42 pdat.serialize_buf(ser);
43
44 auto tmp = ser.finalize();
45 size_t bytecount = tmp.get_size();
46
47 pids.push_back(pid);
48 bytecounts.push_back(bytecount);
49 datas.push_back(std::move(tmp));
50 });
51
52 std::vector<u64> all_pids;
53 std::vector<u64> all_bytecounts;
54
56 pids, get_mpi_type<u64>(), all_pids, get_mpi_type<u64>(), MPI_COMM_WORLD);
58 bytecounts, get_mpi_type<u64>(), all_bytecounts, get_mpi_type<u64>(), MPI_COMM_WORLD);
59
60 std::vector<u64> all_offsets = all_bytecounts;
61
62 std::exclusive_scan(all_offsets.begin(), all_offsets.end(), all_offsets.begin(), u64{0});
63
64 using namespace nlohmann;
65
66 json j;
67 j["pids"] = all_pids;
68 j["bytecounts"] = all_bytecounts;
69 j["offsets"] = all_offsets;
70
71 std::string sout = j.dump(4);
72
73 // Write to the file
74
75 u64 head_ptr = 0;
76 MPI_File mfile{};
77
78 shamcomm::open_reset_file(mfile, fname);
79
80 shambase::Timer timer;
81 timer.start();
82
83 // do some perf investigation before enabling preallocation
84 bool preallocate = false;
85 if (preallocate) {
86 MPI_Offset tot_byte = all_offsets.back() + all_bytecounts.back() + metadata_user.size()
87 + metadata_patch.size() + sout.size() + sizeof(std::size_t) * 3;
88 MPICHECK(MPI_File_preallocate(mfile, tot_byte));
89 }
90
91 shamalgs::collective::write_header(mfile, metadata_user, head_ptr);
92 shamalgs::collective::write_header(mfile, metadata_patch, head_ptr);
93 shamalgs::collective::write_header(mfile, sout, head_ptr);
94
95 shamlog_debug_ln(
96 "ShamrockDump",
97 sham::format(
98 "table sizes {} {} {}", metadata_patch.size(), metadata_user.size(), sout.size()));
99
100 if (/*do check*/ true) {
101 auto check_same_mpi = [](std::string s) {
102 u64 out = shamalgs::collective::allreduce_sum(s.size());
103 if (out != s.size() * shamcomm::world_size()) {
105 "ShamrockDump",
106 sham::format(
107 "string size mismatch between all processes,\n size : {}\nthe "
108 "string : {}\n",
109 s.size(),
110 s));
112 "size mismatch in shamrock dump header");
113 }
114 };
115
116 check_same_mpi(metadata_user);
117 check_same_mpi(metadata_patch);
118 check_same_mpi(sout);
119 }
120
121 if (!shamcmdopt::getenv_str("SHAMDUMP_OFFSET_MODE_OLD").has_value()) {
122 // reset MPI view
123 MPICHECK(MPI_File_set_view(mfile, 0, MPI_BYTE, MPI_CHAR, "native", MPI_INFO_NULL));
124 }
125
126 // map of patch id -> all_pids idx
127 std::unordered_map<u64, size_t> map{};
128 for (u32 i = 0; i < all_pids.size(); i++) {
129 map[all_pids[i]] = i;
130 }
131
132 for (u32 i = 0; i < datas.size(); i++) {
133
134 u64 pid = pids[i];
135 u64 bytecount = bytecounts[i];
136
137 size_t off = all_offsets[map[pid]];
138 auto &data = datas[i];
139
140 shamcomm::CommunicationBuffer buf(data, shamsys::instance::get_compute_scheduler_ptr());
141
142 shamalgs::collective::write_at_large(mfile, buf.get_ptr(), bytecount, head_ptr + off);
143 }
144
145 // write data to file
146
147 MPI_File_close(&mfile);
148 timer.stop();
149
150 if (shamcomm::world_rank() == 0) {
151 size_t plist_len = all_offsets.size();
152 size_t max_head = all_offsets[plist_len - 1] + all_bytecounts[plist_len - 1] + head_ptr;
154 "Shamrock Dump",
155 sham::format(
156 "dump to {}\n - took {}, bandwidth = {}/s",
157 fname,
158 timer.get_time_str(),
159 shambase::readable_sizeof(max_head / timer.elapsed_sec())));
160 }
161 }
162
163 void load_shamrock_dump(std::string fname, std::string &metadata_user, ShamrockCtx &ctx) {
164
165 StackEntry stack_loc{};
166
167 u64 head_ptr = 0;
168 MPI_File mfile{};
169
170 shamcomm::open_read_only_file(mfile, fname);
171
172 shambase::Timer timer;
173 timer.start();
174
175 std::string metadata_patch{};
176 std::string patchdata_infos{};
177
178 metadata_user = shamalgs::collective::read_header(mfile, head_ptr);
179 metadata_patch = shamalgs::collective::read_header(mfile, head_ptr);
180 patchdata_infos = shamalgs::collective::read_header(mfile, head_ptr);
181
182 if (!shamcmdopt::getenv_str("SHAMDUMP_OFFSET_MODE_OLD").has_value()) {
183 // reset MPI view
184 MPICHECK(MPI_File_set_view(mfile, 0, MPI_BYTE, MPI_CHAR, "native", MPI_INFO_NULL));
185 }
186 // logger::raw_ln(metadata_user, metadata_patch, patchdata_infos);
187
188 using namespace nlohmann;
189
190 json jmeta_patch = json::parse(metadata_patch);
191 json jpdat_info = json::parse(patchdata_infos);
192
193 ctx.pdata_layout_new();
194 *ctx.pdl = jmeta_patch.at("patchdata_layout").get<patch::PatchDataLayerLayout>();
195 ctx.init_sched(
196 jmeta_patch.at("crit_patch_split").get<u64>(),
197 jmeta_patch.at("crit_patch_merge").get<u64>());
198
199 auto &sched = shambase::get_check_ref(ctx.sched);
200
201 sched.patch_list = jmeta_patch.at("patchlist").get<SchedulerPatchList>();
202 sched.patch_tree = jmeta_patch.at("patchtree").get<scheduler::PatchTree>();
203 sched.patch_data.sim_box.from_json(jmeta_patch.at("sim_box"));
204 if (jmeta_patch.contains("synchronized_data")) {
205 jmeta_patch.at("synchronized_data").get_to(sched.synchronized_data);
206 }
207
208 // edit patch owner to fit in new world size, or spread if more processes now
209 // a bit dirty but gets the job done for now
210 // ideally we should call a load balance once
211 for (auto &p : sched.patch_list.global) {
212 p.node_owner_id = p.node_owner_id % shamcomm::world_size();
213 }
214
215 // rebuild local patch list
216 auto loc_ids = sched.patch_list.build_local();
217
218 // Load patchdata according to new LB
219
220 std::vector<u64> all_offsets;
221 std::vector<u64> all_pids;
222 std::vector<u64> all_bytecounts;
223
224 all_bytecounts = jpdat_info.at("bytecounts").get<std::vector<u64>>();
225 all_offsets = jpdat_info.at("offsets").get<std::vector<u64>>();
226 all_pids = jpdat_info.at("pids").get<std::vector<u64>>();
227
228 struct PatchFileOffset {
229 u64 offset, bytecount;
230 };
231
232 std::unordered_map<u64, PatchFileOffset> off_table;
233
234 for (u32 i = 0; i < all_bytecounts.size(); i++) {
235 off_table[all_pids[i]] = {.offset = all_offsets[i], .bytecount = all_bytecounts[i]};
236 }
237
238 for (const auto &p : sched.patch_list.local) {
239 u64 pid = p.id_patch;
240 auto loc_file_info = off_table[pid];
241
243 loc_file_info.bytecount, shamsys::instance::get_compute_scheduler_ptr());
244
246 mfile, buf.get_ptr(), loc_file_info.bytecount, head_ptr + loc_file_info.offset);
247
249
251 shamsys::instance::get_compute_scheduler_ptr(), std::move(out), true);
252
253 patch::PatchDataLayer pdat = patch::PatchDataLayer::deserialize_buf(ser, ctx.pdl);
254
255 sched.patch_data.owned_data.add_obj(pid, std::move(pdat));
256 }
257
258 MPI_File_close(&mfile);
259 timer.stop();
260
261 if (shamcomm::world_rank() == 0) {
262 size_t plist_len = all_offsets.size();
263 size_t max_head = all_offsets[plist_len - 1] + all_bytecounts[plist_len - 1] + head_ptr;
265 "Shamrock Dump",
266 sham::format(
267 "load dump from {}\n - took {}, bandwidth = {}/s",
268 fname,
269 timer.get_time_str(),
270 shambase::readable_sizeof(max_head / timer.elapsed_sec())));
271 }
272 }
273
274} // namespace shamrock
std::uint32_t u32
32 bit unsigned integer
std::uint64_t u64
64 bit unsigned integer
The MPI scheduler.
SchedulerPatchData patch_data
handle the data of the patches of the scheduler
Handle the patch list of the mpi scheduler.
A buffer allocated in USM (Unified Shared Memory).
size_t get_size() const
Gets the number of elements in the buffer.
Class Timer measures the time elapsed since the timer was started.
Definition Timer.hpp:36
std::string get_time_str() const
Converts the stored nanosecond time to a string representation.
Definition Timer.hpp:79
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
Shamrock communication buffers.
static sham::DeviceBuffer< u8 > convert_usm(CommunicationBuffer &&buf)
destroy the buffer and recover the held object
PatchDataLayer container class, the layout is described in patchdata_layout.
Patch Tree : Tree structure organisation for an abstract list of patches Nb : this tree is compatible...
Definition PatchTree.hpp:29
std::vector< int > vector_allgatherv(const std::vector< T > &send_vec, const MPI_Datatype &send_type, std::vector< T > &recv_vec, const MPI_Datatype &recv_type, const MPI_Comm comm)
allgatherv on vector with size query (size querying variant of vector_allgatherv_ks) //TODO add fault...
Definition exchanges.hpp:98
#define MPICHECK(mpicall)
Shortcut macro to check MPI return codes.
std::string readable_sizeof(double size)
given a sizeof value return a readble string Example : readable_sizeof(1e9) -> "1....
Definition string.hpp:80
void throw_with_loc(std::string message, SourceLocation loc=SourceLocation{})
Throw an exception and append the source location to it.
T & get_check_ref(const std::unique_ptr< T > &ptr, SourceLocation loc=SourceLocation())
Takes a std::unique_ptr and returns a reference to the object it holds. It throws a std::runtime_erro...
Definition memory.hpp:112
std::optional< std::string > getenv_str(const char *env_var)
Get the content of the environment variable if it exist.
Definition env.cpp:24
void open_reset_file(MPI_File &fh, const std::string &fname)
Open a MPI file and remove its content.
Definition io.cpp:24
i32 world_rank()
Gives the rank of the current process in the MPI communicator.
Definition worldInfo.cpp:41
i32 world_size()
Gives the size of the MPI communicator.
Definition worldInfo.cpp:39
void open_read_only_file(MPI_File &fh, const std::string &fname)
Open a mpi file in read only mode.
Definition io.cpp:52
namespace for the main framework
Definition __init__.py:1
void load_shamrock_dump(std::string fname, std::string &metadata_user, ShamrockCtx &ctx)
Load a Shamrock dump file and restore the state of the patches and retreive user metadata.
void write_shamrock_dump(std::string fname, std::string metadata_user, PatchScheduler &sched)
Write a Shamrock dump file containing the current state of the patches and user supplied metadata.
std::string read_header(MPI_File fh, u64 &file_head_ptr)
Reads a string from a file using MPI and updates the file head pointer. The string is preceded by its...
Definition io.hpp:276
void write_header(MPI_File fh, std::string s, u64 &file_head_ptr)
Writes a string to a file using MPI and updates the file head pointer. The string is preceded by its ...
Definition io.hpp:262
void write_at_large(MPI_File fh, const u8 *buf, size_t len, u64 file_head_ptr)
Writes a large byte buffer at a given offset in a file using MPI.
Definition io.hpp:181
void read_at_large(MPI_File fh, u8 *buf, size_t len, u64 file_head_ptr)
Reads a large byte buffer at a given offset in a file using MPI.
Definition io.hpp:224
void info_ln(std::string module_name, Types... var2)
Prints a log message with multiple arguments followed by a newline.
Definition logs.hpp:132
void err_ln(std::string module_name, Types... var2)
Prints a log message with multiple arguments followed by a newline.
Definition logs.hpp:132
This file contains the definition for the stacktrace related functionality.
shambase::details::BasicStackEntry StackEntry
Alias for shambase::details::BasicStackEntry.