19d99b9b815f — Laurens Holst 5 years ago
Application: Pre-allocate the output file.

Me and Louthrax noticed that decompressing to a file became significantly slower
depending on how full the output disk is. It would cause the Z80 and even the
R800 to spend several seconds more on extracting the file. It turns out that
this overhead is caused by repeated FAT cluster allocation, quite expensive.

This overhead can be avoided by pre-allocating the file at once. This change
does just that, saving several seconds depending on how full the disk is.
Unfortunately, we do have to actually write a byte (causing an extra seek), so
we only do it when the output file size exceeds 64K. Also to know the output
size we must seek to the end of the gz file, which is a shame but unavoidable.
2 files changed, 102 insertions(+), 0 deletions(-)

M src/Application.asm
M src/DOS.asm
M src/Application.asm +80 -0
@@ 4,6 4,8 @@ 
 Application: MACRO
 	cli:
 		dw 0
+	outputSize:
+		dd 0
 	_size:
 	ENDM
 

          
@@ 117,7 119,9 @@ Application_InflateToFile:
 	call Application_PrintInflating
 	call Application_CreateFileReader
 	push de
+	call Application_ReadOutputSize
 	call Application_CreateFileWriter
+	call Application_PreAllocateOutput
 	pop hl
 	push ix
 	push hl

          
@@ 271,6 275,82 @@ Application_CreateNullWriter:
 	pop ix
 	ret
 
+; de = file reader
+; ix = this
+; Modifies: af, bc, hl, iy
+Application_ReadOutputSize:
+	ld iyl,e
+	ld iyh,d
+	push de
+	ld b,(iy + FileReader.fileHandle)
+	call DOS_GetFileHandlePointer
+	call Application_CheckDOSError
+	push de
+	push hl
+	ld a,2
+	ld hl,-4 & 0FFFFH
+	ld de,-4 >> 16
+	ld b,(iy + FileReader.fileHandle)
+	call DOS_MoveFileHandlePointer
+	call Application_CheckDOSError
+	ld e,ixl
+	ld d,ixh
+	ld hl,Application.outputSize
+	add hl,de
+	ex de,hl
+	ld hl,4
+	ld b,(iy + FileReader.fileHandle)
+	call DOS_ReadFromFileHandle
+	call Application_CheckDOSError
+	pop hl
+	pop de
+	ld b,(iy + FileReader.fileHandle)
+	call DOS_SetFileHandlePointer
+	call Application_CheckDOSError
+	pop de
+	ret
+
+; de = file writer
+; ix = this
+; Modifies: af, bc, hl, iy
+Application_PreAllocateOutput:
+	ld iyl,e
+	ld iyh,d
+	ld a,(ix + Application.outputSize + 2)
+	or (ix + Application.outputSize + 3)
+	ret z  ; don’t pre-allocate if < 64K
+	push de
+	ld b,(iy + FileWriter.fileHandle)
+	call DOS_GetFileHandlePointer
+	call Application_CheckDOSError
+	push de
+	push hl
+	ld l,(ix + Application.outputSize)
+	ld h,(ix + Application.outputSize + 1)
+	ld e,(ix + Application.outputSize + 2)
+	ld d,(ix + Application.outputSize + 3)
+	ld bc,1
+	sbc hl,bc
+	dec bc
+	ex de,hl
+	sbc hl,bc
+	ex de,hl
+	ld b,(iy + FileWriter.fileHandle)
+	call DOS_SetFileHandlePointer
+	call Application_CheckDOSError
+	ld de,0  ; don’t care which value we write
+	ld hl,1
+	ld b,(iy + FileWriter.fileHandle)
+	call DOS_WriteToFileHandle
+	call Application_CheckDOSError
+	pop hl
+	pop de
+	ld b,(iy + FileWriter.fileHandle)
+	call DOS_SetFileHandlePointer
+	call Application_CheckDOSError
+	pop de
+	ret
+
 ; Check if the stack is well above the heap
 Application_CheckStack:
 	ld hl,-(HEAP + HEAP_SIZE + STACK_SIZE)

          
M src/DOS.asm +22 -0
@@ 222,6 222,28 @@ DOS_WriteToFileHandle:
 	ld c,_WRITE
 	jp BDOS
 
+DOS_MoveFileHandlePointer:
+	ld c,_SEEK
+	jp BDOS
+
+; b = file handle
+; dehl = file pointer
+; a <- error
+DOS_SetFileHandlePointer:
+	ld a,0
+	call DOS_MoveFileHandlePointer
+	ret
+
+; b = file handle
+; a <- error
+; dehl <- file pointer
+DOS_GetFileHandlePointer:
+	ld hl,0
+	ld de,0
+	ld a,1
+	call DOS_MoveFileHandlePointer
+	ret
+
 DOS_ParsePathname:
 	ld c,_PARSE
 	jp BDOS