From f9bbe58894c91c9990aac713f2638f6ba4d53318 Mon Sep 17 00:00:00 2001 From: IonutParau Date: Sat, 4 Apr 2026 02:26:06 +0200 Subject: [PATCH] SSDs --- TODO.md | 6 ---- src/main.c | 12 ++++---- src/neonucleus.c | 77 ++++++++++++++++++++++++++++++++++++++++++------ src/neonucleus.h | 5 ++++ 4 files changed, 80 insertions(+), 20 deletions(-) diff --git a/TODO.md b/TODO.md index 52d018f..eeea192 100644 --- a/TODO.md +++ b/TODO.md @@ -66,9 +66,3 @@ NOTE: we're mostly bottlenecked by the architecture (typically a Lua VM) and the - make signals use a circular buffer instead of a simple array - use more arenas if possible - -# Drive costs - -The drive has platters just like in OC, as well as a cache line. -The read cost is only factored in if `cachelineOf(lastSector) != cachelineOf(newSector)`. -Seek cost is also in whole cache lines. diff --git a/src/main.c b/src/main.c index 1708e05..b3ade10 100644 --- a/src/main.c +++ b/src/main.c @@ -382,7 +382,8 @@ int main(int argc, char **argv) { "component.invoke(g, 'set', 1, 1, 'starting sequential bench...')\n" "local start = computer.uptime()\n" "local cap = component.invoke(d, 'getCapacity')\n" - "local bc = component.invoke(d, 'getCapacity') / component.invoke(d, 'getSectorSize')\n" + "local ss = component.invoke(d, 'getSectorSize')\n" + "local bc = cap / ss\n" "for i=1,bc do component.invoke(d, 'readSector', i) end\n" "local now = computer.uptime()\n" "component.invoke(g, 'set', 1, 2, 'took ' .. (now - start) .. 's')\n" @@ -391,15 +392,15 @@ int main(int argc, char **argv) { "component.invoke(g, 'bind', s, true)\n" "component.invoke(g, 'set', 1, 1, 'starting random bench...')\n" "start = computer.uptime()\n" - "local shortcut = 4\n" - "for i=1,bc/shortcut do local i = math.random(1, bc) component.invoke(d, 'readSector', i) end\n" + "local rand = 256\n" + "for i=1,rand do local i = math.random(1, bc) component.invoke(d, 'readSector', i) end\n" "now = computer.uptime()\n" "component.invoke(g, 'set', 1, 2, 'took ' .. (now - start) .. 's')\n" - "component.invoke(g, 'set', 1, 3, 'random read speed: ' .. (cap / shortcut / (now - start)) .. 'B/s')\n" + "component.invoke(g, 'set', 1, 3, 'random read speed: ' .. (rand * ss / (now - start)) .. 'B/s')\n" "while computer.uptime() < now + 3 do computer.pullSignal(0.05) end\n" "computer.shutdown(true)\n" ; - nn_Component *testDrive = ncl_createDrive(u, NULL, &nn_floppyDrive, testDriveData, strlen(testDriveData), false); + nn_Component *testDrive = ncl_createDrive(u, NULL, &nn_defaultSSDs[3], testDriveData, strlen(testDriveData), false); ncl_setCLabel(managedfs, "Main Filesystem"); ncl_setCLabel(testingfs, "Secondary Filesystem"); @@ -450,6 +451,7 @@ restart:; // collects stats nn_setEnergyHandler(c, NULL, ne_energy_accumulator); } + nn_setCallBudget(c, 0); // default for 64-bit if(sizeof(void *) > 4) nn_setMemoryScale(c, 1.8); diff --git a/src/neonucleus.c b/src/neonucleus.c index e1d8670..eac314a 100644 --- a/src/neonucleus.c +++ b/src/neonucleus.c @@ -2423,7 +2423,7 @@ const nn_Filesystem nn_defaultTmpFS = NN_INIT(nn_Filesystem) { .spaceTotal = 64 * NN_KiB, .readsPerTick = 1024, .writesPerTick = 512, - .dataEnergyCost = 512.0 / NN_MiB, + .dataEnergyCost = 0.1 / NN_MiB, }; const nn_Drive nn_defaultDrives[4] = { @@ -2436,7 +2436,7 @@ const nn_Drive nn_defaultDrives[4] = { .writesPerTick = 10, .rpm = 3600, .onlySpinForwards = false, - .dataEnergyCost = 256.0 / NN_MiB, + .dataEnergyCost = 4.0 / NN_MiB, }, NN_INIT(nn_Drive) { .capacity = 2 * NN_MiB, @@ -2447,29 +2447,29 @@ const nn_Drive nn_defaultDrives[4] = { .writesPerTick = 15, .rpm = 5400, .onlySpinForwards = false, - .dataEnergyCost = 512.0 / NN_MiB, + .dataEnergyCost = 8.0 / NN_MiB, }, NN_INIT(nn_Drive) { .capacity = 4 * NN_MiB, .sectorSize = 512, .platterCount = 8, - .cacheLineSize = 4, + .cacheLineSize = 8, .readsPerTick = 40, .writesPerTick = 20, .rpm = 7200, .onlySpinForwards = false, - .dataEnergyCost = 1024.0 / NN_MiB, + .dataEnergyCost = 16.0 / NN_MiB, }, NN_INIT(nn_Drive) { .capacity = 8 * NN_MiB, .sectorSize = 512, .platterCount = 16, - .cacheLineSize = 8, + .cacheLineSize = 16, .readsPerTick = 60, .writesPerTick = 30, .rpm = 7200, .onlySpinForwards = false, - .dataEnergyCost = 2048.0 / NN_MiB, + .dataEnergyCost = 32.0 / NN_MiB, }, }; @@ -2482,9 +2482,67 @@ const nn_Drive nn_floppyDrive = { .writesPerTick = 5, .rpm = 1800, .onlySpinForwards = true, - .dataEnergyCost = 128.0 / NN_MiB, + .dataEnergyCost = 1.0 / NN_MiB, }; +const nn_Drive nn_defaultSSDs[4] = { + NN_INIT(nn_Drive) { + .capacity = 512 * NN_KiB, + .sectorSize = 512, + .platterCount = 2, + .cacheLineSize = 2, + .readsPerTick = 20, + .writesPerTick = 10, + .rpm = 0, + .onlySpinForwards = false, + .dataEnergyCost = 64.0 / NN_MiB, + }, + NN_INIT(nn_Drive) { + .capacity = 1 * NN_MiB, + .sectorSize = 512, + .platterCount = 4, + .cacheLineSize = 4, + .readsPerTick = 30, + .writesPerTick = 15, + .rpm = 0, + .onlySpinForwards = false, + .dataEnergyCost = 128.0 / NN_MiB, + }, + NN_INIT(nn_Drive) { + .capacity = 2 * NN_MiB, + .sectorSize = 512, + .platterCount = 8, + .cacheLineSize = 8, + .readsPerTick = 40, + .writesPerTick = 20, + .rpm = 0, + .onlySpinForwards = false, + .dataEnergyCost = 256.0 / NN_MiB, + }, + NN_INIT(nn_Drive) { + .capacity = 4 * NN_MiB, + .sectorSize = 512, + .platterCount = 16, + .cacheLineSize = 16, + .readsPerTick = 60, + .writesPerTick = 30, + .rpm = 0, + .onlySpinForwards = false, + .dataEnergyCost = 512.0 / NN_MiB, + }, +}; + +const nn_Drive nn_floppySSD = { + .capacity = 256 * NN_KiB, + .sectorSize = 512, + .platterCount = 1, + .cacheLineSize = 2, + .readsPerTick = 10, + .writesPerTick = 5, + .rpm = 0, + .onlySpinForwards = true, + .dataEnergyCost = 16.0 / NN_MiB, +}; const nn_ScreenConfig nn_defaultScreens[4] = { NN_INIT(nn_ScreenConfig) { @@ -2667,7 +2725,7 @@ static void nn_splitColor(int color, double *r, double *g, double *b) { *b = (double)_b / 255; } -static double nn_colorLuminance(int color) { +double nn_colorLuminance(int color) { double r, g, b; nn_splitColor(color, &r, &g, &b); // taken from https://stackoverflow.com/questions/687261/converting-rgb-to-grayscale-intensity @@ -3945,6 +4003,7 @@ static nn_Exit nn_drvHandler(nn_ComponentRequest *request) { if(nn_drive_cachelineOf(curPos, cacheline) != nn_drive_cachelineOf(sec, cacheline)) { nn_drive_seekPenalty(C, curPos, sec, &state->drive); nn_costComponent(C, request->compAddress, state->drive.readsPerTick); + nn_removeEnergy(C, state->drive.dataEnergyCost * cacheline * ss); } char *sector = nn_alloc(ctx, ss); diff --git a/src/neonucleus.h b/src/neonucleus.h index 377cd53..41caa7a 100644 --- a/src/neonucleus.h +++ b/src/neonucleus.h @@ -1118,6 +1118,9 @@ typedef struct nn_Drive { extern const nn_Drive nn_defaultDrives[4]; extern const nn_Drive nn_floppyDrive; +extern const nn_Drive nn_defaultSSDs[4]; +extern const nn_Drive nn_floppySSD; + typedef enum nn_DriveAction { // drive gone NN_DRIVE_DROP, @@ -1449,6 +1452,8 @@ extern int nn_ocpalette8[256]; // initializes the contents of the palettes. void nn_initPalettes(); +// Returns a number from 0 to 1 representing the perceived luminance. +double nn_colorLuminance(int color); // Expensive. // Maps a color to the closest match in a palette. int nn_mapColor(int color, int *palette, size_t len);