rip the drive cache
had huge oversight and was just a bad idea
This commit is contained in:
21
TODO.md
21
TODO.md
@@ -1,6 +1,7 @@
|
|||||||
# For MVP functionality
|
# 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
|
- write a tester OS, basically a menu with tests to run
|
||||||
- tmpfs (rework the whole thing)
|
- tmpfs (rework the whole thing)
|
||||||
- device info
|
- 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
|
- make signals use a circular buffer instead of a simple array
|
||||||
- use more arenas if possible
|
- 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
|
# Unique components
|
||||||
|
|
||||||
Subject to change, still being discussed with the other NeoFlock members.
|
Subject to change, still being discussed with the other NeoFlock members.
|
||||||
|
|||||||
14
src/main.c
14
src/main.c
@@ -389,28 +389,28 @@ int main(int argc, char **argv) {
|
|||||||
"component.invoke(g, 'bind', s, true)\n"
|
"component.invoke(g, 'bind', s, true)\n"
|
||||||
"component.invoke(g, 'set', 1, 1, 'starting sequential bench...')\n"
|
"component.invoke(g, 'set', 1, 1, 'starting sequential bench...')\n"
|
||||||
"local start = computer.uptime()\n"
|
"local start = computer.uptime()\n"
|
||||||
"local cap = component.invoke(d, 'getCapacity')\n"
|
|
||||||
"local ss = component.invoke(d, 'getSectorSize')\n"
|
"local ss = component.invoke(d, 'getSectorSize')\n"
|
||||||
|
"local cap = component.invoke(d, 'getCapacity')\n"
|
||||||
"local bc = cap / ss\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"
|
"local now = computer.uptime()\n"
|
||||||
"component.invoke(g, 'set', 1, 2, 'took ' .. (now - start) .. 's')\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"
|
"while computer.uptime() < now + 3 do computer.pullSignal(0.05) end\n"
|
||||||
"component.invoke(g, 'bind', s, true)\n"
|
"component.invoke(g, 'bind', s, true)\n"
|
||||||
"component.invoke(g, 'set', 1, 1, 'starting random bench...')\n"
|
"component.invoke(g, 'set', 1, 1, 'starting random bench...')\n"
|
||||||
"start = computer.uptime()\n"
|
"start = computer.uptime()\n"
|
||||||
"local rand = 256\n"
|
"for i=1,tc do local i = math.random(1, bc) component.invoke(d, 'readSector', i) end\n"
|
||||||
"for i=1,rand do local i = math.random(1, bc) component.invoke(d, 'readSector', i) end\n"
|
|
||||||
"now = computer.uptime()\n"
|
"now = computer.uptime()\n"
|
||||||
"component.invoke(g, 'set', 1, 2, 'took ' .. (now - start) .. 's')\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"
|
"while computer.uptime() < now + 3 do computer.pullSignal(0.05) end\n"
|
||||||
"computer.shutdown(true)\n"
|
"computer.shutdown(true)\n"
|
||||||
;
|
;
|
||||||
nn_Drive driveconf;
|
nn_Drive driveconf;
|
||||||
nn_Drive driveparts[] = {
|
nn_Drive driveparts[] = {
|
||||||
nn_floppySSD,
|
nn_defaultSSDs[3],
|
||||||
};
|
};
|
||||||
nn_mergeDrives(&driveconf, driveparts, sizeof(driveparts) / sizeof(driveparts[0]));
|
nn_mergeDrives(&driveconf, driveparts, sizeof(driveparts) / sizeof(driveparts[0]));
|
||||||
nn_Component *testDrive = ncl_createDrive(u, NULL, &driveconf, testDriveData, strlen(testDriveData), false);
|
nn_Component *testDrive = ncl_createDrive(u, NULL, &driveconf, testDriveData, strlen(testDriveData), false);
|
||||||
|
|||||||
@@ -2488,7 +2488,6 @@ const nn_Drive nn_defaultDrives[4] = {
|
|||||||
.capacity = 1 * NN_MiB,
|
.capacity = 1 * NN_MiB,
|
||||||
.sectorSize = 512,
|
.sectorSize = 512,
|
||||||
.platterCount = 2,
|
.platterCount = 2,
|
||||||
.cacheLineSize = 2,
|
|
||||||
.readsPerTick = 20,
|
.readsPerTick = 20,
|
||||||
.writesPerTick = 10,
|
.writesPerTick = 10,
|
||||||
.rpm = 3600,
|
.rpm = 3600,
|
||||||
@@ -2499,7 +2498,6 @@ const nn_Drive nn_defaultDrives[4] = {
|
|||||||
.capacity = 2 * NN_MiB,
|
.capacity = 2 * NN_MiB,
|
||||||
.sectorSize = 512,
|
.sectorSize = 512,
|
||||||
.platterCount = 4,
|
.platterCount = 4,
|
||||||
.cacheLineSize = 4,
|
|
||||||
.readsPerTick = 30,
|
.readsPerTick = 30,
|
||||||
.writesPerTick = 15,
|
.writesPerTick = 15,
|
||||||
.rpm = 5400,
|
.rpm = 5400,
|
||||||
@@ -2510,7 +2508,6 @@ const nn_Drive nn_defaultDrives[4] = {
|
|||||||
.capacity = 4 * NN_MiB,
|
.capacity = 4 * NN_MiB,
|
||||||
.sectorSize = 512,
|
.sectorSize = 512,
|
||||||
.platterCount = 8,
|
.platterCount = 8,
|
||||||
.cacheLineSize = 8,
|
|
||||||
.readsPerTick = 40,
|
.readsPerTick = 40,
|
||||||
.writesPerTick = 20,
|
.writesPerTick = 20,
|
||||||
.rpm = 7200,
|
.rpm = 7200,
|
||||||
@@ -2521,7 +2518,6 @@ const nn_Drive nn_defaultDrives[4] = {
|
|||||||
.capacity = 8 * NN_MiB,
|
.capacity = 8 * NN_MiB,
|
||||||
.sectorSize = 512,
|
.sectorSize = 512,
|
||||||
.platterCount = 16,
|
.platterCount = 16,
|
||||||
.cacheLineSize = 16,
|
|
||||||
.readsPerTick = 60,
|
.readsPerTick = 60,
|
||||||
.writesPerTick = 30,
|
.writesPerTick = 30,
|
||||||
.rpm = 7200,
|
.rpm = 7200,
|
||||||
@@ -2534,7 +2530,6 @@ const nn_Drive nn_floppyDrive = {
|
|||||||
.capacity = 512 * NN_KiB,
|
.capacity = 512 * NN_KiB,
|
||||||
.sectorSize = 512,
|
.sectorSize = 512,
|
||||||
.platterCount = 1,
|
.platterCount = 1,
|
||||||
.cacheLineSize = 2,
|
|
||||||
.readsPerTick = 10,
|
.readsPerTick = 10,
|
||||||
.writesPerTick = 5,
|
.writesPerTick = 5,
|
||||||
.rpm = 1800,
|
.rpm = 1800,
|
||||||
@@ -2547,7 +2542,6 @@ const nn_Drive nn_defaultSSDs[4] = {
|
|||||||
.capacity = 512 * NN_KiB,
|
.capacity = 512 * NN_KiB,
|
||||||
.sectorSize = 512,
|
.sectorSize = 512,
|
||||||
.platterCount = 2,
|
.platterCount = 2,
|
||||||
.cacheLineSize = 2,
|
|
||||||
.readsPerTick = 10,
|
.readsPerTick = 10,
|
||||||
.writesPerTick = 5,
|
.writesPerTick = 5,
|
||||||
.rpm = 0,
|
.rpm = 0,
|
||||||
@@ -2558,7 +2552,6 @@ const nn_Drive nn_defaultSSDs[4] = {
|
|||||||
.capacity = 1 * NN_MiB,
|
.capacity = 1 * NN_MiB,
|
||||||
.sectorSize = 512,
|
.sectorSize = 512,
|
||||||
.platterCount = 4,
|
.platterCount = 4,
|
||||||
.cacheLineSize = 4,
|
|
||||||
.readsPerTick = 15,
|
.readsPerTick = 15,
|
||||||
.writesPerTick = 7,
|
.writesPerTick = 7,
|
||||||
.rpm = 0,
|
.rpm = 0,
|
||||||
@@ -2569,7 +2562,6 @@ const nn_Drive nn_defaultSSDs[4] = {
|
|||||||
.capacity = 2 * NN_MiB,
|
.capacity = 2 * NN_MiB,
|
||||||
.sectorSize = 512,
|
.sectorSize = 512,
|
||||||
.platterCount = 8,
|
.platterCount = 8,
|
||||||
.cacheLineSize = 8,
|
|
||||||
.readsPerTick = 20,
|
.readsPerTick = 20,
|
||||||
.writesPerTick = 10,
|
.writesPerTick = 10,
|
||||||
.rpm = 0,
|
.rpm = 0,
|
||||||
@@ -2580,7 +2572,6 @@ const nn_Drive nn_defaultSSDs[4] = {
|
|||||||
.capacity = 4 * NN_MiB,
|
.capacity = 4 * NN_MiB,
|
||||||
.sectorSize = 512,
|
.sectorSize = 512,
|
||||||
.platterCount = 16,
|
.platterCount = 16,
|
||||||
.cacheLineSize = 16,
|
|
||||||
.readsPerTick = 30,
|
.readsPerTick = 30,
|
||||||
.writesPerTick = 15,
|
.writesPerTick = 15,
|
||||||
.rpm = 0,
|
.rpm = 0,
|
||||||
@@ -2593,7 +2584,6 @@ const nn_Drive nn_floppySSD = {
|
|||||||
.capacity = 256 * NN_KiB,
|
.capacity = 256 * NN_KiB,
|
||||||
.sectorSize = 512,
|
.sectorSize = 512,
|
||||||
.platterCount = 1,
|
.platterCount = 1,
|
||||||
.cacheLineSize = 2,
|
|
||||||
.readsPerTick = 5,
|
.readsPerTick = 5,
|
||||||
.writesPerTick = 2,
|
.writesPerTick = 2,
|
||||||
.rpm = 0,
|
.rpm = 0,
|
||||||
@@ -4067,30 +4057,16 @@ static void nn_drive_seekPenalty(nn_Computer *C, size_t lastSector, size_t newSe
|
|||||||
} else {
|
} else {
|
||||||
sectorDelta = lastSector - newSector;
|
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.
|
// RPM over the number of sectors, over 60 seconds.
|
||||||
double latency = (double)sectorDelta * 60 / ((double)drive->rpm * maxSectors);
|
double latency = (double)sectorDelta * 60 / ((double)drive->rpm * maxSectors);
|
||||||
nn_addIdleTime(C, latency);
|
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 {
|
typedef enum nn_DrvNum {
|
||||||
NN_DRVNUM_GETCAPACITY,
|
NN_DRVNUM_GETCAPACITY,
|
||||||
NN_DRVNUM_GETSECTORSIZE,
|
NN_DRVNUM_GETSECTORSIZE,
|
||||||
NN_DRVNUM_GETPLATTERCOUNT,
|
NN_DRVNUM_GETPLATTERCOUNT,
|
||||||
NN_DRVNUM_GETCACHESIZE,
|
|
||||||
NN_DRVNUM_ISRO,
|
NN_DRVNUM_ISRO,
|
||||||
NN_DRVNUM_GETLABEL,
|
NN_DRVNUM_GETLABEL,
|
||||||
NN_DRVNUM_SETLABEL,
|
NN_DRVNUM_SETLABEL,
|
||||||
@@ -4131,9 +4107,8 @@ static nn_Exit nn_drvHandler(nn_ComponentRequest *request) {
|
|||||||
return NN_OK;
|
return NN_OK;
|
||||||
}
|
}
|
||||||
size_t ss = state->drive.sectorSize;
|
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 sectorCount = state->drive.capacity / ss;
|
||||||
|
size_t perPlatter = sectorCount / state->drive.platterCount;
|
||||||
unsigned int method = request->methodIdx;
|
unsigned int method = request->methodIdx;
|
||||||
if(method == NN_DRVNUM_GETCAPACITY) {
|
if(method == NN_DRVNUM_GETCAPACITY) {
|
||||||
request->returnCount = 1;
|
request->returnCount = 1;
|
||||||
@@ -4143,10 +4118,6 @@ static nn_Exit nn_drvHandler(nn_ComponentRequest *request) {
|
|||||||
request->returnCount = 1;
|
request->returnCount = 1;
|
||||||
return nn_pushinteger(C, ss);
|
return nn_pushinteger(C, ss);
|
||||||
}
|
}
|
||||||
if(method == NN_DRVNUM_GETCACHESIZE) {
|
|
||||||
request->returnCount = 1;
|
|
||||||
return nn_pushinteger(C, cacheline);
|
|
||||||
}
|
|
||||||
if(method == NN_DRVNUM_ISRO) {
|
if(method == NN_DRVNUM_ISRO) {
|
||||||
dreq.action = NN_DRIVE_ISRO;
|
dreq.action = NN_DRIVE_ISRO;
|
||||||
e = state->handler(&dreq);
|
e = state->handler(&dreq);
|
||||||
@@ -4188,11 +4159,9 @@ static nn_Exit nn_drvHandler(nn_ComponentRequest *request) {
|
|||||||
if(e) return e;
|
if(e) return e;
|
||||||
curPos = dreq.curpos;
|
curPos = dreq.curpos;
|
||||||
|
|
||||||
if(nn_drive_cachelineOf(curPos, cacheline) != nn_drive_cachelineOf(sec, cacheline)) {
|
|
||||||
nn_drive_seekPenalty(C, curPos, sec, &state->drive);
|
nn_drive_seekPenalty(C, curPos, sec, &state->drive);
|
||||||
nn_costComponent(C, request->compAddress, state->drive.readsPerTick);
|
nn_costComponent(C, request->compAddress, state->drive.readsPerTick);
|
||||||
nn_removeEnergy(C, state->drive.dataEnergyCost * cacheline * ss);
|
nn_removeEnergy(C, state->drive.dataEnergyCost * ss);
|
||||||
}
|
|
||||||
|
|
||||||
char *sector = nn_alloc(ctx, ss);
|
char *sector = nn_alloc(ctx, ss);
|
||||||
if(sector == NULL) return NN_ENOMEM;
|
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_GETCAPACITY] = {"getCapacity", "function(): integer - Get drive capacity", NN_DIRECT},
|
||||||
[NN_DRVNUM_GETSECTORSIZE] = {"getSectorSize", "function(): integer - Get sector size", 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_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_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_GETLABEL] = {"getLabel", "function(): string? - Get drive label", NN_DIRECT},
|
||||||
[NN_DRVNUM_SETLABEL] = {"setLabel", "function(label: string?): string - Set drive label", NN_INDIRECT},
|
[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->dataEnergyCost += d.dataEnergyCost;
|
||||||
merged->rpm += d.rpm;
|
merged->rpm += d.rpm;
|
||||||
merged->capacity += d.capacity;
|
merged->capacity += d.capacity;
|
||||||
merged->cacheLineSize += d.cacheLineSize;
|
|
||||||
merged->platterCount += d.platterCount;
|
merged->platterCount += d.platterCount;
|
||||||
}
|
}
|
||||||
merged->readsPerTick /= len;
|
merged->readsPerTick /= len;
|
||||||
|
|||||||
@@ -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
|
// 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.
|
// would mean only 3 rotations.
|
||||||
size_t platterCount;
|
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.
|
// how many reads can be issued per tick.
|
||||||
// Anything that kicks out the current cacheline counts as a read.
|
// Anything that kicks out the current cacheline counts as a read.
|
||||||
size_t readsPerTick;
|
size_t readsPerTick;
|
||||||
|
|||||||
Reference in New Issue
Block a user