loom migration to support compressed pointers

This commit is contained in:
barter-simsum 2023-02-17 14:43:32 -05:00
parent 0966fb0195
commit 48e326ff03
8 changed files with 282 additions and 65 deletions

View File

@ -18,7 +18,9 @@ c3_w u3_Code;
// declarations of inline functions
//
c3_w c3_align_w(c3_w x, c3_w al, align_dir hilo);
void u3a_config_loom(c3_w ver_w);
c3_w c3_align_w(c3_w x, c3_w al, align_dir hilo); /* ;;: after rebasing on /vere, these should be declared somewhere else (the align functions) */
c3_d c3_align_d(c3_d x, c3_d al, align_dir hilo);
void *c3_align_p(void const * p, size_t al, align_dir hilo);
void *u3a_into(c3_w x);
@ -71,9 +73,9 @@ _box_count(c3_ws siz_ws) { }
#define _box_vaal(box_u) \
do { \
c3_dessert(((uintptr_t)u3a_boxto(box_u) \
& u3a_balign-1) == 0); \
& u3C.balign_d-1) == 0); \
c3_dessert((((u3a_box*)(box_u))->siz_w \
& u3a_walign-1) == 0); \
& u3C.walign_w-1) == 0); \
} while(0)
/* _box_slot(): select the right free list to search for a block.
@ -325,7 +327,7 @@ _ca_box_make_hat(c3_w len_w, c3_w ald_w, c3_w alp_w, c3_w use_w)
if ( c3y == u3a_is_north(u3R) ) {
all_p = u3R->hat_p;
pad_w = c3_align(all_p, ald_w, ALHI) - all_p;
siz_w = c3_align(len_w + pad_w, u3a_walign, ALHI);
siz_w = c3_align(len_w + pad_w, u3C.walign_w, ALHI);
// hand-inlined: siz_w >= u3a_open(u3R)
//
@ -337,7 +339,7 @@ _ca_box_make_hat(c3_w len_w, c3_w ald_w, c3_w alp_w, c3_w use_w)
else {
all_p = u3R->hat_p - len_w;
pad_w = all_p - c3_align(all_p, ald_w, ALLO);
siz_w = c3_align(len_w + pad_w, u3a_walign, ALHI);
siz_w = c3_align(len_w + pad_w, u3C.walign_w, ALHI);
// hand-inlined: siz_w >= u3a_open(u3R)
//
@ -526,7 +528,7 @@ _ca_willoc(c3_w len_w, c3_w ald_w, c3_w alp_w)
}
else { /* we got a non-null freelist */
c3_w pad_w = _me_align_pad(*pfr_p, ald_w, alp_w);
c3_w des_w = c3_align(siz_w + pad_w, u3a_walign, ALHI);
c3_w des_w = c3_align(siz_w + pad_w, u3C.walign_w, ALHI);
if ( 1 == ald_w ) c3_assert(0 == pad_w);
@ -624,8 +626,8 @@ _ca_walloc(c3_w len_w, c3_w ald_w, c3_w alp_w)
*/
req_w = len_w
+ (c3_wiseof(u3a_box) + 1)
+ u3a_walign
& ~(u3a_walign - 1)
+ u3C.walign_w
& ~(u3C.walign_w - 1)
- (c3_wiseof(u3a_box) + 1);
for (;;) {
ptr_v = _ca_willoc(req_w, ald_w, alp_w);
@ -675,8 +677,8 @@ u3a_wealloc(void* lag_v, c3_w len_w)
/* N.B: see related note in _ca_walloc */
req_w = len_w
+ (c3_wiseof(u3a_box) + 1)
+ u3a_walign
& ~(u3a_walign - 1)
+ u3C.walign_w
& ~(u3C.walign_w - 1)
- (c3_wiseof(u3a_box) + 1);
if ( !lag_v ) {
@ -743,17 +745,17 @@ u3a_wtrim(void* tox_v, c3_w old_w, c3_w len_w)
c3_w* box_w = (void*)u3a_botox(nov_w);
c3_w* end_w = c3_align(nov_w + len_w + 1, /* +1 for trailing allocation size */
u3a_balign,
u3C.balign_d,
ALHI);
c3_w asz_w = (end_w - box_w); /* total size in words of new allocation */
if (box_u->siz_w <= asz_w) return;
c3_w bsz_w = box_u->siz_w - asz_w; /* size diff in words between old and new */
c3_dessert(asz_w && ((asz_w & u3a_walign-1) == 0)); /* new allocation size must be non-zero and DWORD multiple */
c3_dessert(asz_w && ((asz_w & u3C.walign_w-1) == 0)); /* new allocation size must be non-zero and DWORD multiple */
c3_dessert(end_w < (box_w + box_u->siz_w)); /* desired alloc end must not exceed existing boundaries */
c3_dessert(((uintptr_t)end_w & u3a_balign-1) == 0); /* address of box getting freed must be DWORD aligned */
c3_dessert((bsz_w & u3a_walign-1) == 0); /* size of box getting freed must be DWORD multiple */
c3_dessert(((uintptr_t)end_w & u3C.balign_d-1) == 0); /* address of box getting freed must be DWORD aligned */
c3_dessert((bsz_w & u3C.walign_w-1) == 0); /* size of box getting freed must be DWORD multiple */
_box_attach(_box_make(end_w, bsz_w, 0)); /* free the unneeded space */
@ -1783,12 +1785,24 @@ u3a_rewritten_noun(u3_noun som)
return som;
}
u3_post som_p = u3a_rewritten(u3a_to_off(som));
/* If this is being called during a migration, one-bit pointer compression
needs to be temporarily enabled so the rewritten reference is compressed */
if (u3C.migration_state == MIG_REWRITE_COMPRESSED)
u3C.vits_w = 1;
if ( c3y == u3a_is_pug(som) ) {
return u3a_to_pug(som_p);
som_p = u3a_to_pug(som_p);
}
else {
return u3a_to_pom(som_p);
som_p = u3a_to_pom(som_p);
}
/* likewise, pointer compression is disabled until migration is complete */
if (u3C.migration_state == MIG_REWRITE_COMPRESSED)
u3C.vits_w = 0;
return som_p;
}
/* u3a_mark_mptr(): mark a malloc-allocated ptr for gc.

View File

@ -2,6 +2,7 @@
#define U3_ALLOCATE_H
#include "manage.h"
#include "options.h"
/** Constants.
**/
@ -9,17 +10,10 @@
*/
# define u3a_bits U3_OS_LoomBits /* 30 */
/* u3a_vits: number of virtual bits in a noun reference gained via shifting
/* u3a_vits_max: number of virtual bits in a reference gained via pointer
compression
*/
# define u3a_vits 1
/* u3a_walign: references into the loom are guaranteed to be word-aligned to:
*/
# define u3a_walign (1 << u3a_vits)
/* u3a_balign: u3a_walign in bytes
*/
# define u3a_balign (sizeof(c3_w)*u3a_walign)
# define u3a_vits_max 1
/* u3a_bits_max: max loom bex
*/
@ -31,11 +25,11 @@
/* u3a_pages: maximum number of pages in memory.
*/
# define u3a_pages (1ULL << (u3a_bits + u3a_vits - u3a_page) )
# define u3a_pages (1ULL << (u3a_bits + u3a_vits_max - u3a_page) )
/* u3a_words: maximum number of words in memory.
*/
# define u3a_words ( 1ULL << (u3a_bits + u3a_vits))
# define u3a_words ( 1ULL << (u3a_bits + u3a_vits_max ))
/* u3a_bytes: maximum number of bytes in memory.
*/
@ -360,7 +354,7 @@
# define _rod_vaal(rod_u) \
do { \
c3_dessert(((uintptr_t)((u3a_road*)(rod_u))->hat_p \
& u3a_walign-1) == 0); \
& u3C.walign_w-1) == 0); \
} while(0)
@ -381,6 +375,23 @@
/** inline functions.
**/
/* u3a_config_loom(): configure loom information by u3v version
*/
inline void u3a_config_loom(c3_w ver_w) {
switch (ver_w) {
case /* U3V_VER1 */ 1:
u3C.vits_w = 0;
break;
case /* U3V_VER2 */ 2:
u3C.vits_w = 1;
break;
default:
c3_assert(0);
}
u3C.walign_w = 1 << u3C.vits_w;
u3C.balign_d = sizeof(c3_w) * u3C.walign_w;
}
/* u3a_into(): convert loom offset [x] into generic pointer.
*/
@ -397,7 +408,7 @@
/* u3a_to_off(): mask off bits 30 and 31 from noun [som].
*/
inline c3_w u3a_to_off(c3_w som) {
return (som & 0x3fffffff) << u3a_vits;
return (som & 0x3fffffff) << u3C.vits_w;
}
/* u3a_to_ptr(): convert noun [som] into generic pointer into loom.
@ -415,15 +426,15 @@
/* u3a_to_pug(): set bit 31 of [off].
*/
inline c3_w u3a_to_pug(c3_w off) {
c3_dessert((off & u3a_walign-1) == 0);
return (off >> u3a_vits) | 0x80000000;
c3_dessert((off & u3C.walign_w-1) == 0);
return (off >> u3C.vits_w) | 0x80000000;
}
/* u3a_to_pom(): set bits 30 and 31 of [off].
*/
inline c3_w u3a_to_pom(c3_w off) {
c3_dessert((off & u3a_walign-1) == 0);
return (off >> u3a_vits) | 0xc0000000;
c3_dessert((off & u3C.walign_w-1) == 0);
return (off >> u3C.vits_w) | 0xc0000000;
}
/** road stack.

View File

@ -1017,8 +1017,15 @@ _ch_rewrite_node(u3h_node* han_u, c3_w lef_w)
else {
void* hav_v = u3h_slot_to_node(sot_w);
u3h_node* nod_u = u3to(u3h_node,u3a_rewritten(u3of(u3h_node,hav_v)));
if (u3C.migration_state == MIG_REWRITE_COMPRESSED)
u3C.vits_w = 1;
han_u->sot_w[i_w] = u3h_node_to_slot(nod_u);
if (u3C.migration_state == MIG_REWRITE_COMPRESSED)
u3C.vits_w = 0;
if ( 0 == lef_w ) {
_ch_rewrite_buck(hav_v);
} else {
@ -1050,8 +1057,15 @@ u3h_rewrite(u3p(u3h_root) har_p)
else if ( _(u3h_slot_is_node(sot_w)) ) {
u3h_node* han_u = u3h_slot_to_node(sot_w);
u3h_node* nod_u = u3to(u3h_node,u3a_rewritten(u3of(u3h_node,han_u)));
if (u3C.migration_state == MIG_REWRITE_COMPRESSED)
u3C.vits_w = 1;
har_u->sot_w[i_w] = u3h_node_to_slot(nod_u);
if (u3C.migration_state == MIG_REWRITE_COMPRESSED)
u3C.vits_w = 0;
_ch_rewrite_node(han_u, 25);
}
}

View File

@ -79,8 +79,8 @@
# define u3h_slot_is_node(sot) ((1 == ((sot) >> 30)) ? c3y : c3n)
# define u3h_slot_is_noun(sot) ((1 == ((sot) >> 31)) ? c3y : c3n)
# define u3h_slot_is_warm(sot) (((sot) & 0x40000000) ? c3y : c3n)
# define u3h_slot_to_node(sot) (u3a_into(((sot) & 0x3fffffff) << u3a_vits))
# define u3h_node_to_slot(ptr) ((u3a_outa((ptr)) >> u3a_vits) | 0x40000000)
# define u3h_slot_to_node(sot) (u3a_into(((sot) & 0x3fffffff) << u3C.vits_w))
# define u3h_node_to_slot(ptr) ((u3a_outa((ptr)) >> u3C.vits_w) | 0x40000000)
# define u3h_noun_be_warm(sot) ((sot) | 0x40000000)
# define u3h_noun_be_cold(sot) ((sot) & ~0x40000000)
# define u3h_slot_to_noun(sot) (0x40000000 | (sot))

View File

@ -488,7 +488,7 @@ _pave_parts(void)
static u3_road*
_pave_road(c3_w* rut_w, c3_w* mat_w, c3_w* cap_w, c3_w siz_w)
{
c3_dessert(((uintptr_t)rut_w & u3a_balign-1) == 0);
c3_dessert(((uintptr_t)rut_w & u3C.balign_d-1) == 0);
u3_road* rod_u = (void*) mat_w;
// enable in case of corruption
@ -529,8 +529,8 @@ _pave_north(c3_w* mem_w, c3_w siz_w, c3_w len_w)
// 00~~~|R|---|H|######|C|+++|M|~~~FF
// ^--u3R which _pave_road returns (u3H for home road)
//
c3_w* mat_w = c3_align(mem_w + len_w - siz_w, u3a_balign, ALLO);
c3_w* rut_w = c3_align(mem_w, u3a_balign, ALHI);
c3_w* mat_w = c3_align(mem_w + len_w - siz_w, u3C.balign_d, ALLO);
c3_w* rut_w = c3_align(mem_w, u3C.balign_d, ALHI);
c3_w* cap_w = mat_w;
return _pave_road(rut_w, mat_w, cap_w, siz_w);
@ -555,8 +555,8 @@ _pave_south(c3_w* mem_w, c3_w siz_w, c3_w len_w)
//
// 00~~~|M|+++|C|######|H|---|R|~~~FFF
// ^---u3R which _pave_road returns
c3_w* mat_w = c3_align(mem_w, u3a_balign, ALHI);
c3_w* rut_w = c3_align(mem_w + len_w, u3a_balign, ALLO);
c3_w* mat_w = c3_align(mem_w, u3C.balign_d, ALHI);
c3_w* rut_w = c3_align(mem_w + len_w, u3C.balign_d, ALLO);
c3_w* cap_w = mat_w + siz_w;
return _pave_road(rut_w, mat_w, cap_w, siz_w);
@ -567,9 +567,12 @@ _pave_south(c3_w* mem_w, c3_w siz_w, c3_w len_w)
static void
_pave_home(void)
{
c3_w* mem_w = u3_Loom + u3a_walign;
/* a pristine home road will always have compressed references */
u3a_config_loom(/* U3V_LATEST */ 2);
c3_w* mem_w = u3_Loom + u3C.walign_w;
c3_w siz_w = c3_wiseof(u3v_home);
c3_w len_w = u3C.wor_i - u3a_walign;
c3_w len_w = u3C.wor_i - u3C.walign_w;
u3H = (void *)_pave_north(mem_w, siz_w, len_w);
u3H->ver_w = u3v_version;
@ -586,34 +589,34 @@ STATIC_ASSERT( ((c3_wiseof(u3v_home) * 4) == sizeof(u3v_home)),
static void
_find_home(void)
{
c3_w ver_w = *(u3_Loom + u3C.wor_i - 1);
u3a_config_loom(ver_w);
// NB: the home road is always north
//
c3_w* mem_w = u3_Loom + u3a_walign;
c3_w* mem_w = u3_Loom + u3C.walign_w;
c3_w siz_w = c3_wiseof(u3v_home);
c3_w len_w = u3C.wor_i - u3a_walign;
c3_w* mat_w;
c3_w len_w = u3C.wor_i - u3C.walign_w;
c3_w* mat_w = c3_align(mem_w + len_w - siz_w, u3C.balign_d, ALLO);
{
c3_w ver_w = *((mem_w + len_w) - 1);
if ( u3v_version != ver_w ) {
fprintf(stderr, "loom: checkpoint version mismatch: "
"have %u, need %u\r\n",
ver_w,
u3v_version);
abort();
}
}
mat_w = c3_align(mem_w + len_w - siz_w, u3a_balign, ALLO);
u3H = (void *)mat_w;
u3R = &u3H->rod_u;
// this looks risky, but there are no legitimate scenarios
// where it's wrong
//
// this looks risky, but there are no legitimate scenarios where it's wrong
u3R->cap_p = u3R->mat_p = u3C.wor_i - c3_wiseof(*u3H);
if (u3v_version > ver_w) {
u3m_migrate(u3v_version);
u3a_config_loom(u3v_version);
}
else if ( u3v_version < ver_w ) {
fprintf(stderr, "loom: checkpoint version mismatch: "
"have %u, need %u\r\n",
ver_w,
u3v_version);
abort();
}
_rod_vaal(u3R);
}
@ -825,7 +828,7 @@ u3m_leap(c3_w pad_w)
}
pad_w += c3_wiseof(u3a_road);
len_w = u3a_open(u3R) - pad_w;
c3_align(len_w, u3a_walign, ALHI);
c3_align(len_w, u3C.walign_w, ALHI);
}
/* Allocate a region on the cap.
@ -2008,3 +2011,155 @@ u3m_pack(void)
return (u3a_open(u3R) - pre_w);
}
static void
_migrate_reclaim()
{
fprintf(stderr, "loom: migration reclaim\r\n");
u3m_reclaim();
}
static void
_migrate_seek(const u3a_road *rod_u)
{
/*
very much like u3a_pack_seek with the following changes:
- there is no need to account for free space as |pack is performed before
the migration
- odd sized boxes will be padded by one word to achieve an even size
- rut will be moved from one word ahead of u3_Loom to two words ahead
*/
c3_w * box_w = u3a_into(rod_u->rut_p);
c3_w * end_w = u3a_into(rod_u->hat_p);
u3_post new_p = (rod_u->rut_p + 1 + c3_wiseof(u3a_box));
u3a_box * box_u = (void *)box_w;
fprintf(stderr, "loom: migration seek\r\n");
for (; box_w < end_w
; box_w += box_u->siz_w
, box_u = (void*)box_w)
{
if (!box_u->use_w)
continue;
c3_assert(box_u->siz_w);
c3_assert(box_u->use_w);
box_w[box_u->siz_w - 1] = new_p;
new_p = c3_align(new_p + box_u->siz_w, 2, ALHI);
}
}
static void
_migrate_rewrite()
{
fprintf(stderr, "loom: migration rewrite\r\n");
/* So that rewritten pointers are compressed, this flag is set */
u3C.migration_state = MIG_REWRITE_COMPRESSED;
_cm_pack_rewrite();
u3C.migration_state = MIG_NONE;
}
static void
_migrate_move(u3a_road *rod_u)
{
fprintf(stderr, "loom: migration move\r\n");
c3_z hiz_z = u3a_heap(rod_u) * sizeof(c3_w);
/* calculate required shift distance to prevent write head overlapping read head */
c3_w off_w = 1; /* at least 1 word because u3R->rut_p migrates from 1 to 2 */
for (u3a_box *box_u = u3a_into(rod_u->rut_p)
; (void *)box_u < u3a_into(rod_u->hat_p)
; box_u = (void *)((c3_w *)box_u + box_u->siz_w))
off_w += box_u->siz_w & 1; /* odd-sized boxes are padded by one word */
/* shift */
memmove(u3a_into(u3H->rod_u.rut_p + off_w),
u3a_into(u3H->rod_u.rut_p),
hiz_z);
/* manually zero the former rut */
*(c3_w *)u3a_into(rod_u->rut_p) = 0;
/* relocate boxes to DWORD-aligned addresses stored in trailing size word */
c3_w *box_w = u3a_into(rod_u->rut_p + off_w);
c3_w *end_w = u3a_into(rod_u->hat_p + off_w);
u3a_box *old_u = (void *)box_w;
c3_w siz_w = old_u->siz_w;
u3p(c3_w) new_p = rod_u->rut_p + 1 + c3_wiseof(u3a_box);
c3_w *new_w;
for (; box_w < end_w
; box_w += siz_w
, old_u = (void *)box_w
, siz_w = old_u->siz_w) {
old_u->use_w &= 0x7fffffff;
if (!old_u->use_w)
continue;
new_w = (void *)u3a_botox(u3a_into(new_p));
c3_assert(box_w[siz_w - 1] == new_p);
c3_assert(new_w <= box_w);
c3_w i_w;
for (i_w = 0; i_w < siz_w - 1; i_w++)
new_w[i_w] = box_w[i_w];
if (siz_w & 1) {
new_w[i_w++] = 0; /* pad odd sized boxes */
new_w[i_w++] = siz_w + 1; /* restore trailing size word */
new_w[0] = siz_w + 1; /* and the leading size word */
}
else {
new_w[i_w++] = siz_w;
}
new_p += i_w;
}
/* restore proper heap state */
rod_u->rut_p = 2;
rod_u->hat_p = new_p - c3_wiseof(u3a_box);
/* like |pack, clear the free lists and cell allocator */
for (c3_w i_w = 0; i_w < u3a_fbox_no; i_w++)
u3R->all.fre_p[i_w] = 0;
u3R->all.fre_w = 0;
u3R->all.cel_p = 0;
}
/* u3m_migrate: perform loom migration if necessary.
ver_w - target version
*/
void
u3m_migrate(c3_w ver_w)
{
if (u3H->ver_w == ver_w)
return;
/* 1 -> 2 is all that is currently supported */
c3_dessert(u3H->ver_w == 1 &&
ver_w == 2);
/* only home road migration is supported */
c3_dessert((uintptr_t)u3H == (uintptr_t)u3R);
fprintf(stderr, "loom: migration running. This may take several minutes to perform\r\n");
fprintf(stderr, "loom: have version: %" PRIc3_w " migrating to version: %" PRIc3_w "\r\n",
u3H->ver_w, ver_w);
/* packing first simplifies migration logic and minimizes required buffer space */
u3m_pack();
/* perform the migration in a pattern similar to |pack */
_migrate_reclaim();
_migrate_seek(&u3H->rod_u);
_migrate_rewrite();
_migrate_move(&u3H->rod_u);
/* finally update the version and commit to disk */
u3H->ver_w = ver_w;
u3e_save();
}

View File

@ -159,4 +159,10 @@
c3_w
u3m_pack(void);
/* u3m_migrate: perform loom migration if necessary.
ver_w - target version
*/
void
u3m_migrate(c3_w ver_w);
#endif /* ifndef U3_MANAGE_H */

View File

@ -14,6 +14,14 @@
u3_noun who; // single identity
c3_c* dir_c; // execution directory (pier)
c3_w wag_w; // flags (both ways)
c3_w vits_w; // number of virtual bits in reference
c3_w walign_w; // word alignment
c3_d balign_d; // byte alignment
enum {
MIG_NONE,
MIG_REWRITE_COMPRESSED,
} migration_state;
size_t wor_i; // loom word-length (<= u3a_words)
void (*stderr_log_f)(c3_c*); // errors from c code
void (*slog_f)(u3_noun); // function pointer for slog
@ -45,5 +53,4 @@
extern u3o_config u3o_Config;
# define u3C u3o_Config
#endif /* ifndef U3_OPTIONS_H */

View File

@ -37,7 +37,17 @@
/** Constants.
**/
# define u3v_version 1
/*
version change log:
1 -> 2:
- 1 bit pointer compression to enable 8G loom
*/
/* ;;: TODO: refactor so that this is possible -- dependency loop if used in options.h */
/* # define U3V_VER1 1 */
/* # define U3V_VER2 2 */
/* # define u3v_version U3V_VER2 */
# define u3v_version 2
/** Functions.
**/