Initial conversion to markdown
This commit is contained in:
parent
a96a114403
commit
5e10794a24
362 changed files with 67353 additions and 0 deletions
262
01-03.md
Normal file
262
01-03.md
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
------------------------ --------------------------------- --------------------
|
||||
[Previous](01-02.html) [Table of Contents](index.html) [Next](01-04.html)
|
||||
------------------------ --------------------------------- --------------------
|
||||
|
||||
* * * * *
|
||||
|
||||
Listing
|
||||
|
||||
Borland
|
||||
|
||||
Microsoft
|
||||
|
||||
Borland
|
||||
|
||||
Microsoft
|
||||
|
||||
Assembly
|
||||
|
||||
Optimization\
|
||||
Ratio
|
||||
|
||||
* * * * *
|
||||
|
||||
(no opt)
|
||||
|
||||
(no opt)
|
||||
|
||||
(opt)
|
||||
|
||||
(opt)
|
||||
|
||||
1
|
||||
|
||||
166.9
|
||||
|
||||
166.8
|
||||
|
||||
167.0
|
||||
|
||||
165.8
|
||||
|
||||
155.1
|
||||
|
||||
1.08
|
||||
|
||||
4
|
||||
|
||||
13.5
|
||||
|
||||
13.6
|
||||
|
||||
13.5
|
||||
|
||||
13.5
|
||||
|
||||
...
|
||||
|
||||
1.01
|
||||
|
||||
5
|
||||
|
||||
4.7
|
||||
|
||||
5.5
|
||||
|
||||
3.8
|
||||
|
||||
3.4
|
||||
|
||||
2.7
|
||||
|
||||
2.04
|
||||
|
||||
Ratio best\
|
||||
designed\
|
||||
to worst\
|
||||
designed
|
||||
|
||||
35.51
|
||||
|
||||
30.33
|
||||
|
||||
43.95
|
||||
|
||||
48.76
|
||||
|
||||
57.44
|
||||
|
||||
**Note:** The execution times (in seconds) for this chapter’s listings
|
||||
were timed when the compiled listings were run on the WordPerfect 4.2
|
||||
thesaurus file TH.WP (362,293 bytes in size), as compiled in the small
|
||||
model with Borland and Microsoft compilers with optimization on (opt)
|
||||
and off (no opt). All times were measured with Paradigm Systems’ TIMER
|
||||
program on a 10 MHz 1-wait-state AT clone with a 28-ms hard disk, with
|
||||
disk caching turned off.
|
||||
|
||||
* * * * *
|
||||
|
||||
Table 1.1 Execution Times for WordPerfect Checksum.
|
||||
|
||||
* * * * *
|
||||
|
||||
**LISTING 1.2 L1-2.C**
|
||||
|
||||
/*
|
||||
* Program to calculate the 16-bit checksum of the stream of bytes
|
||||
* from the specified file. Obtains the bytes one at a time in
|
||||
* assembler, via direct calls to DOS.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
main(int argc, char *argv[]) {
|
||||
int Handle;
|
||||
unsigned char Byte;
|
||||
unsigned int Checksum;
|
||||
int ReadLength;
|
||||
|
||||
if ( argc != 2 ) {
|
||||
printf(“usage: checksum filename\n”);
|
||||
exit(1);
|
||||
}
|
||||
if ( (Handle = open(argv[1], O_RDONLY | O_BINARY)) == -1 ) {
|
||||
printf(“Can’t open file: %s\n”, argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
if ( !ChecksumFile(Handle, &Checksum) ) {
|
||||
printf(“Error reading file %s\n”, argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Report the result */
|
||||
printf(“The checksum is: %u\n”, Checksum);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
**LISTING 1.3 L1-3.ASM**
|
||||
|
||||
; Assembler subroutine to perform a 16-bit checksum on the file
|
||||
; opened on the passed-in handle. Stores the result in the
|
||||
; passed-in checksum variable. Returns 1 for success, 0 for error.
|
||||
;
|
||||
; Call as:
|
||||
; int ChecksumFile(unsigned int Handle, unsigned int *Checksum);
|
||||
;
|
||||
; where:
|
||||
; Handle = handle # under which file to checksum is open
|
||||
; Checksum = pointer to unsigned int variable checksum is
|
||||
; to be stored in
|
||||
;
|
||||
; Parameter structure:
|
||||
;
|
||||
Parms struc
|
||||
dw ? ;pushed BP
|
||||
dw ? ;return address
|
||||
Handle dw ?
|
||||
Checksum dw ?
|
||||
Parms ends
|
||||
;
|
||||
.model small
|
||||
.data
|
||||
TempWord label word
|
||||
TempByte db ? ;each byte read by DOS will be stored here
|
||||
db 0 ;high byte of TempWord is always 0
|
||||
;for 16-bit adds
|
||||
;
|
||||
.code
|
||||
public _ChecksumFile
|
||||
_ChecksumFile proc near
|
||||
push bp
|
||||
mov bp,sp
|
||||
push si ;save C’s register variable
|
||||
;
|
||||
mov bx,[bp+Handle] ;get file handle
|
||||
sub si,si ;zero the checksum ;accumulator
|
||||
mov cx,1 ;request one byte on each ;read
|
||||
mov dx,offset TempByte ;point DX to the byte in
|
||||
;which DOS should store
|
||||
;each byte read
|
||||
ChecksumLoop:
|
||||
mov ah,3fh ;DOS read file function #
|
||||
int 21h ;read the byte
|
||||
jcErrorEnd;an error occurred
|
||||
and ax,ax ;any bytes read?
|
||||
jz Success ;no-end of file reached-we’re done
|
||||
add si,[TempWord] ;add the byte into the
|
||||
;checksum total
|
||||
jmpChecksumLoop
|
||||
ErrorEnd:
|
||||
sub ax,ax ;error
|
||||
jmp short Done
|
||||
Success:
|
||||
mov bx,[bp+Checksum] ;point to the checksum variable
|
||||
mov [bx],si ;save the new checksum
|
||||
mov ax,1 ;success
|
||||
;
|
||||
Done:
|
||||
pop si ;restore C’s register variable
|
||||
pop bp
|
||||
ret
|
||||
_ChecksumFileendp
|
||||
end
|
||||
|
||||
The lesson is clear: Optimization makes code faster, but without proper
|
||||
design, optimization just creates fast slow code.
|
||||
|
||||
Well, then, how are we going to improve our design? Before we can do
|
||||
that, we have to understand what’s wrong with the current design.
|
||||
|
||||
#### Know the Territory {#Heading9}
|
||||
|
||||
Just why is Listing 1.1 so slow? In a word: overhead. The C library
|
||||
implements the **read()** function by calling DOS to read the desired
|
||||
number of bytes. (I figured this out by watching the code execute with a
|
||||
debugger, but you can buy library source code from both Microsoft and
|
||||
Borland.) That means that Listing 1.1 (and Listing 1.3 as well) executes
|
||||
one DOS function per byte processed—and DOS functions, especially this
|
||||
one, come with a lot of overhead.
|
||||
|
||||
For starters, DOS functions are invoked with interrupts, and interrupts
|
||||
are among the slowest instructions of the x86 family CPUs. Then, DOS has
|
||||
to set up internally and branch to the desired function, expending more
|
||||
cycles in the process. Finally, DOS has to search its own buffers to see
|
||||
if the desired byte has already been read, read it from the disk if not,
|
||||
store the byte in the specified location, and return. All of that takes
|
||||
a *long* time—far, far longer than the rest of the main loop in Listing
|
||||
1.1. In short, Listing 1.1 spends virtually all of its time executing
|
||||
**read(),** and most of that time is spent somewhere down in DOS.
|
||||
|
||||
You can verify this for yourself by watching the code with a debugger or
|
||||
using a code profiler, but take my word for it: There’s a great deal of
|
||||
overhead to DOS calls, and that’s what’s draining the life out of
|
||||
Listing 1.1.
|
||||
|
||||
How can we speed up Listing 1.1? It should be clear that we must somehow
|
||||
avoid invoking DOS for every byte in the file, and that means reading
|
||||
more than one byte at a time, then buffering the data and parceling it
|
||||
out for examination one byte at a time. By gosh, that’s a description of
|
||||
C’s stream I/O feature, whereby C reads files in chunks and buffers the
|
||||
bytes internally, doling them out to the application as needed by
|
||||
reading them from memory rather than calling DOS. Let’s try using stream
|
||||
I/O and see what happens.
|
||||
|
||||
Listing 1.4 is similar to Listing 1.1, but uses **fopen()** and
|
||||
**getc()** (rather than **open()** and **read()**) to access the file
|
||||
being checksummed. The results confirm our theories splendidly, and
|
||||
validate our new design. As shown in Table 1.1, Listing 1.4 runs more
|
||||
than an order of magnitude faster than even the assembly version of
|
||||
Listing 1.1, *even though Listing 1.1 and Listing 1.4 look almost the
|
||||
same*. To the casual observer, **read()** and **getc()** would seem
|
||||
slightly different but pretty much interchangeable, and yet in this
|
||||
application the performance difference between the two is about the same
|
||||
as that between a 4.77 MHz PC and a 16 MHz 386.
|
||||
|
||||
------------------------ --------------------------------- --------------------
|
||||
[Previous](01-02.html) [Table of Contents](index.html) [Next](01-04.html)
|
||||
------------------------ --------------------------------- --------------------
|
||||
|
||||
* * * * *
|
||||
|
||||
Graphics Programming Black Book © 2001 Michael Abrash
|
||||
Loading…
Reference in a new issue