abrash-black-book/01-04.html
2013-12-30 12:21:49 +11:00

124 lines
7.4 KiB
HTML

<HTML>
<HEAD>
<META name=vsisbn content="1576101746">
<META name=vstitle content="Michael Abrash's Graphics Programming Black Book, Special Edition">
<META name=vsauthor content="Michael Abrash">
<META name=vspublisher content="The Coriolis Group">
<META name=vspubdate content="07/01/97">
<META name=vscategory content="Web and Software Development: Game Development,Web and Software Development: Graphics and Multimedia Development">
<TITLE>Michael Abrash's Graphics Programming Black Book Special Edition: The Best Optimizer Is between Your Ears</TITLE>
<!-- HEADER -->
<!-- Empty Reference Subhead -->
<!--ISBN=1576101746//-->
<!--TITLE=Michael Abrash's Graphics Programming Black Book Special Edition//-->
<!--AUTHOR=Michael Abrash//-->
<!--PUBLISHER=The Coriolis Group, Inc.//-->
<!--CHAPTER=01//-->
<!--PAGES=013-015//-->
<!--UNASSIGNED1//-->
<!--UNASSIGNED2//--></HEAD><BODY LINK=#0000FF ALINK=#000099 VLINK=#0000FF BGCOLOR=#FFFFFF>
<CENTER>
<TABLE BORDER>
<TR>
<TD><A HREF="01-03.html">Previous</A></TD>
<TD><A HREF="index.html">Table of Contents</A></TD>
<TD><A HREF="01-05.html">Next</A></TD>
</TR>
</TABLE>
</CENTER>
<P><BR></P>
<TABLE WIDTH="100%">
<TD WIDTH="5%" VALIGN="TOP"><IMG SRC="images/01-03i.jpg"><TD WIDTH="95%"><SMALL><I>Make sure you understand what really goes on when you insert a seemingly-innocuous function call into the time-critical portions of your code.</I></SMALL>
</TABLE>
<P>In this case that means knowing how DOS and the C/C<SMALL>&#43;&#43;</SMALL> file-access libraries do their work. In other words, <I>know the territory</I>!</P>
<P><B>LISTING 1.4 L1-4.C</B></P>
<!-- CODE //-->
<PRE>
/*
* Program to calculate the 16-bit checksum of the stream of bytes
* from the specified file. Obtains the bytes one at a time via
* getc(), allowing C to perform data buffering.
*/
#include &lt;stdio.h&gt;
main(int argc, char *argv[]) {
FILE *CheckFile;
int Byte;
unsigned int Checksum;
if ( argc != 2 ) {
printf(&#147;usage: checksum filename\n&#148;);
exit(1);
}
if ( (CheckFile = fopen(argv[1], &#147;rb&#148;)) == NULL ) {
printf(&#147;Can&#146;t open file: %s\n&#148;, argv[1]);
exit(1);
}
/* Initialize the checksum accumulator */
Checksum = 0;
/* Add each byte in turn into the checksum accumulator */
while ( (Byte = getc(CheckFile)) != EOF ) {
Checksum &#43;= (unsigned int) Byte;
}
/* Report the result */
printf(&#147;The checksum is: %u\n&#148;, Checksum);
exit(0);
}
</PRE>
<!-- END CODE //-->
<H4 ALIGN="LEFT"><A NAME="Heading10"></A><FONT COLOR="#000077">Know When It Matters</FONT></H4>
<P>The last section contained a particularly interesting phrase: <I>the time-critical portions of your code</I>. Time-critical portions of your code are those portions in which the speed of the code makes a significant difference in the overall performance of your program&#151;and by &#147;significant,&#148; I don&#146;t mean that it makes the code 100 percent faster, or 200 percent, or any particular amount at all, but rather that it makes the program more responsive and/or usable <I>from the user&#146;s perspective</I>.</P>
<P>Don&#146;t waste time optimizing non-time-critical code: set-up code, initialization code, and the like. Spend your time improving the performance of the code inside heavily-used loops and in the portions of your programs that directly affect response time. Notice, for example, that I haven&#146;t bothered to implement a version of the checksum program entirely in assembly; Listings 1.2 and 1.6 call assembly subroutines that handle the time-critical operations, but C is still used for checking command-line parameters, operning files, printing, and the like.</P>
<TABLE WIDTH="100%"><TD WIDTH="5%" VALIGN="TOP"><IMG SRC="images/01-04i.jpg"><TD WIDTH="95%"><SMALL><I>If you were to implement any of the listings in this chapter entirely in hand-optimized assembly, I suppose you might get a performance improvement of a few percent&#151;but I rather doubt you&#146;d get even that much, and you&#146;d sure as heck spend an awful lot of time for whatever meager improvement does result. Let C do what it does well, and use assembly only when it makes a perceptible difference.</I></SMALL>
</TABLE>
<P>Besides, we don&#146;t want to optimize until the design is refined to our satisfaction, and that won&#146;t be the case until we&#146;ve thought about other approaches.
</P>
<H4 ALIGN="LEFT"><A NAME="Heading11"></A><FONT COLOR="#000077">Always Consider the Alternatives</FONT></H4>
<P>Listing 1.4 is good, but let&#146;s see if there are other&#151;perhaps less obvious&#151;ways to get the same results faster. Let&#146;s start by considering why Listing 1.4 is so much better than Listing 1.1. Like <B>read()</B>, <B>getc()</B> calls DOS to read from the file; the speed improvement of Listing 1.4 over Listing 1.1 occurs because <B>getc()</B> eads many bytes at once via DOS, then manages those bytes for us. That&#146;s faster than reading them one at a time using <B>read()</B>&#151;but there&#146;s no reason to think that it&#146;s faster than having our program read and manage blocks itself. Easier, yes, but not faster.</P>
<P>Consider this: Every invocation of <B>getc()</B> involves pushing a parameter, executing a call to the C library function, getting the parameter (in the C library code), looking up information about the desired stream, unbuffering the next byte from the stream, and returning to the calling code. That takes a considerable amount of time, especially by contrast with simply maintaining a pointer to a buffer and whizzing through the data in the buffer inside a single loop.</P>
<P>There are four reasons that many programmers would give for not trying to improve on Listing 1.4:</P>
<DL>
<DD><B>1.</B>&nbsp;&nbsp;The code is already fast enough.
<DD><B>2.</B>&nbsp;&nbsp;The code works, and some people are content with code that works, even when it&#146;s slow enough to be annoying.
<DD><B>3.</B>&nbsp;&nbsp;The C library is written in optimized assembly, and it&#146;s likely to be faster than any code that the average programmer could write to perform essentially the same function.
<DD><B>4.</B>&nbsp;&nbsp;The C library conveniently handles the buffering of file data, and it would be a nuisance to have to implement that capability.
</DL>
<P>I&#146;ll ignore the first reason, both because performance is no longer an issue if the code is fast enough and because the current application does <I>not</I> run fast enough&#151;13 seconds is a long time. (Stop and wait for 13 seconds while you&#146;re doing something intense, and you&#146;ll see just how long it is.)</P>
<P>The second reason is the hallmark of the mediocre programmer. Know when optimization matters&#151;and then optimize when it does!</P><P><BR></P>
<CENTER>
<TABLE BORDER>
<TR>
<TD><A HREF="01-03.html">Previous</A></TD>
<TD><A HREF="index.html">Table of Contents</A></TD>
<TD><A HREF="01-05.html">Next</A></TD>
</TR>
</TABLE>
</CENTER>
<hr width="90%" size="1" noshade>
<div align="center">
<font face="Verdana,sans-serif" size="1">Graphics Programming Black Book &copy; 2001 Michael Abrash</font>
</div>
<!-- all of the reference materials (books) have the footer and subfoot reveresed -->
<!-- reference_subfoot = footer -->
<!-- reference_footer = subfoot -->
<!-- BEGIN SUB FOOTER -->
</BODY>
</HTML>
<!-- END FOOTER -->