The filesystem waits for the disk instead of asking it repeatedly
sbfsWaitDisk spun on the status port. Read ahead had already hidden about
three quarters of the latency, and what remained was still 11.5% of Type
over a 14K file on a ten thousand cycle disk - all of it memory traffic
spent finding out that nothing had happened yet.
It tests the port first and only waits if the disk is still busy, and that
order is the whole of what makes it safe: the disk raises its line when it
finishes, so a disk that finished in the gap between the test and the WAIT
has its line standing already and the WAIT does nothing rather than
sleeping through the answer. No handler and no vector - the shell keeps the
Interrupt Flag down, and a WAIT wakes on a line whether or not anybody
means to answer it.
Printing a 14K file, by where the cycles go:
cycles a block total bus waiting
0 922,570 922,570 0
2,000 946,474 922,702 23,772
10,000 1,042,474 922,702 119,772
The bus column stops moving. What the program costs in memory is now the
same whatever the disk does. On this emulator nothing observable changes;
on hardware it is a CPU standing out of the way of the memory controller
rather than competing with it for every one of those 119,772 cycles.
The first version cost 660 cycles more at latency zero because it read the
status port again on the way out. AND writes to Q and leaves A alone, so
the status was already there - which is what the original said in its own
comment, and what I stopped believing while rewriting around it.
This commit is contained in:
@@ -1892,12 +1892,23 @@ sbfsForgetBuffer:
|
||||
; settled status, and CALL would put A back the way it found it - so the one thing this
|
||||
; exists to hand over is the one thing an ordinary call cannot carry. Two bytes of Stack
|
||||
; instead of ten, as well, in a routine that runs on every block the machine ever touches.
|
||||
; ASKED FIRST, THEN WAITED ON, and that order is the whole of what makes this safe. The
|
||||
; disk raises its line when it finishes, so if it finished between the test and the WAIT
|
||||
; the line is already standing and the WAIT does nothing rather than sleeping through the
|
||||
; answer. Testing after waiting would have exactly the opposite property.
|
||||
;
|
||||
; No handler and no vector: the shell keeps the Interrupt Flag down, and a WAIT wakes on a
|
||||
; line whether or not anybody is going to answer it. It takes the line down on the way
|
||||
; past, which is what stops the next wait finding this one's line and returning at once.
|
||||
sbfsWaitDisk:
|
||||
INA 0x23
|
||||
INIB 0x01
|
||||
AND
|
||||
BNQ sbfsWaitDisk ; The busy bit is up, so round again.
|
||||
RRET ; A is the status, with the busy bit down.
|
||||
BRQ sbfsWaitDone ; The busy bit is down, so there is nothing to wait for.
|
||||
WAIT
|
||||
BRI sbfsWaitDisk
|
||||
sbfsWaitDone:
|
||||
RRET ; A is the status, with the busy bit down: AND leaves A alone.
|
||||
|
||||
; Copies the disk's buffer, a whole block of it, to Data Memory at DP1.
|
||||
sbfsBufferOut:
|
||||
|
||||
Reference in New Issue
Block a user