Itoyori  v0.0.1
tlb.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <array>
4 #include <algorithm>
5 
6 #include "ityr/common/util.hpp"
7 #include "ityr/ori/util.hpp"
8 
9 namespace ityr::ori {
10 
11 template <typename Key, typename Entry, int NEntries = 3>
12 class tlb {
13 public:
14  constexpr static bool enabled = NEntries > 0;
15 
16  tlb() : tlb(Key{}, Entry{}) {}
17  tlb(Key invalid_key, Entry invalid_entry) {
18  entries_.fill({invalid_key, invalid_entry, 0});
19  }
20 
21  void add(const Key& key, const Entry& entry) {
22  if constexpr (!enabled) return;
23 
24  // FIXME: the same entry can be duplicated?
25  Key invalid_key = entries_[0].key;
26  for (int i = 1; i <= NEntries; i++) {
27  if (entries_[i].key == invalid_key) {
28  entries_[i] = {key, entry, timestamp_++};
29  return;
30  }
31  }
32 
33  // TLB is full, so evict the element with the smallest timestamp
34  tlb_entry& victim = *std::min_element(
35  entries_.begin() + 1, entries_.end(),
36  [](const auto& te1, const auto& te2) {
37  return te1.timestamp < te2.timestamp;
38  });
39  victim = {key, entry, timestamp_++};
40  }
41 
42  Entry get(const Key& key) {
43  return get([&](const Key& k) { return k == key; });
44  }
45 
46  template <typename Fn>
47  Entry get(Fn fn) {
48  if constexpr (!enabled) return entries_[0].entry;
49 
50  int found_index = 0;
51  for (int i = 1; i <= NEntries; i++) {
52  if (fn(entries_[i].key)) {
53  // Do not immediately return here for branch-less execution (using CMOV etc.)
54  found_index = i;
55  }
56  }
57  entries_[found_index].timestamp = timestamp_++;
58  return entries_[found_index].entry;
59  }
60 
61  void clear() {
62  if constexpr (!enabled) return;
63 
64  tlb_entry invalid_te = entries_[0];
65  entries_.fill(invalid_te);
66  timestamp_ = 0;
67  }
68 
69 private:
70  using timestamp_t = int;
71 
72  struct tlb_entry {
73  Key key;
74  Entry entry;
75  timestamp_t timestamp;
76  };
77 
78  std::array<tlb_entry, NEntries + 1> entries_;
79  timestamp_t timestamp_ = 0;
80 };
81 
82 ITYR_TEST_CASE("[ityr::ori::tlb] test TLB") {
83  using key_t = int;
84  using element_t = int;
85  constexpr int n_elements = 5;
86 
87  key_t invalid_key = -1;
88  element_t invalid_element = -1;
89 
90  tlb<key_t, element_t, n_elements> tlb_(invalid_key, invalid_element);
91 
92  int n = 100;
93  for (int i = 0; i < n; i++) {
94  tlb_.add(i, i * 2);
95  }
96 
97  for (int i = 0; i < n; i++) {
98  element_t ret = tlb_.get(i);
99  if (i < n - n_elements) {
100  ITYR_CHECK(ret == invalid_element);
101  } else {
102  ITYR_CHECK(ret == i * 2);
103  }
104  }
105 
106  tlb_.clear();
107 
108  for (int i = 0; i < n; i++) {
109  element_t ret = tlb_.get(i);
110  ITYR_CHECK(ret == invalid_element);
111  }
112 }
113 
114 }
Definition: tlb.hpp:12
void clear()
Definition: tlb.hpp:61
tlb()
Definition: tlb.hpp:16
Entry get(const Key &key)
Definition: tlb.hpp:42
constexpr static bool enabled
Definition: tlb.hpp:14
tlb(Key invalid_key, Entry invalid_entry)
Definition: tlb.hpp:17
Entry get(Fn fn)
Definition: tlb.hpp:47
void add(const Key &key, const Entry &entry)
Definition: tlb.hpp:21
#define ITYR_CHECK(cond)
Definition: util.hpp:48
Definition: block_region_set.hpp:9
ForwardIterator min_element(const ExecutionPolicy &policy, ForwardIterator first, ForwardIterator last, Compare comp)
Search for the minimum element in a range.
Definition: parallel_search.hpp:88