Skip to content

Commit

Permalink
serf: adds new, stateful memory-pressure thresholds (#546)
Browse files Browse the repository at this point in the history
This PR adjusts the serf's memory-pressure thresholds, adds state to
track threshold events and avoid thrashing ("schmitt trigger"), and
refactors post-event operation to use a bitmap and track operations more
granularly.

These changes are useful on there own, and necessary for adding
memory-pressure-based trimming to #508.
  • Loading branch information
pkova authored Nov 8, 2023
2 parents 7e3660a + 280ac6a commit 936a61a
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 37 deletions.
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

0 comments on commit 936a61a

Please sign in to comment.