Skip to content

Commit 80b02bb

Browse files
committed
Update table implementation
1 parent 6b7c19c commit 80b02bb

File tree

4 files changed

+151
-28
lines changed

4 files changed

+151
-28
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Currently, this project is in early development.
2727

2828
## Credits
2929

30-
Part of the Graph implementation is from https://github.com/jcmosc/Compute
30+
OpenGraph_SPI's Data, Graph, Vector and more is modified based on [Compute](https://github.com/jcmosc/Compute)'s implementations.
3131

3232
## License
3333

Sources/OpenGraph_SPI/Data/ptr.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ template <typename T> class ptr {
3636
OG_INLINE OG_CONSTEXPR ptr(difference_type offset = 0) : _offset(offset){};
3737
OG_INLINE OG_CONSTEXPR ptr(nullptr_t){};
3838

39-
OG_INLINE OG_CONSTEXPR
40-
void assert_valid() const {
41-
if (_offset >= shared_table().data_capacity()) {
39+
OG_INLINE
40+
void assert_valid(table t = shared_table()) const {
41+
if (t.data_capacity() <= _offset) {
4242
precondition_failure("invalid data offset: %u", _offset);
4343
}
4444
}

Sources/OpenGraph_SPI/Data/table.cpp

Lines changed: 146 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
//
55
// Audited for iOS 18.0
66
// Status: WIP
7+
// Modified from https://github.com/jcmosc/Compute/blob/0a6b21a4cdeb9bbdd95e7e914c4e18bed37a2456/Sources/ComputeCxx/Data/Table.cpp [MIT License]
78

89
#include "table.hpp"
910
#include "page.hpp"
10-
#include "page.hpp"
11+
#include "page_const.hpp"
12+
#include "zone.hpp"
1113
#include "../Util/assert.hpp"
1214
#include <sys/mman.h>
1315
#include <malloc/malloc.h>
@@ -81,36 +83,157 @@ void table::grow_region() OG_NOEXCEPT {
8183
_data_capacity = new_size + page_size;
8284
}
8385

84-
void table::make_pages_reusable(uint32_t page_index, bool flag) OG_NOEXCEPT {
85-
precondition_failure("TODO");
86+
void table::make_pages_reusable(uint32_t page_index, bool reusable) OG_NOEXCEPT {
87+
static constexpr uint32_t mapped_pages_size = page_size * pages_per_map; // 64 * 512 = 0x8000
88+
void *mapped_pages_address = reinterpret_cast<void *>(region_base() + ((page_index * page_size) & ~(mapped_pages_size - 1)));
89+
int advice = reusable ? MADV_FREE_REUSABLE : MADV_FREE_REUSE;
90+
madvise(mapped_pages_address, mapped_pages_size, advice);
91+
static bool unmap_reusable = []() -> bool {
92+
char *result = getenv("OG_UNMAP_REUSABLE");
93+
if (result) {
94+
return atoi(result) != 0;
95+
}
96+
return false;
97+
}();
98+
if (unmap_reusable) {
99+
int protection = reusable ? PROT_NONE : (PROT_READ | PROT_WRITE);
100+
mprotect(mapped_pages_address, mapped_pages_size, protection);
101+
}
102+
_reusable_pages_num += reusable ? mapped_pages_size : -mapped_pages_size;
86103
}
87104

88-
ptr<page> table::alloc_page(zone *zone, uint32_t size) OG_NOEXCEPT {
89-
precondition_failure("TODO");
105+
// TO BE AUDITED
106+
ptr<page> table::alloc_page(zone *zone, uint32_t needed_size) OG_NOEXCEPT {
107+
lock();
108+
109+
uint32_t needed_pages = (needed_size + page_mask) / page_size;
110+
111+
// assume we'll have to append a new page
112+
uint32_t new_page_index = _page_maps.size() * pages_per_map;
113+
114+
// scan for consecutive free pages
115+
if (!_page_maps.empty() && _used_pages_num <= _page_maps.size() * pages_per_map) {
116+
117+
uint32_t start_map_index = _map_search_start;
118+
for (int i = 0; i < _page_maps.size(); i++) {
119+
int map_index = start_map_index + i;
120+
if (map_index >= _page_maps.size()) {
121+
map_index -= _page_maps.size(); // wrap around
122+
}
123+
124+
page_map_type free_pages_map = _page_maps[map_index].flip();
125+
while (free_pages_map.any()) {
126+
127+
int candidate_bit = std::countr_zero(static_cast<uint64_t>(free_pages_map.to_ullong()));
128+
129+
// scan ahead to find enough consecutive free pages
130+
bool found = false;
131+
if (needed_pages > 1) {
132+
for (int j = 1; j < needed_pages; j++) {
133+
int next_page_index = (map_index * pages_per_map) + candidate_bit + j;
134+
int next_map_index = next_page_index / pages_per_map;
135+
if (next_map_index == _page_maps.size()) {
136+
// There are not enough maps, but the trailing pages are contiguous so this page is
137+
// usable
138+
found = true;
139+
break;
140+
}
141+
if (_page_maps[next_map_index].test(next_page_index % pages_per_map)) {
142+
// next page is used, remove this page from free_pages_map
143+
free_pages_map.reset(candidate_bit);
144+
break;
145+
}
146+
}
147+
found = true;
148+
} else {
149+
// only need one page
150+
found = true;
151+
}
152+
153+
if (found) {
154+
new_page_index = (map_index * pages_per_map) + candidate_bit;
155+
_map_search_start = map_index;
156+
break;
157+
}
158+
}
159+
}
160+
}
161+
162+
// update maps
163+
for (int i = 0; i < needed_pages; i++) {
164+
uint32_t page_index = new_page_index + i;
165+
uint32_t map_index = page_index / pages_per_map;
166+
167+
if (map_index == _page_maps.size()) {
168+
_page_maps.push_back(0);
169+
_page_metadata_maps.push_back(0);
170+
} else if (_page_maps[map_index] == 0) {
171+
make_pages_reusable(page_index, false);
172+
}
173+
174+
_page_maps[map_index].set(page_index % pages_per_map);
175+
if (i == 0) {
176+
_page_metadata_maps[map_index].set(page_index % pages_per_map);
177+
}
178+
}
179+
180+
_used_pages_num += needed_pages;
181+
182+
uint32_t new_region_size = (new_page_index + needed_pages) * page_size;
183+
while (region_capacity() < new_region_size) {
184+
grow_region();
185+
}
186+
187+
// ptr offsets are "one"-based, so that we can treat 0 as null.
188+
ptr<page> new_page = ptr<page>((new_page_index + 1) * page_size);
189+
new_page->zone = zone;
190+
new_page->previous = nullptr;
191+
new_page->total = (needed_size + page_mask) & page_alignment;
192+
new_page->in_use = sizeof(page);
193+
unlock();
194+
return new_page;
90195
}
91196

197+
// TO BE AUDITED
92198
void table::dealloc_page_locked(ptr<page> page) OG_NOEXCEPT {
93-
precondition_failure("TODO");
199+
int32_t total_bytes = page->total;
200+
int32_t num_pages = total_bytes / page_size;
201+
202+
_used_pages_num -= num_pages;
203+
204+
// convert the page address (starts at 512) to an index (starts at 0)
205+
int32_t page_index = (page / page_size) - 1;
206+
for (int32_t i = 0; i != num_pages; i += 1) {
207+
208+
int32_t next_page_index = page_index + i;
209+
int32_t next_map_index = next_page_index / pages_per_map;
210+
211+
_page_maps[next_map_index].reset(next_page_index % pages_per_map);
212+
if (i == 0) {
213+
_page_metadata_maps[next_map_index].reset(next_page_index % pages_per_map);
214+
}
215+
216+
if (_page_maps[next_map_index].none()) {
217+
make_pages_reusable(next_page_index, true);
218+
}
219+
}
94220
}
95221

222+
// TO BE AUDITED
96223
uint64_t table::raw_page_seed(ptr<page> page) OG_NOEXCEPT {
97-
precondition_failure("TODO");
98-
// page.assert_valid();
99-
//
100-
// lock();
101-
//
102-
// uint32_t page_index = (page / page_size) - 1;
103-
// uint32_t map_index = page_index / pages_per_map;
104-
//
105-
// uint64_t result = 0;
106-
// if (map_index < _page_metadata_maps.size() && _page_metadata_maps[map_index].test(page_index % page_size)) {
107-
// auto raw_zone_info = page->zone->info().to_raw_value();
108-
// result = raw_zone_info | (1 < 8);
109-
// }
110-
//
111-
// unlock();
112-
//
113-
// return result;
224+
page.assert_valid(*this);
225+
lock();
226+
uint32_t page_index = (page / page_size) - 1;
227+
uint32_t map_index = page_index / pages_per_map;
228+
229+
// FIXME
230+
uint64_t result = 0;
231+
if (map_index < _page_metadata_maps.size() && _page_metadata_maps[map_index].test(page_index % page_size)) {
232+
auto raw_zone_info = page->zone->info().to_raw_value();
233+
result = raw_zone_info | (1 < 8);
234+
}
235+
unlock();
236+
return result;
114237
}
115238

116239
void table::print() const OG_NOEXCEPT {

Sources/OpenGraph_SPI/Data/table.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class table {
5959

6060
void grow_region() OG_NOEXCEPT;
6161

62-
void make_pages_reusable(uint32_t page_index, bool flag) OG_NOEXCEPT;
62+
void make_pages_reusable(uint32_t page_index, bool reusable) OG_NOEXCEPT;
6363

6464
ptr<page> alloc_page(zone *zone, uint32_t size) OG_NOEXCEPT;
6565

0 commit comments

Comments
 (0)