abrash-black-book/01-04.html

144 lines
7.1 KiB
HTML

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<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>
<meta name="chapter" content="01" />
<meta name="pages" content="013-015" />
</head>
<body>
<center>
<table border="1">
<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>
<table width="100%">
<tr>
<td width="5%" valign="top"><img src="images/i.jpg" /></td>
<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></td>
</tr>
</table>
<p>In this case that means knowing how DOS and the C/C<small>++</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>
<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(&ldquo;usage: checksum filename\n&rdquo;);
exit(1);
}
if ( (CheckFile = fopen(argv[1], &ldquo;rb&rdquo;)) == NULL ) {
printf(&ldquo;Can&rsquo;t open file: %s\n&rdquo;, 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 += (unsigned int) Byte;
}
/* Report the result */
printf(&ldquo;The checksum is: %u\n&rdquo;, Checksum);
exit(0);
}
</pre>
<h4 id="Heading10">Know When It Matters</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&mdash;and by &ldquo;significant,&rdquo; I don&rsquo;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&rsquo;s perspective</i>.</p>
<p>Don&rsquo;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&rsquo;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%">
<tr>
<td width="5%" valign="top"><img src="images/i.jpg" /></td>
<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&mdash;but I rather doubt you&rsquo;d get even that much, and you&rsquo;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></td>
</tr>
</table>
<p>Besides, we don&rsquo;t want to optimize until the design is refined to our satisfaction, and that won&rsquo;t be the case until we&rsquo;ve thought about other approaches.</p>
<h4 id="Heading11">Always Consider the Alternatives</h4>
<p>Listing 1.4 is good, but let&rsquo;s see if there are other&mdash;perhaps less obvious&mdash;ways to get the same results faster. Let&rsquo;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&rsquo;s faster than reading them one at a time using <b>read()</b>&mdash;but there&rsquo;s no reason to think that it&rsquo;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>
<dd><b>2.</b>&nbsp;&nbsp;The code works, and some people are content with code that works, even when it&rsquo;s slow enough to be annoying.</dd>
<dd><b>3.</b>&nbsp;&nbsp;The C library is written in optimized assembly, and it&rsquo;s likely to be faster than any code that the average programmer could write to perform essentially the same function.</dd>
<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.</dd>
</dl>
<p>I&rsquo;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&mdash;13 seconds is a long time. (Stop and wait for 13 seconds while you&rsquo;re doing something intense, and you&rsquo;ll see just how long it is.)</p>
<p>The second reason is the hallmark of the mediocre programmer. Know when optimization matters&mdash;and then optimize when it does!</p>
<center>
<table border="1">
<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="noshade" />
<div align="center">
Graphics Programming Black Book &copy; 2001 Michael Abrash
</div>
</body>
</html>