Itoyori  v0.0.1
home_manager.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <algorithm>
4 
5 #include "ityr/common/util.hpp"
6 #include "ityr/common/span.hpp"
8 #include "ityr/common/logger.hpp"
11 #include "ityr/ori/util.hpp"
12 #include "ityr/ori/options.hpp"
13 #include "ityr/ori/prof_events.hpp"
15 #include "ityr/ori/tlb.hpp"
17 
18 namespace ityr::ori {
19 
20 template <block_size_t BlockSize>
21 class home_manager {
22  static constexpr bool enable_vm_map = ITYR_ORI_ENABLE_VM_MAP;
23 
24 public:
25  home_manager(std::size_t mmap_entry_limit)
26  : mmap_entry_limit_(mmap_entry_limit),
27  cs_(mmap_entry_limit_, mmap_entry(this)),
28  home_tlb_({nullptr, 0}, nullptr) {}
29 
30  template <bool IncrementRef>
31  bool checkout_fast(std::byte* addr, std::size_t size) {
32  if constexpr (!home_tlb::enabled) return false;
33 
34  ITYR_CHECK(addr);
35  ITYR_CHECK(size > 0);
36 
37  if constexpr (!enable_vm_map) {
38  return false;
39  }
40 
41  auto me_p = home_tlb_.get([&](const std::pair<std::byte*, std::size_t>& seg) {
42  return seg.first <= addr && addr + size <= seg.first + seg.second;
43  });
44 
45  if (!me_p) return false;
46 
47  if constexpr (IncrementRef) {
48  mmap_entry& me = *me_p;
49  ITYR_CHECK((me_p == &mmap_entry_dummy_ || me.ref_count >= 0));
50  me.ref_count++;
51  }
52 
53  hprof_.record(size, true);
54 
55  return true;
56  }
57 
58  template <bool IncrementRef>
59  bool checkout_seg(std::byte* seg_addr,
60  std::size_t seg_size,
61  std::byte* req_addr, // only required for profiling
62  std::size_t req_size, // only required for profiling
63  const common::physical_mem& pm,
64  std::size_t pm_offset,
65  bool mapped_always) {
66  ITYR_CHECK(seg_addr);
67  ITYR_CHECK(seg_size > 0);
68 
69  if constexpr (!enable_vm_map) {
70  return true;
71  }
72 
73  if (mapped_always) {
74  home_tlb_.add({seg_addr, seg_size}, &mmap_entry_dummy_);
75  hprof_.record(seg_addr, seg_size, req_addr, req_size, true);
76  return true;
77  }
78 
79  mmap_entry& me = get_entry(seg_addr);
80 
81  bool checkout_completed = true;
82 
83  bool mmap_hit = seg_addr == me.mapped_addr;
84  if (!mmap_hit) {
85  me.addr = seg_addr;
86  me.size = seg_size;
87  me.pm = &pm;
88  me.pm_offset = pm_offset;
89  home_segments_to_map_.push_back(&me);
90  checkout_completed = false;
91  }
92 
93  if constexpr (IncrementRef) {
94  ITYR_CHECK(me.ref_count >= 0);
95  me.ref_count++;
96  }
97 
98  home_tlb_.add({seg_addr, seg_size}, &me);
99 
100  hprof_.record(seg_addr, seg_size, req_addr, req_size, mmap_hit);
101 
102  return checkout_completed;
103  }
104 
105  template <bool DecrementRef>
106  bool checkin_fast(const std::byte* addr, std::size_t size) {
107  if constexpr (!home_tlb::enabled) return false;
108 
109  ITYR_CHECK(addr);
110  ITYR_CHECK(size > 0);
111 
112  if constexpr (!enable_vm_map) {
113  return false;
114  }
115 
116  auto me_p = home_tlb_.get([&](const std::pair<std::byte*, std::size_t>& seg) {
117  return seg.first <= addr && addr + size <= seg.first + seg.second;
118  });
119 
120  if (!me_p) return false;
121 
122  if constexpr (DecrementRef) {
123  mmap_entry& me = *me_p;
124  me.ref_count--;
125  ITYR_CHECK((me_p == &mmap_entry_dummy_ || me.ref_count >= 0));
126  }
127 
128  return true;
129  }
130 
131  template <bool DecrementRef>
132  void checkin_seg(std::byte* seg_addr, bool mapped_always) {
133  if constexpr (!enable_vm_map) {
134  return;
135  }
136 
137  if (mapped_always) return;
138 
139  if constexpr (DecrementRef) {
140  mmap_entry& me = get_entry<false>(seg_addr);
141  me.ref_count--;
142  ITYR_CHECK(me.ref_count >= 0);
143  }
144  }
145 
147  if constexpr (!enable_vm_map) {
148  return;
149  }
150 
151  if (!home_segments_to_map_.empty()) {
152  for (mmap_entry* me : home_segments_to_map_) {
153  update_mapping(*me);
154  }
155  home_segments_to_map_.clear();
156  }
157  }
158 
159  void ensure_evicted(void* addr) {
160  if constexpr (!enable_vm_map) {
161  return;
162  }
163 
164  cs_.ensure_evicted(cache_key(addr));
165  }
166 
167  void clear_tlb() {
168  home_tlb_.clear();
169  }
170 
171  void on_checkout_noncoll(std::size_t size) {
172  // Home blocks are always mapped to the local view for noncoll memory
173  hprof_.record(size, true);
174  }
175 
176  void home_prof_begin() { hprof_.start(); }
177  void home_prof_end() { hprof_.stop(); }
178  void home_prof_print() const { hprof_.print(); }
179 
180 private:
181  using cache_key_t = uintptr_t;
182 
183  struct mmap_entry {
185  std::byte* addr = nullptr;
186  std::byte* mapped_addr = nullptr;
187  std::size_t size = 0;
188  std::size_t mapped_size = 0;
189  const common::physical_mem* pm = nullptr;
190  std::size_t pm_offset = 0;
191  int ref_count = 0;
192  home_manager* outer;
193 
194  explicit mmap_entry(home_manager* outer_p) : outer(outer_p) {}
195 
196  /* Callback functions for cache_system class */
197 
198  bool is_evictable() const {
199  return ref_count == 0;
200  }
201 
202  void on_evict() {
203  ITYR_CHECK(is_evictable());
204  ITYR_CHECK(mapped_addr == addr);
206  // for safety
207  outer->home_tlb_.clear();
208  }
209 
210  void on_cache_map(cache_entry_idx_t idx) {
211  entry_idx = idx;
212  }
213  };
214 
215  template <bool UpdateLRU = true>
216  mmap_entry& get_entry(void* addr) {
217  try {
218  return cs_.template ensure_cached<UpdateLRU>(cache_key(addr));
219  } catch (cache_full_exception& e) {
220  common::die("home segments are exhausted (too much checked-out memory)");
221  }
222  }
223 
224  void update_mapping(mmap_entry& me) {
225  ITYR_PROFILER_RECORD(prof_event_home_mmap);
226 
227  if (me.mapped_addr) {
228  common::verbose<3>("Unmap home segment [%p, %p) (size=%ld)",
229  me.mapped_addr, me.mapped_addr + me.mapped_size, me.mapped_size);
230  common::mmap_no_physical_mem(me.mapped_addr, me.mapped_size, true);
231  }
232 
233  ITYR_CHECK(me.pm);
234  ITYR_CHECK(me.addr);
235  common::verbose<3>("Map home segment [%p, %p) (size=%ld)",
236  me.addr, me.addr + me.size, me.size);
237  me.pm->map_to_vm(me.addr, me.size, me.pm_offset);
238  me.mapped_addr = me.addr;
239  me.mapped_size = me.size;
240  }
241 
242  cache_key_t cache_key(void* addr) const {
243  ITYR_CHECK(addr);
244  ITYR_CHECK(reinterpret_cast<uintptr_t>(addr) % BlockSize == 0);
245  return reinterpret_cast<uintptr_t>(addr) / BlockSize;
246  }
247 
248  using home_tlb = tlb<std::pair<std::byte*, std::size_t>,
249  mmap_entry*,
251 
252  std::size_t mmap_entry_limit_;
253  cache_system<cache_key_t, mmap_entry> cs_;
254  mmap_entry mmap_entry_dummy_ = mmap_entry{nullptr};
255  home_tlb home_tlb_;
256  std::vector<mmap_entry*> home_segments_to_map_;
257  home_profiler hprof_;
258 };
259 
260 }
Definition: physical_mem.hpp:18
void ensure_evicted(Key key)
Definition: cache_system.hpp:77
Definition: home_manager.hpp:21
bool checkin_fast(const std::byte *addr, std::size_t size)
Definition: home_manager.hpp:106
void checkout_complete()
Definition: home_manager.hpp:146
bool checkout_seg(std::byte *seg_addr, std::size_t seg_size, std::byte *req_addr, std::size_t req_size, const common::physical_mem &pm, std::size_t pm_offset, bool mapped_always)
Definition: home_manager.hpp:59
home_manager(std::size_t mmap_entry_limit)
Definition: home_manager.hpp:25
void ensure_evicted(void *addr)
Definition: home_manager.hpp:159
void checkin_seg(std::byte *seg_addr, bool mapped_always)
Definition: home_manager.hpp:132
void home_prof_end()
Definition: home_manager.hpp:177
void home_prof_print() const
Definition: home_manager.hpp:178
bool checkout_fast(std::byte *addr, std::size_t size)
Definition: home_manager.hpp:31
void home_prof_begin()
Definition: home_manager.hpp:176
void on_checkout_noncoll(std::size_t size)
Definition: home_manager.hpp:171
void clear_tlb()
Definition: home_manager.hpp:167
void clear()
Definition: tlb.hpp:61
Entry get(const Key &key)
Definition: tlb.hpp:42
void add(const Key &key, const Entry &entry)
Definition: tlb.hpp:21
#define ITYR_CHECK(cond)
Definition: util.hpp:48
void * mmap_no_physical_mem(void *addr, std::size_t size, bool replace=false, std::size_t alignment=alignof(max_align_t))
Definition: virtual_mem.hpp:110
Definition: block_region_set.hpp:9
int cache_entry_idx_t
Definition: cache_system.hpp:30
ITYR_CONCAT(home_profiler_, ITYR_ORI_CACHE_PROF) home_profiler
Definition: home_profiler.hpp:77
monoid< T, max_functor<>, lowest< T > > max
Definition: reducer.hpp:104
constexpr auto size(const checkout_span< T, Mode > &cs) noexcept
Definition: checkout_span.hpp:178
#define ITYR_ORI_HOME_TLB_SIZE
#define ITYR_ORI_ENABLE_VM_MAP
#define ITYR_PROFILER_RECORD(event,...)
Definition: profiler.hpp:319