home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / JSAGE / ZSUS / TCJ / TCJ40LH.WS < prev    next >
Text File  |  2000-06-30  |  20KB  |  366 lines

  1.                         PROGRAMMING FOR PERFORMANCE
  2.                                   PART 2
  3.  
  4.                                by Lee A. Hart
  5.                         The Computer Journal, Issue 40
  6.                           Reproduced with permission
  7.                            of author and publisher
  8.  
  9.                              Know The Hardware
  10.  
  11.    Truly efficient software has an intimate, almost incestuous relationshipì
  12. with its hardware.  They merge so thoroughly as to become inseparable;ì
  13. neither makes any sense without the other.
  14.  
  15.    This requires that you, the programmer, must TOTALLY understand theì
  16. hardware.  I cannot stress this point too strongly.  The strengths andì
  17. weaknesses of the hardware influence program structure at every level, notì
  18. just the low-level drivers.  A system with weak disk I/O will be slow andì
  19. unresponsive if your program relies on overlays.  A shallow keyboard bufferì
  20. requires frequent checks to avoid missing keys.  The characteristics of the ì
  21. console device determines your whole approach to data displays.  If you tryì
  22. to hide from these limitations in a high-level language, your program willì
  23. work as if it were written in BASIC 101.  Let's consider some actual caseì
  24. histories of what can be gained by paying attention to the hardware.
  25.  
  26. CASE #1
  27.  
  28.    A customer needed a faster way to transfer data between two computers. ì
  29. He had been using a serial port at 9600 baud but complained that it was tooì
  30. slow and tied up the computer's serial port.  Hardware mods were ruled out.
  31.  
  32.    After study, I found that each computer had unused handshake lines in itsì
  33. RS-232 port.  A special "Y" cable was built to cross-connect two of theseì
  34. lines, providing one bit of serial I/O in each direction.  A "software UART"ì
  35. program was then written to transfer data between the two machines.  Thisì
  36. worked to about 30K  bits per second before timing dither (due toì
  37. interrupts, memory refresh, etc.) caused errors.
  38.  
  39.    The serial port's UART could be programmed to generate an interrupt whenì
  40. the handshake line went low.  Therefore, an interrupt-driven protocol withì
  41. handshaking was devised.  A '0' was sent by pulling the output low until theì
  42. other computer echoed the low on its output.  A '1' was sent by pulsing theì
  43. output low and immediately back high and waiting until the other systemì
  44. echoed it.  The data rate increased to over 100K bits per second, andì
  45. transfers were now unaffected by disk I/O, keyboard activity, etc.
  46.  
  47. CASE 2
  48.  
  49.    The firmware for a CRT terminal was to be upgraded to run 38400 bits perì
  50. second without handshaking.  Now, 38400 bps is fast, only 260 microsecondsì
  51. per character (about 75 instructions for a 3 MHz Z80).
  52. è   The slowest routines need the most attention.  For example, clear-lineì
  53. was accomplished by moving the stack pointer to the end of the line andì
  54. executing 36 PUSH HL instructions.  The interrupt handler needed a 4-levelì
  55. stack, so the last 8 bytes were cleared normally.  Clear-screen used 25ì
  56. iterations of clear-line.
  57.  
  58.    This still isn't fast enough to complete every ESC sequence before theì
  59. next one is received.  This calls for an interrupt-driven system.  Eachì
  60. character received generates an interrupt.  The interrupt handler pushes theì
  61. character into one end of a FIFO (First-In-First-Out) buffer in memory.  Theì
  62. main program pops characters out the other end and processes them.  The FIFOì
  63. fills while we process slow commands like clear-screen and empties back outì
  64. during fast commands.
  65.  
  66.    But what if some idiot sends a long string of slow commands (like 100ì
  67. clear-screens in a row)?  The FIFO would eventually overflow, and data wouldì
  68. be lost.  I prevented this with "look-ahead" logic.  When the interruptì
  69. handler spots a clear-screen command, it sets a flag so MAIN expects it. ì
  70. MAIN can then ignore unnecessary commands (no sense altering a screen that'sì
  71. about to be cleared). 
  72.  
  73.    Scrolling is one of the most difficult actions.  The obvious algorithm isì
  74. to block move lines 2-24 up 1, then clear line 24.  But that's what IBM didì
  75. on the PC, and we all know how well that worked.  So examine the 6845 CRTì
  76. controller.  The Start-Address register holds the address of the firstì
  77. character on the screen, the one displayed in the top left corner.  If weì
  78. add 80 to it, line 2 instantly becomes the top line, and we've scrolled theì
  79. whole screen up a line.  All that remains is to clear the 80 bytes that ì
  80. form the new 24th line, for which we have a fast routine.
  81.  
  82.    Each scroll moves the start address up another 80 bytes.  This obviouslyì
  83. can't go on indefinitely, so the original program spent a great deal of timeì
  84. checking for overflow outside its 2K block of screen RAM (F800-FFFF).  Forì
  85. instance, the old code read:
  86.  
  87.      ld   (hl),a    ; put character on screen
  88.      inc  hl        ; advance to next
  89.      ld   a,h       ; get new address
  90.      or   0F8h      ; if overflow to 0000,
  91.      ld   h,a       ;   force it to F800-FFFF
  92.  
  93.    But is this really necessary?  The schematic revealed that the 2K RAM wasì
  94. partially decoded and actually occupied 16K in the Z80's address spaceì
  95. (C000-FFFF).  It's far easier to insure that an address lies within thisì
  96. range:
  97.  
  98.      ld   (hl),a    ; put character on screen
  99.      res  6,h       ; insure we don't wrap to 0000
  100.      inc  hl        ; advance to next
  101.  
  102. CASE #3
  103. è   Fast Disk I/O.  Way back in 8 B.C. (eight years Before Clones) I had anì
  104. S-100 system.  Its 8080 CPU blazed along at 1.843 MHz, through 32K of RAMì
  105. spread over half a dozen furnace boards.  Two Shugart SA-801R single-sidedì
  106. 8" drives provided disk storage, with CP/M 1.4 tying it all together.  Thatì
  107. old war horse and I fought many battles together, until it finally died theì
  108. Death-of-1000-Intermittents.
  109.  
  110.    Many of its "features" I'd rather forget, but it had one outstandingì
  111. attribute: the fastest floppies I've ever seen.  Warm boots were done beforeì
  112. your fingers were off the keys; Wordstar loaded in under a second; PIPì
  113. copied files at 10K bytes/sec.  All without a fast CPU, DMA, vectoredì
  114. interrupts, or even a disk controller IC.  The "controller" was just a bunchì
  115. of TTL chips implementing a parallel port, an 8-bit shift register, and aì
  116. CRC checkcode generator.  The real work was done by the CPU, byte-bangingì
  117. out the IBM 3740 SD/DD format in software.
  118.  
  119.    How good was it?  An 8" disk spins at 360 rpm, or 6 revs/sec.  Each trackì
  120. held 6.5K (26 double-density sectors of 256 bytes each).  That makes theì
  121. theoretical maximum transfer rate 6.5K x 6 = 39K bytes/sec.  It actuallyì
  122. achieved 50% of this, or 20K bytes/sec.
  123.  
  124.    Few modern micros come anywhere near this level of performance.  Theì
  125. Kaypro I wrote this article on creeps through the disk at 4K/sec.  My PCì
  126. clone is closer, at 12K/sec.  The problem is that the CPU spends most of itsì
  127. time in wait loops; waiting for the drive motor to start, for the head toì
  128. load, for an index hole, for a certain sector to come around on the disk.ì
  129. The capabilities of fast CPUs, elaborate interrupt systems, DMA, and fancyì
  130. disk controllers are thrown away by crude software.
  131.  
  132.    The CPU has better things to do.  If the disk isn't ready when an ì
  133. application program needs it, the BIOS should start the task, save the dataì
  134. in a buffer, and set up an interrupt to finish the task later when the diskì
  135. is REALLY ready.  The time lost to wait loops is thus reclaimed to run yourì
  136. application programs.
  137.  
  138.    That's how my antique worked.  The BIOS maintained a track buffer in RAM.ì
  139. The first read from a particular track moved the head to the desired trackì
  140. and read the whole thing into the buffer.  Further reads from that trackì
  141. simply came from RAM, taking virtually no time at all.
  142.  
  143.    Similarly, writes to a sector on the current track just put data in theì
  144. buffer and marked it as changed.  The actual write was performed later, whenì
  145. a new track was selected for read/write, or just before the drive timed outì
  146. from a lack of disk activity.
  147.  
  148.    Physical track reads/writes were fast as well.  The key was to simplyì
  149. begin wherever the head was.  After seeking to the desired track, it readì
  150. the ID# of each sector encountered and transferred it to/from the appropriateì
  151. place in the RAM buffer.  No need to find the index hole, wait for aì
  152. particular sector ID#, or worry about interleave; one revolution got it all.
  153.  
  154.    Such a system must be implemented carefully.  CP/M does not expectìèdelayed error messages, which can produce some odd results.  For instance, aì
  155. BDOS read error might be reported when the real cause was a write error inì
  156. flushing the previous track buffer to disk.  Also, modern drives do not haveì
  157. door locks to prevent disk removal if unwritten data remains in the trackì
  158. buffer.
  159.  
  160.    The main factor limiting my S-100 system's performance was the slow CPUì
  161. and lack of DMA.  A double-density 8" disk has a peak data transfer rate ofì
  162. 500K bits/sec, which only allows 16 microseconds between bytes. Thisì
  163. required polled I/O where the CPU was 100% devoted to the disk during actualì
  164. reads/writes.
  165.  
  166.    5-1/4" disks have a slower maximum transfer rate, but modern hardware hasì
  167. advantages that can make up for it.  A normal 5-1/4" disk spins at 300 rpm,ì
  168. or 5 rev/sec. Assuming 9 sectors of 512 bytes per track, the maximumì
  169. transfer rate is 22.5K bytes/sec.  The peak data rate is 250K bits/sec, orì
  170. 32 microseconds per byte. This is slow enough for a 4 MHz Z80 to (barely)ì
  171. handle it on an interrupt basis.  Here's an interrupt handler to read 256ì
  172. bytes from a disk controller chip at 32 microseconds max. per byte:
  173.  
  174. T-states
  175.    23                       ; time to finish longest instruction
  176.    13                       ; Z80 interrupt mode 0 or 1 response
  177.    11 int:  push af         ; save registers used
  178.    11       in   a,(data)   ; read data byte from disk controller
  179.    13 next: ld   (buffer),a ; store it in buffer (a variable)
  180.    13       ld   a,(next+1) ; get buffer address
  181.     4       inc  a          ;   increment
  182.    13       ld   (next+1),a ;   save for next time
  183.     7       jr   nz,done    ; if end of page, done
  184.    10       pop  af         ;   else restore registers
  185.    10       ret             ;   and return
  186.   ----
  187.   128 T-states max = 32 microseconds with a 4 MHz Z80
  188.  
  189.    But this routine barely squeaks by. It can't use interrupt mode 2 (whichì
  190. adds 6 T-states to the response time) or signal Z80 peripherals that theì
  191. interrupt is complete with an RETI (which adds 4 T-states).  It's limited toì
  192. a 256-byte sector.  Worse, some disk controller chips need processing timeì
  193. of their own.  The popular Western Digital FD179x series only allows 27.5ì
  194. microseconds for each byte.
  195.  
  196.    So we have to get clever again.  The following example reads pairs ofì
  197. bytes, the first on an interrupt and the second by polled I/O.  Thisì
  198. improves performance to allow interrupt mode 2, larger sector sizes, and theì
  199. slow response time of a FD179x chip:
  200.  
  201. T-states
  202.    23                       ; time to finish longest instruction
  203.    19                       ; Z80 interrupt mode 2 response time
  204.    11 int:  push af         ; save A and flags
  205.    11       in   a,(data)   ; read 1st byte from disk controllerè   11       push hl         ; save HL
  206.    10 next: ld   hl,buffer  ; get buffer address (a variable)
  207.     7       ld   (hl),a     ; store byte in buffer
  208.     6       inc  hl         ; advance buffer pointer
  209.     6       inc  hl         ;   for next interrupt
  210.    16       ld   (next+1),hl;   & store it
  211.     6       dec  hl         ;   point to current address
  212. 11+11 check:in   a,(status) ; check disk controller status
  213.  4+ 4       rra             ; if not busy (bit 0=1),
  214.  7+ 7       jr   nc,done    ;   then we're done
  215.  4+ 4       rra             ; if next byte not ready (bit 1=0),
  216. 12+ 7       jr   nc,check   ;   then loop until it is
  217.    11       in   a,(data)   ; get 2nd byte from disk controller
  218.     7       ld   (hl),a     ;   & store it in buffer
  219.    10       pop  hl         ; restore registers
  220.    10       pop  af
  221.    14       reti            ; return
  222.   ----
  223.   188 or 226 T-states (for 1 or 2 passes through status loop)
  224.  
  225.    This routine reads bytes from the controller chip within 17.75ì
  226. microseconds worst-case.  Interrupt overhead averages 80% for a 4 MHz Z80,ì
  227. leaving 20% for the main program execution.  The peculiar way ofì
  228. incrementing the address pointer minimizes the worst-case delay from anì
  229. interrupt or status flag change until the byte is read.  We want to maximizeì
  230. the chance that the second character is ready the first time the status isì
  231. checked.
  232.  
  233.    Why improve your disk system?  Because, as a practical matter, there'sì
  234. more to be gained by improving it than any other change you could make. ì
  235. It's disk I/O that sets the pace, not CPU speed or memory size.  Usersì
  236. almost never wait on CPU speed; it's the disk that keeps you twiddling yourì
  237. thumbs with the keyboard ignored, the screen frozen, and the disk driveì
  238. emitting Bronx cheers.  Put a Commodore 64's tinkertoy disk system on an AT¡
  239. clone, and you'd have high-priced junk that only a masochist would use.ì
  240. Conversely, the AT's DMA-based disk I/O would transform a C64 into a fire¡
  241. breathing dragon that would eat its competition alive.
  242.  
  243.  
  244.                                  Algorithms
  245.  
  246.    When a hardware engineer sits down to design a circuit, he doesn't beginì
  247. with a blank sheet of paper.  He has a vast library of textbooks, dataì
  248. sheets, and catalogs of standard circuits to choose from.  Most of the taskì
  249. is simply connecting off-the-shelf components into one of these standardì
  250. configurations, modifying them as necessary to satisfy any uniqueì
  251. requirements.
  252.  
  253.    Algorithms are to programmers what IC chips are to hardware designers.ì
  254. Just as the engineer builds a library of standard parts and circuits, everyì
  255. programmer must continually build his own algorithm collection.  Whetherì
  256. it's a shoebox full of magazine clippings or a carefully indexed series ofìènotebooks, start NOW.
  257.  
  258.    Programming textbooks tend to concentrate on traditional computer ì
  259. algorithms for floating-point math, transcendental functions, and sortingì
  260. routines.  The old standby is Knuth's "The Art of Programming".  Hamming'sì
  261. "Numerical Methods for Scientists and Engineers" explains the basics ofì
  262. iterative calculations.  "Digital Computation and Numerical Methods" byì
  263. Southworth and Deeleeuw provides detailed flowcharts and sample code asì
  264. well.
  265.  
  266.    Magazines are a great source and tend to be more down-to-earth and closerì
  267. to the state of the art.  Read carefully!  Good algorithms may be expressedì
  268. in BASIC listings, assembly code for some obscure processor, pocketì
  269. calculator key sequences, and even disguised as circuit diagrams.ì
  270. Professional journals like EDN or Computer Design are often better than theì
  271. popular magazines, which have pretty much abandoned education in favor ofì
  272. marketing.  Especially check out back issues.  The cruder the hardware, theì
  273. trickier the algorithms had to be to make up for it.
  274.  
  275.    Manufacturers' technical literature is a gold mine. Get the ì
  276. manufacturers' own manuals, not some boiled-down paperback from theì
  277. bookstore.  They won't be models of clarity but are full of hidden gold.ì
  278. Read everything, hardware and software manuals, data sheets, applicationì
  279. notes, etc.
  280.  
  281.    User groups are the traditional source of solutions to specific ì
  282. problems.  Even better, they provide actual implementations in printedì
  283. listings, on disk, or even by modem.
  284.  
  285.    Don't waste time reinventing the wheel.  Learn from others what works,ì
  286. and what doesn't.  Some of the best (and worst) algorithms I know were foundì
  287. by disassembling existing programs.  And once you find a good algorithm,ì
  288. recycle it.  That clever sort routine for an antique 8008 may be theì
  289. foundation of the fastest '386 sort yet!
  290.  
  291.  
  292.                                  Conclusion
  293.  
  294.    These techniques are not new; in fact old-timers will recognize many ofì
  295. them from the early days of computing when hardware limitations were moreì
  296. severe.  However, they have fallen into disuse.  A whole generation ofì
  297. programmers has been taught that such techniques have no place in modernì
  298. structured programming.
  299.  
  300.    The theory goes something like this: Programs written in a high-levelì
  301. language are faster and easier to write, debug, document, and maintain.ì
  302. Memory and speed are viewed as infinite resources, so the performance lossì
  303. is unimportant.  Programs should be totally generic; it is the compiler's orì
  304. run-time library's job to worry about the hardware interface.
  305.  
  306.    These rules make sense in a mainframe environment, where the hardwareì
  307. resources are truly awesome, and teams of programmers spend years working onìèone application.  But they impose severe penalties on a microcomputerì
  308. system.  The user must pay for the programmer's luxuries with higherì
  309. hardware cost and lackluster performance.
  310.  
  311.    It's easy to forget that "microcomputer" literally means "one millionthì
  312. of a computer".  Microprocessors make abysmally bad CPUs.  Build a computerì
  313. with one, and you'll wind up needing $5000 worth of memory and peripheralsì
  314. to support a $5 CPU chip.
  315.  
  316.    But micros make superlative controllers.  That's what they were designedì
  317. for, and what they do best.  A single microcomputer can replace dozens ofì
  318. boards and hundreds of ICs with as little as a single chip.  That's why 90%ì
  319. of all microprocessors go into non-computer uses: calculators, auto emissionì
  320. controls, home entertainment equipment, industrial controls, and the like.ì
  321. Of 30 million Z80s sold last year, fewer than 1 million went into computers.
  322.  
  323.    Programming a controller is different than a computer.  Most applicationsì
  324. demand real-time multi-tasking capabilities, and there is never enough speedì
  325. or memory.  Inputs and outputs are physical hardware devices, not abstractì
  326. data structures, so the code must inevitably be hardware-dependent. ì
  327. Computer languages are just not cut out for this sort of thing.
  328.  
  329.    The question is not, "How do I write a computer program to handle thisì
  330. data?"  Instead, you should ask yourself, "How must I manipulate thisì
  331. hardware to do the job?"  The techniques in this article may be out of placeì
  332. in the bureaucracy of a large computer but are right at home in the wild¡
  333. west world of a microcomputer.
  334.  
  335.    Lest you think this has nothing to do with a "real" computer like your PCì
  336. clone, consider this.  Instead of a '286 with 1 meg of memory, suppose itì
  337. contained ten Z80 controller boards, each with 64K of memory and a fastì
  338. network to tie them together.  Each Z80 handles a different device:ì
  339. keyboard, screen, printer, modem, and one for each disk.  The rest are freeì
  340. to run application programs, several at a time!
  341.  
  342.    Suppose you're doing word processing on this system.  The keyboard doesì
  343. spelling correction on data entry.  The screen Z80 displays your text inì
  344. bit-mapped fonts to match the printer's Z80, which is simultaneouslyì
  345. printing a file.  The Z80 running the word processor itself suffers noì
  346. annoying pauses or hesitation, since disk I/O is handled instantaneously viaì
  347. each drive's Z80 track buffer.  Meanwhile, the modem's Z80 is downloading aì
  348. file while another assembles a program.  Pop-up utilities are ready andì
  349. waiting in still other Z80s in case they're needed.
  350.  
  351.    Such a system would clearly have half the hardware cost of a PC, yetì
  352. would outperform it by a wide margin.  True multi-tasking becomes child'sì
  353. play with multiple processors.  More processors can be readily added forì
  354. even higher performance, or removed to save cost (or continue operationì
  355. while waiting for a replacement).
  356.  
  357.    If the computer scientists really want to further the micro-revolution,ì
  358. they should stop trying to force antiquated mainframe languages onto microsìèand concentrate on developing tools to maximize the use of micros as theyì
  359. are!
  360.  
  361. [This article was originally published in issue 40 of The Computer Journal,
  362. P.O. Box 12, South Plainfield, NJ 07080-0012 and is reproduced with the
  363. permission of the author and the publisher. Further reproduction for non-
  364. commercial purposes is authorized. This copyright notice must be retained.
  365. (c) Copyright 1989, 1991 Socrates Press and respective authors]
  366.