1 /* Copyright (c) 2014-2019. The SimGrid Team. All rights reserved. */
3 /* This program is free software; you can redistribute it and/or modify it
4 * under the terms of the license (GNU LGPL) which comes with this package. */
11 #include "xbt/asserts.h"
12 #include "xbt/sysdep.h"
14 #include "src/internal_config.h"
15 #include "src/smpi/include/private.hpp"
17 #include "src/mc/mc_mmu.hpp"
18 #include "src/mc/mc_private.hpp"
19 #include "src/mc/mc_smx.hpp"
20 #include "src/mc/sosp/PageStore.hpp"
21 #include "src/mc/sosp/mc_snapshot.hpp"
24 /** @brief Read memory from a snapshot region broken across fragmented pages
26 * @param addr Process (non-snapshot) address of the data
27 * @param region Snapshot memory region where the data is located
28 * @param target Buffer to store the value
29 * @param size Size of the data to read in bytes
30 * @return Pointer where the data is located (target buffer of original location)
32 const void* MC_region_read_fragmented(simgrid::mc::RegionSnapshot* region, void* target, const void* addr, size_t size)
34 // Last byte of the memory area:
35 void* end = (char*)addr + size - 1;
37 // TODO, we assume the chunks are aligned to natural chunk boundaries.
38 // We should remove this assumption.
40 // Page of the last byte of the memory area:
41 size_t page_end = simgrid::mc::mmu::split((std::uintptr_t)end).first;
46 xbt_die("Missing destination buffer for fragmented memory access");
49 while (simgrid::mc::mmu::split((std::uintptr_t)addr).first != page_end) {
50 void* snapshot_addr = mc_translate_address_region_chunked((uintptr_t)addr, region);
51 void* next_page = (void*)simgrid::mc::mmu::join(simgrid::mc::mmu::split((std::uintptr_t)addr).first + 1, 0);
52 size_t readable = (char*)next_page - (char*)addr;
53 memcpy(dest, snapshot_addr, readable);
54 addr = (char*)addr + readable;
55 dest = (char*)dest + readable;
60 void* snapshot_addr = mc_translate_address_region_chunked((uintptr_t)addr, region);
61 memcpy(dest, snapshot_addr, size);
66 /** Compare memory between snapshots (with known regions)
68 * @param addr1 Address in the first snapshot
69 * @param region1 Region of the address in the first snapshot
70 * @param addr2 Address in the second snapshot
71 * @param region2 Region of the address in the second snapshot
72 * @return same semantic as memcmp
74 int MC_snapshot_region_memcmp(const void* addr1, simgrid::mc::RegionSnapshot* region1, const void* addr2,
75 simgrid::mc::RegionSnapshot* region2, size_t size)
77 // Using alloca() for large allocations may trigger stack overflow:
78 // use malloc if the buffer is too big.
79 bool stack_alloc = size < 64;
80 void* buffer1a = nullptr;
81 void* buffer2a = nullptr;
82 if (region1 != nullptr && region1->storage_type() != simgrid::mc::StorageType::Flat)
83 buffer1a = stack_alloc ? alloca(size) : ::operator new(size);
84 if (region2 != nullptr && region2->storage_type() != simgrid::mc::StorageType::Flat)
85 buffer2a = stack_alloc ? alloca(size) : ::operator new(size);
86 const void* buffer1 = MC_region_read(region1, buffer1a, addr1, size);
87 const void* buffer2 = MC_region_read(region2, buffer2a, addr2, size);
89 if (buffer1 == buffer2)
92 res = memcmp(buffer1, buffer2, size);
93 if (not stack_alloc) {
94 ::operator delete(buffer1a);
95 ::operator delete(buffer2a);
103 Snapshot::Snapshot(RemoteClient* process, int _num_state)
104 : AddressSpace(process)
105 , num_state_(_num_state)
106 , heap_bytes_used_(0)
107 , enabled_processes_()
108 , privatization_index_(0)
113 void Snapshot::add_region(RegionType type, ObjectInformation* object_info, void* start_addr, void* permanent_addr,
116 if (type == simgrid::mc::RegionType::Data)
117 xbt_assert(object_info, "Missing object info for object.");
118 else if (type == simgrid::mc::RegionType::Heap)
119 xbt_assert(not object_info, "Unexpected object info for heap region.");
121 simgrid::mc::RegionSnapshot* region;
123 const bool privatization_aware = object_info && mc_model_checker->process().privatized(*object_info);
124 if (privatization_aware && MC_smpi_process_count())
125 region = simgrid::mc::privatized_region(type, start_addr, permanent_addr, size);
128 region = simgrid::mc::region(type, start_addr, permanent_addr, size);
130 region->object_info(object_info);
131 snapshot_regions_.push_back(std::unique_ptr<simgrid::mc::RegionSnapshot>(std::move(region)));
134 const void* Snapshot::read_bytes(void* buffer, std::size_t size, RemotePtr<void> address, int process_index,
135 ReadOptions options) const
137 RegionSnapshot* region = this->get_region((void*)address.address(), process_index);
139 const void* res = MC_region_read(region, buffer, (void*)address.address(), size);
140 if (buffer == res || options & ReadOptions::lazy())
143 memcpy(buffer, res, size);
147 return this->process()->read_bytes(buffer, size, address, process_index, options);
149 /** @brief Find the snapshoted region from a pointer
151 * @param addr Pointer
152 * @param process_index rank requesting the region
154 RegionSnapshot* Snapshot::get_region(const void* addr, int process_index) const
156 size_t n = snapshot_regions_.size();
157 for (size_t i = 0; i != n; ++i) {
158 RegionSnapshot* region = snapshot_regions_[i].get();
159 if (not(region && region->contain(simgrid::mc::remote(addr))))
162 if (region->storage_type() == simgrid::mc::StorageType::Privatized) {
164 // Use the current process index of the snapshot:
165 if (process_index == simgrid::mc::ProcessIndexDisabled)
166 process_index = privatization_index_;
167 xbt_assert(process_index >= 0, "Missing process index");
168 xbt_assert(process_index < (int)region->privatized_data().size(), "Invalid process index");
170 RegionSnapshot* priv_region = region->privatized_data()[process_index].get();
171 xbt_assert(priv_region->contain(simgrid::mc::remote(addr)));
174 xbt_die("Privatized region in a non SMPI build (this should not happen)");
184 /** @brief Find the snapshoted region from a pointer, with a hinted_region */
185 RegionSnapshot* Snapshot::get_region(const void* addr, int process_index, RegionSnapshot* hinted_region) const
187 if (hinted_region->contain(simgrid::mc::remote(addr)))
188 return hinted_region;
190 return get_region(addr, process_index);
194 } // namespace simgrid