From 51bc2ad8e643d606dcfde3f587124cb613dc4525 Mon Sep 17 00:00:00 2001 From: ionut Date: Fri, 8 May 2026 03:40:02 +0300 Subject: [PATCH] call budgets match OC logic --- src/main.c | 20 ++++++----- src/neonucleus.c | 92 +++++++++++++++++++++++------------------------- src/neonucleus.h | 21 +++++++---- 3 files changed, 71 insertions(+), 62 deletions(-) diff --git a/src/main.c b/src/main.c index 38df772..58733d3 100644 --- a/src/main.c +++ b/src/main.c @@ -564,7 +564,7 @@ int main(int argc, char **argv) { ncl_setCLabel(testFlash, "Flash Storage"); size_t ramTotal = 0; - ramTotal += 4 * nn_ramSizes[5]; + ramTotal += 4 * nn_ramSizes[7]; //ramTotal += nn_ramSizes[0]; SetExitKey(KEY_NULL); @@ -578,10 +578,6 @@ int main(int argc, char **argv) { if(getenv("NN_TICKDELAY") != NULL) { tickDelay = atof(getenv("NN_TICKDELAY")); } - if(getenv("NN_FAST") != NULL) { - tickDelay = 0; - noIdle = true; - } struct {int key; nn_codepoint unicode;} keybuf[512]; memset(keybuf, 0, sizeof(keybuf)); @@ -591,22 +587,28 @@ int main(int argc, char **argv) { double nextSecond = 0; double wattage = 0; - nn_Component *screen = ncl_createScreen(u, NULL, &nn_defaultScreens[2]); - nn_Component *gpuCard = ncl_createGPU(u, NULL, &nn_defaultGPUs[2]); + nn_Component *screen = ncl_createScreen(u, NULL, &nn_defaultScreens[3]); + nn_Component *gpuCard = ncl_createGPU(u, NULL, &nn_defaultGPUs[3]); nn_Component *keyboard = nn_createComponent( u, "mainKB", "keyboard"); ncl_ScreenState *scrstate = nn_getComponentState(screen); ncl_mountKeyboard(scrstate, "mainKB"); - nn_Computer *c = nn_createComputer(u, NULL, NULL, ramTotal, 256, 256); + // we assume server basically + nn_Computer *c = nn_createComputer(u, NULL, NULL, ramTotal, nn_defaultComponentLimits[3] * 4, 256); nn_Environment cEnv = { .userdata = NULL, .handler = ne_env, }; nn_setComputerEnvironment(c, cEnv); - nn_setCallBudget(c, 0); + nn_setCallBudget(c, nn_defaultCallBudgets[3]); nn_setTotalEnergy(c, allEnergy); + if(getenv("NN_FAST") != NULL) { + tickDelay = 0; + noIdle = true; + nn_setCallBudget(c, 0); + } nn_setArchitecture(c, &arch); nn_addSupportedArchitecture(c, &arch); diff --git a/src/neonucleus.c b/src/neonucleus.c index 3d2aa40..5e0d8f8 100644 --- a/src/neonucleus.c +++ b/src/neonucleus.c @@ -948,7 +948,6 @@ typedef struct nn_Universe { typedef struct nn_ComponentEntry { const char *address; nn_Component *comp; - double budgetUsed; int slot; } nn_ComponentEntry; @@ -1080,8 +1079,8 @@ typedef struct nn_Computer { void *archState; nn_Architecture arch; nn_Architecture desiredArch; - size_t callBudget; - size_t totalCallBudget; + double callBudget; + double totalCallBudget; nn_HashMap components; nn_DeviceInfoArray deviceInfo; double totalEnergy; @@ -1200,7 +1199,7 @@ nn_Computer *nn_createComputer(nn_Universe *universe, void *userdata, const char c->desiredArch.name = NULL; c->archState = NULL; - c->totalCallBudget = 10000; + c->totalCallBudget = 1; c->callBudget = c->totalCallBudget; if(nn_hashInit(&c->components, maxComponents, ctx, &nn_componentHasher)) { @@ -2065,7 +2064,6 @@ nn_Exit nn_mountComponent(nn_Computer *c, nn_Component *comp, int slot, bool sil .address = comp->address, .comp = comp, .slot = slot, - .budgetUsed = 0, }; if(!nn_hashPut(&c->components, &ent)) return NN_ELIMIT; nn_retainComponent(comp); @@ -2165,6 +2163,9 @@ nn_Exit nn_invokeComponent(nn_Computer *computer, const char *compAddress, const nn_pop(computer); } + // TODO: configurable cost + nn_costComponent(computer, 22000); + nn_ComponentRequest req; req.ctx = &c->universe->ctx; req.computer = computer; @@ -2486,17 +2487,20 @@ static void nn_dropValue(nn_Value val) { } } -// TODO: call +double nn_defaultCallBudgets[4] = { 0.5, 1, 1.5, 2 }; +double nn_unlimitedCallBudget = 0; +size_t nn_defaultComponentLimits[4] = { 8, 12, 16, 20 }; +size_t nn_creativeComponentLimit = 1024; -void nn_setCallBudget(nn_Computer *computer, size_t budget) { +void nn_setCallBudget(nn_Computer *computer, double budget) { computer->totalCallBudget = budget; } -size_t nn_getCallBudget(nn_Computer *computer) { +double nn_getCallBudget(nn_Computer *computer) { return computer->totalCallBudget; } -size_t nn_callBudgetRemaining(nn_Computer *computer) { +double nn_callBudgetRemaining(nn_Computer *computer) { return computer->callBudget; } @@ -2505,30 +2509,24 @@ void nn_resetCallBudget(nn_Computer *computer) { } bool nn_componentsOverused(nn_Computer *computer) { - for(nn_ComponentEntry *c = nn_hashIterate(&computer->components, NULL); c != NULL; c = nn_hashIterate(&computer->components, c)) { - if(c->budgetUsed >= NN_COMPONENT_CALLBUDGET) return true; - } - if(computer->totalCallBudget == 0) return false; - return computer->callBudget == 0; + if(computer->totalCallBudget <= 0) return false; + return computer->callBudget <= 0; } void nn_resetComponentBudgets(nn_Computer *computer) { - for(nn_ComponentEntry *c = nn_hashIterate(&computer->components, NULL); c != NULL; c = nn_hashIterate(&computer->components, c)) { - c->budgetUsed = 0; - } computer->callBudget = computer->totalCallBudget; } -bool nn_costComponent(nn_Computer *computer, const char *address, double perTick) { - return nn_costComponentN(computer, address, 1, perTick); + +bool nn_costComponent(nn_Computer *computer, double perTick) { + return nn_costComponentN(computer, 1, perTick); } -bool nn_costComponentN(nn_Computer *computer, const char *address, double amount, double perTick) { +bool nn_costComponentN(nn_Computer *computer, double amount, double perTick) { // this means 0 per tick means free if(perTick == 0) return false; - nn_ComponentEntry *c = nn_getInternalComponent(computer, address); - if(c == NULL) return false; - c->budgetUsed += (NN_COMPONENT_CALLBUDGET * amount) / perTick; - return c->budgetUsed >= NN_COMPONENT_CALLBUDGET; + computer->callBudget -= amount / perTick; + if(computer->callBudget < 0) computer->callBudget = 0; + return computer->callBudget <= 0; } bool nn_checkstack(nn_Computer *computer, size_t amount) { @@ -4556,7 +4554,7 @@ static nn_Exit nn_fsHandler(nn_ComponentRequest *req) { e = state->handler(&freq); if(e) return e; req->returnCount = 1; - nn_costComponent(C, req->compAddress, state->fs.opensPerTick); + nn_costComponent(C, state->fs.opensPerTick); return nn_pushinteger(C, freq.fd); } if(method == NN_FSNUM_READ) { @@ -4581,7 +4579,7 @@ static nn_Exit nn_fsHandler(nn_ComponentRequest *req) { nn_free(ctx, buf, state->fs.maxReadSize); return NN_OK; } - nn_costComponent(C, req->compAddress, state->fs.readsPerTick); + nn_costComponent(C, state->fs.readsPerTick); nn_removeEnergy(C, state->fs.dataEnergyCost * freq.read.len); req->returnCount = 1; e = nn_pushlstring(C, buf, freq.read.len); @@ -4597,7 +4595,7 @@ static nn_Exit nn_fsHandler(nn_ComponentRequest *req) { e = state->handler(&freq); if(e) return e; req->returnCount = 1; - nn_costComponent(C, req->compAddress, state->fs.writesPerTick); + nn_costComponent(C, state->fs.writesPerTick); nn_removeEnergy(C, state->fs.dataEnergyCost * freq.write.len); return nn_pushbool(C, true); } @@ -4627,7 +4625,7 @@ static nn_Exit nn_fsHandler(nn_ComponentRequest *req) { e = state->handler(&freq); if(e) return e; req->returnCount = 1; - nn_costComponent(C, req->compAddress, state->fs.readsPerTick); + nn_costComponent(C, state->fs.readsPerTick); return nn_pushinteger(C, freq.seek.off); } if(method == NN_FSNUM_CLOSE) { @@ -4961,7 +4959,7 @@ static nn_Exit nn_drvHandler(nn_ComponentRequest *request) { curPos = dreq.curpos; nn_drive_seekPenalty(C, curPos, sec, &state->drive); - nn_costComponent(C, request->compAddress, state->drive.readsPerTick); + nn_costComponent(C, state->drive.readsPerTick); nn_removeEnergy(C, state->drive.dataEnergyCost * ss); char *sector = nn_alloc(ctx, ss); @@ -5170,7 +5168,7 @@ static nn_Exit nn_flashHandler(nn_ComponentRequest *request) { nn_setError(C, "sector out of bounds"); return NN_EBADCALL; } - nn_costComponent(C, request->compAddress, state->flash.readsPerTick); + nn_costComponent(C, state->flash.readsPerTick); nn_removeEnergy(C, state->flash.dataEnergyCost * ss); char *sector = nn_alloc(ctx, ss); @@ -5205,7 +5203,7 @@ static nn_Exit nn_flashHandler(nn_ComponentRequest *request) { return NN_EBADCALL; } - nn_costComponent(C, request->compAddress, state->flash.writesPerTick); + nn_costComponent(C, state->flash.writesPerTick); nn_removeEnergy(C, state->flash.dataEnergyCost * ss); size_t len; @@ -5650,7 +5648,7 @@ static nn_Exit nn_gpuHandler(nn_ComponentRequest *req) { } // setBackground if(m == NN_GPUNUM_SETBG) { - if(isScreen) nn_costComponent(C, req->compAddress, cls->gpu.setBackgroundPerTick); + if(isScreen) nn_costComponent(C, cls->gpu.setBackgroundPerTick); if(nn_checknumber(C, 0, "bad argument #1 (number expected)")) return NN_EBADCALL; @@ -5685,7 +5683,7 @@ static nn_Exit nn_gpuHandler(nn_ComponentRequest *req) { } // setForeground if(m == NN_GPUNUM_SETFG) { - if(isScreen) nn_costComponent(C, req->compAddress, cls->gpu.setForegroundPerTick); + if(isScreen) nn_costComponent(C, cls->gpu.setForegroundPerTick); if(nn_checknumber(C, 0, "bad argument #1 (number expected)")) return NN_EBADCALL; @@ -5907,7 +5905,7 @@ static nn_Exit nn_gpuHandler(nn_ComponentRequest *req) { if(e) return e; req->returnCount = 1; if(isScreen) { - nn_costComponent(C, req->compAddress, cls->gpu.setPerTick); + nn_costComponent(C, cls->gpu.setPerTick); nn_removeEnergy(C, cls->gpu.energyPerWrite * g.set.len); } return nn_pushbool(C, true); @@ -5935,7 +5933,7 @@ static nn_Exit nn_gpuHandler(nn_ComponentRequest *req) { if(e) return e; req->returnCount = 1; if(isScreen) { - nn_costComponent(C, req->compAddress, cls->gpu.copyPerTick); + nn_costComponent(C, cls->gpu.copyPerTick); nn_removeEnergy(C, cls->gpu.energyPerWrite * g.copy.w * g.copy.h); } return nn_pushbool(C, true); @@ -5966,7 +5964,7 @@ static nn_Exit nn_gpuHandler(nn_ComponentRequest *req) { if(e) return e; req->returnCount = 1; if(isScreen) { - nn_costComponent(C, req->compAddress, cls->gpu.fillPerTick); + nn_costComponent(C, cls->gpu.fillPerTick); nn_removeEnergy(C, (g.fill.codepoint == ' ' ? cls->gpu.energyPerClear : cls->gpu.energyPerWrite) * g.fill.w * g.fill.h); } return nn_pushbool(C, true); @@ -6082,7 +6080,7 @@ static nn_Exit nn_gpuHandler(nn_ComponentRequest *req) { if(g.bitblt.h > g.gpu->maxHeight) g.bitblt.h = g.gpu->maxHeight; if(g.bitblt.dst == 0 || g.bitblt.src == 0) { // taxed as a copy - nn_costComponent(C, req->compAddress, g.gpu->copyPerTick); + nn_costComponent(C, g.gpu->copyPerTick); nn_removeEnergy(C, g.gpu->energyPerWrite * g.bitblt.w * g.bitblt.h); } e = cls->handler(&g); @@ -6508,7 +6506,7 @@ static nn_Exit nn_dataHandler(nn_ComponentRequest *req) { // TODO: the cool methods if(method == NN_DATANUM_ENCODE64) { - nn_costComponent(C, req->compAddress, dataCard.base64PerTick); + nn_costComponent(C, dataCard.base64PerTick); if(nn_checkstring(C, 0, "bad argument #1 (string expected)")) return NN_EBADCALL; dreq.action = NN_DATA_ENCODE64; dreq.data = nn_tolstring(C, 0, &dreq.datalen); @@ -6520,7 +6518,7 @@ static nn_Exit nn_dataHandler(nn_ComponentRequest *req) { return NN_OK; } if(method == NN_DATANUM_DECODE64) { - nn_costComponent(C, req->compAddress, dataCard.base64PerTick); + nn_costComponent(C, dataCard.base64PerTick); if(nn_checkstring(C, 0, "bad argument #1 (string expected)")) return NN_EBADCALL; dreq.action = NN_DATA_DECODE64; dreq.data = nn_tolstring(C, 0, &dreq.datalen); @@ -6532,7 +6530,7 @@ static nn_Exit nn_dataHandler(nn_ComponentRequest *req) { return NN_OK; } if(method == NN_DATANUM_DEFLATE) { - nn_costComponent(C, req->compAddress, dataCard.deflatingPerTick); + nn_costComponent(C, dataCard.deflatingPerTick); if(nn_checkstring(C, 0, "bad argument #1 (string expected)")) return NN_EBADCALL; dreq.action = NN_DATA_DEFLATE; dreq.data = nn_tolstring(C, 0, &dreq.datalen); @@ -6544,7 +6542,7 @@ static nn_Exit nn_dataHandler(nn_ComponentRequest *req) { return NN_OK; } if(method == NN_DATANUM_INFLATE) { - nn_costComponent(C, req->compAddress, dataCard.deflatingPerTick); + nn_costComponent(C, dataCard.deflatingPerTick); if(nn_checkstring(C, 0, "bad argument #1 (string expected)")) return NN_EBADCALL; dreq.action = NN_DATA_INFLATE; dreq.data = nn_tolstring(C, 0, &dreq.datalen); @@ -6556,7 +6554,7 @@ static nn_Exit nn_dataHandler(nn_ComponentRequest *req) { return NN_OK; } if(method == NN_DATANUM_CRC32) { - nn_costComponent(C, req->compAddress, dataCard.crc32PerTick); + nn_costComponent(C, dataCard.crc32PerTick); if(nn_checkstring(C, 0, "bad argument #1 (string expected)")) return NN_EBADCALL; dreq.action = NN_DATA_CRC32; dreq.crc32.data = nn_tolstring(C, 0, &dreq.crc32.datalen); @@ -6568,7 +6566,7 @@ static nn_Exit nn_dataHandler(nn_ComponentRequest *req) { return nn_pushlstring(C, dreq.crc32.checksum, 4); } if(method == NN_DATANUM_MD5) { - nn_costComponent(C, req->compAddress, dataCard.md5PerTick); + nn_costComponent(C, dataCard.md5PerTick); if(nn_checkstring(C, 0, "bad argument #1 (string expected)")) return NN_EBADCALL; dreq.action = NN_DATA_MD5; dreq.md5.data = nn_tolstring(C, 0, &dreq.md5.datalen); @@ -6580,7 +6578,7 @@ static nn_Exit nn_dataHandler(nn_ComponentRequest *req) { return nn_pushlstring(C, dreq.md5.checksum, 16); } if(method == NN_DATANUM_SHA256) { - nn_costComponent(C, req->compAddress, dataCard.sha256PerTick); + nn_costComponent(C, dataCard.sha256PerTick); if(nn_checkstring(C, 0, "bad argument #1 (string expected)")) return NN_EBADCALL; dreq.action = NN_DATA_SHA256; dreq.sha256.data = nn_tolstring(C, 0, &dreq.sha256.datalen); @@ -6592,7 +6590,7 @@ static nn_Exit nn_dataHandler(nn_ComponentRequest *req) { return nn_pushlstring(C, dreq.sha256.checksum, 32); } if(method == NN_DATANUM_RANDOM) { - nn_costComponent(C, req->compAddress, dataCard.randomPerTick); + nn_costComponent(C, dataCard.randomPerTick); if(nn_checkinteger(C, 0, "bad argument #1 (integer expected)")) return NN_EBADCALL; intptr_t n = nn_tointeger(C, 0); if(n <= 0) { @@ -6615,7 +6613,7 @@ static nn_Exit nn_dataHandler(nn_ComponentRequest *req) { return e; } if(method == NN_DATANUM_ENCRYPT) { - nn_costComponent(C, req->compAddress, dataCard.encryptPerTick); + nn_costComponent(C, dataCard.encryptPerTick); if(nn_checkstring(C, 0, "bad argument #1 (string expected)")) return NN_EBADCALL; if(nn_checkstring(C, 1, "bad argument #2 (string expected)")) return NN_EBADCALL; if(nn_checkstring(C, 2, "bad argument #3 (string expected)")) return NN_EBADCALL; @@ -6640,7 +6638,7 @@ static nn_Exit nn_dataHandler(nn_ComponentRequest *req) { return NN_OK; } if(method == NN_DATANUM_DECRYPT) { - nn_costComponent(C, req->compAddress, dataCard.encryptPerTick); + nn_costComponent(C, dataCard.encryptPerTick); if(nn_checkstring(C, 0, "bad argument #1 (string expected)")) return NN_EBADCALL; if(nn_checkstring(C, 1, "bad argument #2 (string expected)")) return NN_EBADCALL; if(nn_checkstring(C, 2, "bad argument #3 (string expected)")) return NN_EBADCALL; diff --git a/src/neonucleus.h b/src/neonucleus.h index a28294f..c94d866 100644 --- a/src/neonucleus.h +++ b/src/neonucleus.h @@ -828,15 +828,24 @@ nn_Exit nn_serializeUserdata(nn_Computer *computer, size_t userdata); // NOTE: if the component does not exist, or the userdata index is already taken, this errors. nn_Exit nn_deserializeUserdata(nn_Computer *computer, size_t userdata, const char *compAddress, const char *buf, size_t len); +// default call budgets for 4 tiers of CPUs +extern double nn_defaultCallBudgets[4]; +// the call budget of a creative CPU +extern double nn_unlimitedCallBudget; +// default component limits for 4 tiers of component buses / CPUs +extern size_t nn_defaultComponentLimits[4]; +// the component limit of a creative component bus +extern size_t nn_creativeComponentLimit; + // Sets the call budget. -// The default is 1,000. -void nn_setCallBudget(nn_Computer *computer, size_t budget); +// The default is 1. +void nn_setCallBudget(nn_Computer *computer, double budget); // gets the total call budget -size_t nn_getCallBudget(nn_Computer *computer); +double nn_getCallBudget(nn_Computer *computer); // returns the remaining call budget -size_t nn_callBudgetRemaining(nn_Computer *computer); +double nn_callBudgetRemaining(nn_Computer *computer); // automatically called by nn_tick() void nn_resetCallBudget(nn_Computer *computer); @@ -851,12 +860,12 @@ void nn_resetComponentBudgets(nn_Computer *computer); // Upon a full component budget being used for that component, it returns true. // nn_componentsOverused() will also return true. // This indicates the architecture should yield, to throttle the computer for overuse. -bool nn_costComponent(nn_Computer *computer, const char *address, double perTick); +bool nn_costComponent(nn_Computer *computer, double perTick); // Uses amount/perTick to the component budget. // Upon a full component budget being used for that component, it returns true. // nn_componentsOverused() will also return true. // This indicates the architecture should yield, to throttle the computer for overuse. -bool nn_costComponentN(nn_Computer *computer, const char *address, double amount, double perTick); +bool nn_costComponentN(nn_Computer *computer, double amount, double perTick); // call stack operations. // The type system and API are inspired by Lua, as Lua remains the most popular architecture for OpenComputers.