rip the drive cache

had huge oversight and was just a bad idea
This commit is contained in:
2026-04-05 03:33:26 +02:00
parent dad8e34cca
commit 77aded7a05
4 changed files with 31 additions and 48 deletions

21
TODO.md
View File

@@ -1,6 +1,7 @@
# For MVP functionality
- implement the RAID merger algorithm (merges multiple drives or filesystems together into a bigger config)
- move SSDs to ossm_flash
- remove HDD cachelines (they're pointless)
- write a tester OS, basically a menu with tests to run
- tmpfs (rework the whole thing)
- device info
@@ -67,6 +68,24 @@ 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
# Component extensions
## filesystem
- `getMaxRead(): integer`, returns the maximum size of a read; effectively the ideal buffer size
## drive
- `readUByte(byte: integer): integer`, reads an unsigned byte
## ossm_flash
- `getLabel(): string?`, to get the label
- `setLabel(label: string?): string?`, to set the label
- `isReadonly(): boolean`, check if the SSD is read-only
- `readUByte(byte: integer): integer`, reads an unsigned byte
- `getWearLevel(): number`, returns a number from 0 to 100, where 0 means full life and 100 means dead
# Unique components
Subject to change, still being discussed with the other NeoFlock members.

View File

@@ -389,28 +389,28 @@ int main(int argc, char **argv) {
"component.invoke(g, 'bind', s, true)\n"
"component.invoke(g, 'set', 1, 1, 'starting sequential bench...')\n"
"local start = computer.uptime()\n"
"local cap = component.invoke(d, 'getCapacity')\n"
"local ss = component.invoke(d, 'getSectorSize')\n"
"local cap = component.invoke(d, 'getCapacity')\n"
"local bc = cap / ss\n"
"for i=1,bc do component.invoke(d, 'readSector', i) end\n"
"local tc = 256\n"
"for i=1,tc do component.invoke(d, 'readSector', i) end\n"
"local now = computer.uptime()\n"
"component.invoke(g, 'set', 1, 2, 'took ' .. (now - start) .. 's')\n"
"component.invoke(g, 'set', 1, 3, 'sequential read speed: ' .. (cap / (now - start)) .. 'B/s')\n"
"component.invoke(g, 'set', 1, 3, 'sequential read speed: ' .. (tc * ss / (now - start)) .. 'B/s')\n"
"while computer.uptime() < now + 3 do computer.pullSignal(0.05) end\n"
"component.invoke(g, 'bind', s, true)\n"
"component.invoke(g, 'set', 1, 1, 'starting random bench...')\n"
"start = computer.uptime()\n"
"local rand = 256\n"
"for i=1,rand do local i = math.random(1, bc) component.invoke(d, 'readSector', i) end\n"
"for i=1,tc 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: ' .. (rand * ss / (now - start)) .. 'B/s')\n"
"component.invoke(g, 'set', 1, 3, 'random read speed: ' .. (tc * ss / (now - start)) .. 'B/s')\n"
"while computer.uptime() < now + 3 do computer.pullSignal(0.05) end\n"
"computer.shutdown(true)\n"
;
nn_Drive driveconf;
nn_Drive driveparts[] = {
nn_floppySSD,
nn_defaultSSDs[3],
};
nn_mergeDrives(&driveconf, driveparts, sizeof(driveparts) / sizeof(driveparts[0]));
nn_Component *testDrive = ncl_createDrive(u, NULL, &driveconf, testDriveData, strlen(testDriveData), false);

View File

@@ -2488,7 +2488,6 @@ const nn_Drive nn_defaultDrives[4] = {
.capacity = 1 * NN_MiB,
.sectorSize = 512,
.platterCount = 2,
.cacheLineSize = 2,
.readsPerTick = 20,
.writesPerTick = 10,
.rpm = 3600,
@@ -2499,7 +2498,6 @@ const nn_Drive nn_defaultDrives[4] = {
.capacity = 2 * NN_MiB,
.sectorSize = 512,
.platterCount = 4,
.cacheLineSize = 4,
.readsPerTick = 30,
.writesPerTick = 15,
.rpm = 5400,
@@ -2510,7 +2508,6 @@ const nn_Drive nn_defaultDrives[4] = {
.capacity = 4 * NN_MiB,
.sectorSize = 512,
.platterCount = 8,
.cacheLineSize = 8,
.readsPerTick = 40,
.writesPerTick = 20,
.rpm = 7200,
@@ -2521,7 +2518,6 @@ const nn_Drive nn_defaultDrives[4] = {
.capacity = 8 * NN_MiB,
.sectorSize = 512,
.platterCount = 16,
.cacheLineSize = 16,
.readsPerTick = 60,
.writesPerTick = 30,
.rpm = 7200,
@@ -2534,7 +2530,6 @@ const nn_Drive nn_floppyDrive = {
.capacity = 512 * NN_KiB,
.sectorSize = 512,
.platterCount = 1,
.cacheLineSize = 2,
.readsPerTick = 10,
.writesPerTick = 5,
.rpm = 1800,
@@ -2547,7 +2542,6 @@ const nn_Drive nn_defaultSSDs[4] = {
.capacity = 512 * NN_KiB,
.sectorSize = 512,
.platterCount = 2,
.cacheLineSize = 2,
.readsPerTick = 10,
.writesPerTick = 5,
.rpm = 0,
@@ -2558,7 +2552,6 @@ const nn_Drive nn_defaultSSDs[4] = {
.capacity = 1 * NN_MiB,
.sectorSize = 512,
.platterCount = 4,
.cacheLineSize = 4,
.readsPerTick = 15,
.writesPerTick = 7,
.rpm = 0,
@@ -2569,7 +2562,6 @@ const nn_Drive nn_defaultSSDs[4] = {
.capacity = 2 * NN_MiB,
.sectorSize = 512,
.platterCount = 8,
.cacheLineSize = 8,
.readsPerTick = 20,
.writesPerTick = 10,
.rpm = 0,
@@ -2580,7 +2572,6 @@ const nn_Drive nn_defaultSSDs[4] = {
.capacity = 4 * NN_MiB,
.sectorSize = 512,
.platterCount = 16,
.cacheLineSize = 16,
.readsPerTick = 30,
.writesPerTick = 15,
.rpm = 0,
@@ -2593,7 +2584,6 @@ const nn_Drive nn_floppySSD = {
.capacity = 256 * NN_KiB,
.sectorSize = 512,
.platterCount = 1,
.cacheLineSize = 2,
.readsPerTick = 5,
.writesPerTick = 2,
.rpm = 0,
@@ -4067,30 +4057,16 @@ static void nn_drive_seekPenalty(nn_Computer *C, size_t lastSector, size_t newSe
} else {
sectorDelta = lastSector - newSector;
}
if(sectorDelta < drive->cacheLineSize) {
sectorDelta = 0; // within cache
} else {
// align to cache line
if(sectorDelta % drive->cacheLineSize != 0) {
sectorDelta += drive->cacheLineSize - sectorDelta % drive->cacheLineSize;
}
}
// RPM over the number of sectors, over 60 seconds.
double latency = (double)sectorDelta * 60 / ((double)drive->rpm * maxSectors);
nn_addIdleTime(C, latency);
}
// 1-indexed
static size_t nn_drive_cachelineOf(size_t sector, size_t perCache) {
return (sector - 1) / perCache;
}
typedef enum nn_DrvNum {
NN_DRVNUM_GETCAPACITY,
NN_DRVNUM_GETSECTORSIZE,
NN_DRVNUM_GETPLATTERCOUNT,
NN_DRVNUM_GETCACHESIZE,
NN_DRVNUM_ISRO,
NN_DRVNUM_GETLABEL,
NN_DRVNUM_SETLABEL,
@@ -4131,9 +4107,8 @@ static nn_Exit nn_drvHandler(nn_ComponentRequest *request) {
return NN_OK;
}
size_t ss = state->drive.sectorSize;
size_t cacheline = state->drive.cacheLineSize;
size_t cacheByteSize = cacheline * ss;
size_t sectorCount = state->drive.capacity / ss;
size_t perPlatter = sectorCount / state->drive.platterCount;
unsigned int method = request->methodIdx;
if(method == NN_DRVNUM_GETCAPACITY) {
request->returnCount = 1;
@@ -4143,10 +4118,6 @@ static nn_Exit nn_drvHandler(nn_ComponentRequest *request) {
request->returnCount = 1;
return nn_pushinteger(C, ss);
}
if(method == NN_DRVNUM_GETCACHESIZE) {
request->returnCount = 1;
return nn_pushinteger(C, cacheline);
}
if(method == NN_DRVNUM_ISRO) {
dreq.action = NN_DRIVE_ISRO;
e = state->handler(&dreq);
@@ -4188,11 +4159,9 @@ static nn_Exit nn_drvHandler(nn_ComponentRequest *request) {
if(e) return e;
curPos = dreq.curpos;
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);
}
nn_drive_seekPenalty(C, curPos, sec, &state->drive);
nn_costComponent(C, request->compAddress, state->drive.readsPerTick);
nn_removeEnergy(C, state->drive.dataEnergyCost * ss);
char *sector = nn_alloc(ctx, ss);
if(sector == NULL) return NN_ENOMEM;
@@ -4222,7 +4191,6 @@ nn_Component *nn_createDrive(nn_Universe *universe, const char *address, const n
[NN_DRVNUM_GETCAPACITY] = {"getCapacity", "function(): integer - Get drive capacity", NN_DIRECT},
[NN_DRVNUM_GETSECTORSIZE] = {"getSectorSize", "function(): integer - Get sector size", NN_DIRECT},
[NN_DRVNUM_GETPLATTERCOUNT] = {"getPlatterCount", "function(): integer - Get number of platters on this drive", NN_DIRECT},
[NN_DRVNUM_GETCACHESIZE] = {"getCacheSize", "function(): integer - Get number of sectors cached in a single read", NN_DIRECT},
[NN_DRVNUM_ISRO] = {"isReadOnly", "function(): boolean - Get whether the drive is read-only", NN_DIRECT},
[NN_DRVNUM_GETLABEL] = {"getLabel", "function(): string? - Get drive label", NN_DIRECT},
[NN_DRVNUM_SETLABEL] = {"setLabel", "function(label: string?): string - Set drive label", NN_INDIRECT},
@@ -4272,7 +4240,6 @@ bool nn_mergeDrives(nn_Drive *merged, const nn_Drive *drives, size_t len) {
merged->dataEnergyCost += d.dataEnergyCost;
merged->rpm += d.rpm;
merged->capacity += d.capacity;
merged->cacheLineSize += d.cacheLineSize;
merged->platterCount += d.platterCount;
}
merged->readsPerTick /= len;

View File

@@ -1094,9 +1094,6 @@ typedef struct nn_Drive {
// However, if it has 2 platters, it'd be seen as 1 to 4 being at the same angle as 5 to 8, which
// would mean only 3 rotations.
size_t platterCount;
// how many sectors are cached together.
// Each platter has "its own cache."
size_t cacheLineSize;
// how many reads can be issued per tick.
// Anything that kicks out the current cacheline counts as a read.
size_t readsPerTick;