Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

serf: adds new, stateful memory-pressure thresholds #546

Merged
merged 2 commits into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 73 additions & 34 deletions pkg/vere/serf.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,25 @@ :: next steps:
--
*/

/* serf memory-threshold levels
*/
enum {
_serf_mas_init = 0, // initial
_serf_mas_hit1 = 1, // past low threshold
_serf_mas_hit0 = 2 // have high threshold
};

/* serf post-op flags
*/
enum {
_serf_fag_none = 0, // nothing to do
_serf_fag_hit1 = 1 << 0, // hit low threshold
_serf_fag_hit0 = 1 << 1, // hit high threshold
_serf_fag_mute = 1 << 2, // mutated state
_serf_fag_much = 1 << 3, // bytecode hack
_serf_fag_vega = 1 << 4 // kernel reset
};

/* _serf_grab(): garbage collect, checking for profiling. RETAIN.
*/
static void
Expand Down Expand Up @@ -174,38 +193,42 @@ u3_serf_grab(void)
void
u3_serf_post(u3_serf* sef_u)
{
if ( c3y == sef_u->rec_o ) {
if ( sef_u->fag_w & (_serf_fag_hit1|_serf_fag_much|_serf_fag_vega) ) {
u3m_reclaim();
sef_u->rec_o = c3n;
}

// XX this runs on replay too, |mass s/b elsewhere
//
if ( c3y == sef_u->mut_o ) {
if ( sef_u->fag_w & _serf_fag_mute ) {
_serf_grab(sef_u->sac);
sef_u->sac = u3_nul;
sef_u->mut_o = c3n;
}

if ( c3y == sef_u->pac_o ) {
if ( sef_u->fag_w & _serf_fag_hit0 ) {
u3a_print_memory(stderr, "serf: pack: gained", u3m_pack());
u3l_log("");
sef_u->pac_o = c3n;
}

if ( u3C.wag_w & u3o_toss ) {
u3m_toss();
}

sef_u->fag_w = _serf_fag_none;
}

/* _serf_curb(): check for memory threshold
*/
static inline c3_t
_serf_curb(c3_w pre_w, c3_w pos_w, c3_w hes_w)
{
return (pre_w > hes_w) && (pos_w <= hes_w);
}

/* _serf_sure_feck(): event succeeded, send effects.
*/
static u3_noun
_serf_sure_feck(u3_serf* sef_u, c3_w pre_w, u3_noun vir)
{
c3_o rec_o = c3n;
c3_o pac_o = c3n;

// intercept |mass, observe |reset
//
{
Expand Down Expand Up @@ -236,7 +259,7 @@ _serf_sure_feck(u3_serf* sef_u, c3_w pre_w, u3_noun vir)
// reclaim memory from persistent caches on |reset
//
if ( c3__vega == u3h(fec) ) {
rec_o = c3y;
sef_u->fag_w |= _serf_fag_vega;
}

riv = u3t(riv);
Expand All @@ -253,39 +276,60 @@ _serf_sure_feck(u3_serf* sef_u, c3_w pre_w, u3_noun vir)
// For future flexibility, the urgency of the notification is represented
// by a *decreasing* number: 0 is maximally urgent, 1 less so, &c.
//
// high-priority: 2^22 contiguous words remaining (~8 MB)
// high-priority: 2^25 contiguous words remaining (~128 MB)
// low-priority: 2^27 contiguous words remaining (~536 MB)
// XX maybe use 2^23 (~16 MB) and 2^26 (~268 MB?
//
// once a threshold is hit, it's not a candidate to be hit again
// until memory usage falls below:
//
// high-priority: 2^26 contiguous words remaining (~256 MB)
// low-priority: 2^26 + 2^27 contiguous words remaining (~768 MB)
//
// XX these thresholds should trigger notifications sent to the king
// instead of directly triggering these remedial actions.
//
{
u3_noun pri = u3_none;
c3_w pos_w = u3a_open(u3R);
c3_w low_w = (1 << 27);
c3_w hig_w = (1 << 22);
c3_w pos_w = u3a_open(u3R);

if ( (pre_w > low_w) && !(pos_w > low_w) ) {
// XX set flag(s) in u3V so we don't repeat endlessly?
//
pac_o = c3y;
rec_o = c3y;
pri = 1;
// if contiguous free space shrunk, check thresholds
// (and track state to avoid thrashing)
//
if ( pos_w < pre_w ) {
if ( (_serf_mas_hit0 != sef_u->mas_w)
&& _serf_curb(pre_w, pos_w, 1 << 25) )
{
sef_u->mas_w = _serf_mas_hit0;
sef_u->fag_w |= _serf_fag_hit0;
pri = 0;
}
else if ( (_serf_mas_init == sef_u->mas_w)
&& _serf_curb(pre_w, pos_w, 1 << 27) )
{
sef_u->mas_w = _serf_mas_hit1;
sef_u->fag_w |= _serf_fag_hit1;
pri = 1;
}
}
else if ( (pre_w > hig_w) && !(pos_w > hig_w) ) {
pac_o = c3y;
rec_o = c3y;
pri = 0;
else if ( _serf_mas_init != sef_u->mas_w ) {
if ( ((1 << 26) + (1 << 27)) < pos_w ) {
sef_u->mas_w = _serf_mas_init;
}
else if ( (_serf_mas_hit0 == sef_u->mas_w)
&& ((1 << 26) < pos_w) )
{
sef_u->mas_w = _serf_mas_hit1;
}
}

// reclaim memory from persistent caches periodically
//
// XX this is a hack to work two things
// - bytecode caches grow rapidly and can't be simply capped
// - we don't make very effective use of our free lists
//
else if ( 0 == (sef_u->dun_d % 1000ULL) ) {
rec_o = c3y;
if ( !(sef_u->dun_d % 1024ULL) ) {
sef_u->fag_w |= _serf_fag_much;
}

// notify daemon of memory pressure via "fake" effect
Expand All @@ -297,9 +341,6 @@ _serf_sure_feck(u3_serf* sef_u, c3_w pre_w, u3_noun vir)
}
}

sef_u->rec_o = c3o(sef_u->rec_o, rec_o);
sef_u->pac_o = c3o(sef_u->pac_o, pac_o);

return vir;
}

Expand All @@ -314,7 +355,7 @@ _serf_sure_core(u3_serf* sef_u, u3_noun cor)
u3A->roc = cor;
u3A->eve_d = sef_u->dun_d;
sef_u->mug_l = u3r_mug(u3A->roc);
sef_u->mut_o = c3y;
sef_u->fag_w |= _serf_fag_mute;
}

/* _serf_sure(): event succeeded, save state and process effects.
Expand Down Expand Up @@ -1016,9 +1057,7 @@ u3_serf_init(u3_serf* sef_u)
// }
// }

sef_u->pac_o = c3n;
sef_u->rec_o = c3n;
sef_u->mut_o = c3n;
sef_u->fag_w = _serf_fag_none;
sef_u->sac = u3_nul;

return rip;
Expand Down
5 changes: 2 additions & 3 deletions pkg/vere/serf.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@
c3_d sen_d; // last event requested
c3_d dun_d; // last event processed
c3_l mug_l; // hash of state
c3_o pac_o; // pack kernel
c3_o rec_o; // reclaim cache
c3_o mut_o; // mutated kerne
c3_w mas_w; // memory threshold state
c3_w fag_w; // post-op flags
u3_noun sac; // space measurementl
void (*xit_f)(void); // exit callback
} u3_serf;
Expand Down