home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / Information / CSMP Digest / volume 1 / csmp-v1-198.txt < prev    next >
Encoding:
Text File  |  1994-12-08  |  47.2 KB  |  1,298 lines  |  [TEXT/R*ch]

  1. C.S.M.P. Digest             Wed, 28 Oct 92       Volume 1 : Issue 198
  2.  
  3. Today's Topics:
  4.  
  5.     Better random number than Random()?
  6.     BlockZero.c snippet
  7.  
  8.  
  9.  
  10. The Comp.Sys.Mac.Programmer Digest is moderated by Michael A. Kelly.
  11.  
  12. The digest is a collection of article threads from the internet newsgroup
  13. comp.sys.mac.programmer.  It is designed for people who read c.s.m.p. semi-
  14. regularly and want an archive of the discussions.  If you don't know what a
  15. newsgroup is, you probably don't have access to it.  Ask your systems
  16. administrator(s) for details.  (This means you can't post questions to the
  17. digest.)
  18.  
  19. Each issue of the digest contains one or more sets of articles (called
  20. threads), with each set corresponding to a 'discussion' of a particular
  21. subject.  The articles are not edited; all articles included in this digest
  22. are in their original posted form (as received by our news server at
  23. cs.uoregon.edu).  Article threads are not added to the digest until the last
  24. article added to the thread is at least one month old (this is to ensure that
  25. the thread is dead before adding it to the digest).  Article threads that
  26. consist of only one message are generally not included in the digest.
  27.  
  28. The entire digest is available for anonymous ftp from ftp.cs.uoregon.edu
  29. [128.223.8.8] in the directory /pub/mac/csmp-digest.  Be sure to read the
  30. file /pub/mac/csmp-digest/README before downloading any files.  The most
  31. recent issues are available from sumex-aim.stanford.edu [36.44.0.6] in the
  32. directory /info-mac/digest/csmp.  If you don't have ftp capability, the sumex
  33. archive has a mail server; send a message with the text '$MACarch help' (no
  34. quotes) to LISTSERV@ricevm1.rice.edu for more information.
  35.  
  36. The digest is also available via email.  Just send a note saying that you
  37. want to be on the digest mailing list to mkelly@cs.uoregon.edu, and you will
  38. automatically receive each new issue as it is created.  Sorry, back issues
  39. are not available through the mailing list.
  40.  
  41. Send administrative mail to mkelly@cs.uoregon.edu.
  42.  
  43.  
  44. -------------------------------------------------------
  45.  
  46. From: hd12@ellis.uchicago.edu (hui  dong)
  47. Subject: Better random number than Random()?
  48. Date: 18 Sep 92 10:54:10 GMT
  49. Organization: University of Chicago Computing Organizations
  50.  
  51. (I did check FAQ before I post this.)
  52.  
  53. I need a fast (speed is very important) random number generator. Right now
  54. I am using Random(), but it seems to me the distribution is not uniform
  55. at all. Is there a better generator? Will it be faster to use my own
  56. function than to use toolbox routine?
  57. Thanks for the help.
  58.  
  59. +++++++++++++++++++++++++++
  60.  
  61. From: fry@tara.harvard.edu (David Fry)
  62. Date: 19 Sep 92 05:20:38 GMT
  63. Organization: Harvard Math Department
  64.  
  65. In article <1992Sep18.105410.24438@midway.uchicago.edu> hd12@midway.uchicago.edu writes:
  66. >(I did check FAQ before I post this.)
  67. >
  68. >I need a fast (speed is very important) random number generator. Right now
  69. >I am using Random(), but it seems to me the distribution is not uniform
  70. >at all. Is there a better generator? Will it be faster to use my own
  71. >function than to use toolbox routine?
  72. >Thanks for the help.
  73.  
  74. This probably should be in the FAQ list because it comes up all the
  75. time (and it seems I'm always the one to answer it).  Random() is a
  76. quite good random number generator, and it is pretty fast. It will
  77. almost certainly be faster than one you write yourself, provided the
  78. one you write yourself is as good. 
  79.  
  80. Are you changing the randSeed seed variable before calling it the
  81. first time?  You can use the result of a GetDateTime() call as the
  82. initial seed.
  83.  
  84. Why do you think it isn't uniform?  Are you doing anything strange
  85. with the results of Random(), like using a "mod" to get a smaller
  86. random number?  This decreases the quality of your random numbers,
  87. although not as much with Random() as with some other RNG's.
  88.  
  89. David Fry                                  fry@math.harvard.edu
  90. Division of Applied Sciences               fry@huma1.bitnet
  91. Harvard University                      ...!harvard!huma1!fry
  92. Cambridge, MA  02138            
  93.  
  94. +++++++++++++++++++++++++++
  95.  
  96. From: jvp@vlsi1.dell.com (Jim Van Peursem)
  97. Date: 19 Sep 92 15:56:43 GMT
  98. Organization: Iowa State University, Ames IA
  99.  
  100. In <1992Sep19.012039.15704@husc3.harvard.edu> fry@tara.harvard.edu (David Fry) writes:
  101.  
  102. >>I need a fast (speed is very important) random number generator. Right now
  103. >>I am using Random(), but it seems to me the distribution is not uniform
  104. >>at all. Is there a better generator? Will it be faster to use my own
  105. >>function than to use toolbox routine?
  106. >>Thanks for the help.
  107.  
  108. >This probably should be in the FAQ list because it comes up all the
  109. >time (and it seems I'm always the one to answer it).  Random() is a
  110. >quite good random number generator, and it is pretty fast. It will
  111. >almost certainly be faster than one you write yourself, provided the
  112. >one you write yourself is as good. 
  113.  
  114.   What kind of RNG is Random()?  Isn't it a linear congruential?
  115. If it is, better quality RNG's exist such as Lagged Fibbonacci.
  116.  
  117. +---------------------------------------------------------------+
  118. | Jim Van Peursem - Ph.D. Student - Ham Radio -> KE0PH          |
  119. | System Administrator - Digital Systems Design Lab             |
  120. | Department of Electrical Engineering and Computer Engineering |
  121. | Iowa State University - Ames, IA 50011                        |
  122. | internet - jvp@cpre1.ee.iastate.edu                           |
  123. +---------------------------------------------------------------+
  124.  
  125. +++++++++++++++++++++++++++
  126.  
  127. From: sw@network-analysis-ltd.co.uk (Sak Wathanasin)
  128. Date: 19 Sep 92 08:45:28 GMT
  129. Organization: Network Analysis Ltd
  130.  
  131.  
  132. In article <1992Sep18.105410.24438@midway.uchicago.edu> (comp.sys.mac.programmer), hd12@ellis.uchicago.edu (hui  dong) writes:
  133.  
  134. > (I did check FAQ before I post this.)
  135.  
  136. Well, it ought to be in the FAQ, since this comes up every few months.
  137. It is covered in the Usenet Mac Programmer's Guide.
  138.  
  139. > I need a fast (speed is very important) random number generator. Right now
  140. > I am using Random(), but it seems to me the distribution is not uniform
  141. > at all. Is there a better generator? Will it be faster to use my own
  142. > function than to use toolbox routine?
  143.  
  144. Ignore the 16-bit result returned by Random(), and use the full 32-bit
  145. value that is in randSeed. Details are in the UMPG. The Random() in rom
  146. is the same as the Park & Miller "minimal standard RNG" described in a
  147. CACM paper, and guards against overflows during intermediate calculations.
  148. You will be hard pushed to write a faster version in C or Pascal, and will
  149. have to use assembler to beat it.
  150.  
  151.  
  152. Sak Wathanasin
  153. Network Analysis Limited
  154. 178 Wainbody Ave South, Coventry CV3 6BX, UK
  155.  
  156. uucp:      ...!uknet!nan!sw  Phone: (+44) 203 419996
  157. AppleLink: NAN.LTD           Internet: sw@network-analysis-ltd.co.uk
  158.  
  159. +++++++++++++++++++++++++++
  160.  
  161. From: fry@tara.harvard.edu (David Fry)
  162. Date: 19 Sep 92 13:42:12 EDT
  163. Organization: Harvard Math Department
  164.  
  165. In article <jvp.716918203@vlsi1> jvp@vlsi1.dell.com (Jim Van Peursem) writes:
  166. >  What kind of RNG is Random()?  Isn't it a linear congruential?
  167. >If it is, better quality RNG's exist such as Lagged Fibbonacci.
  168.  
  169. Yes, it's linear congruential.  Certainly better RNG's exist, but for
  170. more post purposes, Random() is more than good enough. It follows the
  171. so-called "minimal standard" RNG proposed in "Random Number
  172. Generators: Good Ones are Hard to Find" by Park and Miller, in
  173. Communications of the ACM, October 1988.  This article details the
  174. history of faulty RNGs and explains why this is a fast and good one.
  175.  
  176. As someone else pointed out, to really get the best quality from
  177. Random(), you should ignore there result of the function (which is
  178. 16-bits), and use the value in randSeed (which is 32-bits) after
  179. calling Random().  In that case you have exactly the RGN described in
  180. the CACM paper.  I think even using the 16-bit number is good
  181. enough for most purposes because the lower 16-bits of the RNG are
  182. sufficiently random.  Still, I admit to using the full 32-bits in my
  183. work :-).
  184.  
  185. David Fry                                  fry@math.harvard.edu
  186. Division of Applied Sciences               fry@huma1.bitnet
  187. Harvard University                      ...!harvard!huma1!fry
  188. Cambridge, MA  02138            
  189.  
  190. +++++++++++++++++++++++++++
  191.  
  192. From: Bruce.Hoult@bbs.actrix.gen.nz
  193. Organization: Actrix Information Exchange
  194. Date: Sun, 20 Sep 1992 04:06:49 GMT
  195.  
  196. In article <1992Sep18.105410.24438@midway.uchicago.edu> hd12@midway.uchicago.edu writes:
  197. > (I did check FAQ before I post this.)
  198. > I need a fast (speed is very important) random number generator. Right now
  199. > I am using Random(), but it seems to me the distribution is not uniform
  200. > at all. Is there a better generator? Will it be faster to use my own
  201. > function than to use toolbox routine?
  202. > Thanks for the help.
  203.  
  204. The toolbox Random() functions is perfectly OK if you use the *seed*
  205. as your random value and ignore the function result.  OTOH, it's not
  206. exactly fast because of the Trap call overhead.
  207.  
  208. I've included my own random number generator, which requires a 68020
  209. or better.
  210.  
  211. I've also included my attempt at a random generator that produces
  212. "normally" distributed numbers.  It's based on the Central Limits
  213. Theorem that says the sum of several independant random variables is
  214. approximately normally distributed, no matter what distribution the
  215. individual variables have.  I found that for my purposes the sum of
  216. ten uniformally distributed variables was good enough.
  217.  
  218. The only mildly clever thing about it is that I do a little parallel
  219. computing by working out the random numbers in the CPU and then adding
  220. them (to get a greater then 32 bit result) in the coprocessor.
  221.  
  222. Comment is invited on whether this is a good way to generate a normal
  223. distribution, or not.
  224.  
  225. - -- Bruce
  226.  
  227. - ---------------
  228.  
  229. procedure MyRandom(var seed:longint);
  230. inline
  231.    $225F,                        {movea.l (a7)+,a1}
  232.    $2011,                        {move.l (a1),d0}
  233.    $4C3C, $0401, $0000, $41A7,   {mulu.l #41a7,d1:d0}
  234.    $4C7C, $0401, $7FFF, $FFFF,   {divu.l #7fffffff,d1:d0}
  235.    $2281;                        {move.l d1,(a1)}
  236.  
  237. procedure MyNormal(
  238.    numToAdd:integer;
  239.    var seed:longint;
  240.    var result:extended
  241. ); external;
  242.  
  243. - ------------------------------------------------------
  244.  
  245.             machine mc68020
  246.             mc68881
  247.             
  248. MyNormal    proc export
  249.             link a6,#0
  250.             fmove.w #0,fp0
  251.             move.l 8(a6),a1  ;pointer to result
  252.             move.l 12(a6),a0 ;pointer to seed
  253.             move.l (a0),d0
  254.             move.w 16(a6),d2 ;number of loops
  255.             bra.b loopend
  256. loop        mulu.l #16807,d1:d0 ;7^5
  257.             divu.l #$7fffffff,d1:d0
  258.             fadd.l d1,fp0
  259.             move.l d1,d0
  260. loopend     dbra d2,loop
  261.             move.l d0,(a0)   ;update the seed
  262.             fmove.x fp0,(a1) ;return the result
  263.             unlk a6
  264.             move.l (a7)+,a0
  265.             add.l #10,a7
  266.             jmp (a0)
  267.             endproc
  268.             end
  269. - -- 
  270. Bruce.Hoult@bbs.actrix.gen.nz   Twisted pair: +64 4 477 2116
  271. BIX: brucehoult                 Last Resort:  PO Box 4145 Wellington, NZ
  272. "Cray's producing a 500 MIPS personal computer with 256MB RAM and 8 GB
  273. hard disk that fits in your pocket!"   "Great!  Is it PC compatible?"
  274.  
  275. +++++++++++++++++++++++++++
  276.  
  277. From: ksand@apple.com (Kent Sandvik)
  278. Date: 20 Sep 92 19:06:23 GMT
  279. Organization: Apple
  280.  
  281. In article <1992Sep19.012039.15704@husc3.harvard.edu>, fry@tara.harvard.edu
  282. (David Fry) wrote:
  283. > In article <1992Sep18.105410.24438@midway.uchicago.edu> hd12@midway.uchicago.edu writes:
  284.  
  285. > >I need a fast (speed is very important) random number generator. Right now
  286. > >I am using Random(), but it seems to me the distribution is not uniform
  287. > >at all. Is there a better generator? Will it be faster to use my own
  288. > >function than to use toolbox routine?
  289. > >Thanks for the help.
  290.  
  291. > This probably should be in the FAQ list because it comes up all the
  292. > time (and it seems I'm always the one to answer it).  Random() is a
  293. > quite good random number generator, and it is pretty fast. It will
  294. > almost certainly be faster than one you write yourself, provided the
  295. > one you write yourself is as good. 
  296.  
  297. True, at least the Usenet Mac Programmer Guide has a lot of information
  298. about alternate random generator algorithms and code. I've done some
  299. tests myself, and it wasn't really justified to write alternate random
  300. generators, for instance I didn't see much performance improvements
  301. by inlining hex code instead of calling a trap. Check the TRandom C++
  302. class on the developer CD for my silly tests.
  303.  
  304. Cheers,
  305. Kent/DTS
  306. "You should really just relax" -MST3K
  307. - -------------------
  308. Kent Sandvik (UUCP: ....!apple!ksand; INTERNET: ksand@apple.com)
  309. DISCLAIMER: Private activities on the Net.
  310.  
  311. +++++++++++++++++++++++++++
  312.  
  313. From: Bruce.Hoult@bbs.actrix.gen.nz
  314. Date: 21 Sep 92 01:34:32 GMT
  315. Organization: Actrix Information Exchange
  316.  
  317. In article <ksand-200992120624@wintermute.apple.com> ksand@apple.com (Kent Sandvik) writes:
  318.  
  319. > I've done some
  320. > tests myself, and it wasn't really justified to write alternate random
  321. > generators, for instance I didn't see much performance improvements
  322. > by inlining hex code instead of calling a trap. Check the TRandom C++
  323. > class on the developer CD for my silly tests.
  324.  
  325. What machine were you testing on?
  326.  
  327. Whn I wrote the code I posted last night I was on a IIcx and there was
  328. a *massive* difference in trap overhead vs procedure call overhead.
  329. The difference seems to have gotten much smaller on the '040 -- in a
  330. test a while ago on the Q700 I found that a function call and return
  331. with three longword parameters and a trivial body (like SetPt) took just
  332. over 1 uS while a similar trap call took 3 uS.  (I hope i've
  333. remembered those right :-)
  334.  
  335. - -- 
  336. Bruce.Hoult@bbs.actrix.gen.nz   Twisted pair: +64 4 477 2116
  337. BIX: brucehoult                 Last Resort:  PO Box 4145 Wellington, NZ
  338. "Cray's producing a 500 MIPS personal computer with 256MB RAM and 8 GB
  339. hard disk that fits in your pocket!"   "Great!  Is it PC compatible?"
  340.  
  341. +++++++++++++++++++++++++++
  342.  
  343. From: ksand@apple.com (Kent Sandvik)
  344. Date: 22 Sep 92 02:02:51 GMT
  345. Organization: Apple
  346.  
  347. In article <1992Sep21.013432.18668@actrix.gen.nz>,
  348. Bruce.Hoult@bbs.actrix.gen.nz wrote:
  349. > Whn I wrote the code I posted last night I was on a IIcx and there was
  350. > a *massive* difference in trap overhead vs procedure call overhead.
  351. > The difference seems to have gotten much smaller on the '040 -- in a
  352. > test a while ago on the Q700 I found that a function call and return
  353. > with three longword parameters and a trivial body (like SetPt) took just
  354. > over 1 uS while a similar trap call took 3 uS.  (I hope i've
  355. > remembered those right :-)
  356.  
  357. When I think about it my tests were on a Quadra 900. I will do
  358. some more additional tests on other machines later.
  359.  
  360. Kent
  361. "You should really just relax" -MST3K
  362. - -------------------
  363. Kent Sandvik (UUCP: ....!apple!ksand; INTERNET: ksand@apple.com)
  364. DISCLAIMER: Private activities on the Net.
  365.  
  366. ---------------------------
  367.  
  368. From: mgleason@cse.unl.edu (Mike Gleason)
  369. Subject: BlockZero.c snippet
  370. Date: 15 Sep 92 18:50:19 GMT
  371. Organization: NCEMRSoft
  372.  
  373. I think J. McCarthy & M. Mora started a good idea by posting code snippets here,
  374. so here's a freebie function that clears an area of memory (which can start
  375. on an odd boundary).  It's much faster than using memset(ptr,0,n) because
  376. this function uses move.l's for the majority of the block.  It compiles
  377. under Think C, but the asm {} blocks may break other compilers.
  378.  
  379. I use this function all the time, especially when dealing with parameter
  380. blocks. e.g.:
  381.  
  382. #define ZERO(a) BlockZero(&(a), sizeof (a))
  383.  
  384. {
  385.     HParamBlockRec  pb;
  386.  
  387.     ZERO(pb);
  388. }
  389.  
  390.  
  391. Code follows.  Further optimizations, your cool code snippets, bug fixes
  392. <gulp> welcome....
  393.  
  394. - ----------------
  395.  
  396. void BlockZero(void *area, register unsigned long n);
  397.  
  398. void BlockZero(void *area, register unsigned long n)
  399. {
  400.     register char               *p = (char *)area;
  401.     register unsigned long      fours;
  402.     register unsigned long      remainder, zero;
  403.  
  404.     if (n) {
  405.         if ((long) p & 01) {
  406.             /* Ptr on an odd boundary... */
  407.             asm {
  408.                 clr.b       (p)+
  409.             }
  410.             --n;
  411.             /*
  412.              * Ptr is now on an even boundary,
  413.              * and it's first byte is zeroed.
  414.              */
  415.         }
  416.         
  417.         fours = n / 4L;     /* Can be zero. */
  418.         
  419.         /* Do the meat of the block using longwords for speed. */
  420.  
  421.         asm {
  422.                 clr.l       zero
  423.                 bra         @2
  424.         @1:     move.l      zero, (p)+
  425.         @2:     subq.l      #1, fours
  426.                 tst.l       fours
  427.                 bge         @1
  428.         }
  429.  
  430.         /*
  431.          * If the size of the block isn't divisible by 4, we'll
  432.          * have to do the remaining bytes (up to 3) by hand.
  433.          */
  434.  
  435.         remainder = n & 03;     /* same as remainder = n % 4. */
  436.             
  437.         asm {
  438.             bra             @4
  439.         @3: clr.b           (p)+
  440.         @4: dbra            remainder, @3
  441.         }
  442.     }
  443. }   /* BlockZero */
  444.  
  445. /* eof BlockZero.c */
  446. - --
  447. - --mg                                                      mgleason@cse.unl.edu
  448.  
  449. +++++++++++++++++++++++++++
  450.  
  451. From: keith@taligent.com (Keith Rollin)
  452. Date: 16 Sep 92 17:55:14 GMT
  453. Organization: Taligent
  454.  
  455. In article <1992Sep15.185019.22483@unlinfo.unl.edu>, mgleason@cse.unl.edu
  456. (Mike Gleason) wrote:
  457. > I think J. McCarthy & M. Mora started a good idea by posting code snippets here,
  458. > so here's a freebie function that clears an area of memory (which can start
  459. > on an odd boundary).  It's much faster than using memset(ptr,0,n) because
  460. > this function uses move.l's for the majority of the block.  It compiles
  461. > under Think C, but the asm {} blocks may break other compilers.
  462. >
  463. > [ code deleted ]
  464. >
  465.  
  466. True, not only will this not work under MPW (which doesn't have inline
  467. asm), but MPW's memset library routine is better than the one you post.
  468. Specifically, for large enough blocks, it uses a series of 4 MOVE.L
  469. instructions in a row for setting the block. On the other hand, I don't
  470. know what the timing differences between MOVE.L and CLR.L are, so perhaps a
  471. specialized bzero() based on MPW's algorithm would be nice.
  472.  
  473. - -----
  474. Keith Rollin
  475. Phantom Programmer
  476. Taligent, Inc.
  477.  
  478. +++++++++++++++++++++++++++
  479.  
  480. From: nagel@Cigna.COM (Mark Nagel)
  481. Date: 16 Sep 92 23:09:16 GMT
  482. Organization: CIGNA FIRST, Irvine, CA
  483.  
  484. In <keith-160992104732@kip-58.taligent.com> keith@taligent.com (Keith Rollin) writes:
  485.  
  486. >instructions in a row for setting the block. On the other hand, I don't
  487. >know what the timing differences between MOVE.L and CLR.L are, so perhaps a
  488. >specialized bzero() based on MPW's algorithm would be nice.
  489.  
  490. I'm curious about this.  I picked up a Motorola 68K family processor
  491. manual, but it doesn't have instruction timing info.  I have noticed
  492. that THINK C uses MOVEQ.L #0, D0, for example, rather than CLR.L
  493. D0.  I gather from this that MOVEQ.L is faster, but I'd still like
  494. to see timings.  Anyone know a good assembler book for the 68K that
  495. has info like that?  Something along the lines of "Zen and the Art
  496. of Assembly Language Programming" would be wonderful.
  497.  
  498. Mark
  499. - -- 
  500. Mark Nagel <nagel@cigna.com>    | DISCLAIMER: Any resemblence of these
  501. Network Administrator        | opinions to those of CIGNA are purely
  502. CIGNA/FIRST            | coincidental.
  503.           (Don't start vast projects with half-vast ideas)
  504.  
  505. +++++++++++++++++++++++++++
  506.  
  507. From: gurgle@netcom.com (Pete Gontier)
  508. Date: 17 Sep 92 02:47:01 GMT
  509. Organization: cellular
  510.  
  511. nagel@Cigna.COM (Mark Nagel) writes:
  512.  
  513. >I'm curious about this.  I picked up a Motorola 68K family processor
  514. >manual, but it doesn't have instruction timing info.  I have noticed
  515. >that THINK C uses MOVEQ.L #0, D0, for example, rather than CLR.L
  516. >D0.  I gather from this that MOVEQ.L is faster, but I'd still like
  517. >to see timings.
  518.  
  519. Notice, though, that MOVEQ has very limited destination operand types.
  520. If I remember correctly, registers only. So that renders its use in
  521. the context of bzero( ) pretty dubious. Me, I just call NewHandleClear
  522. in the first place and assume Apple's Cray can write better 68000
  523. than me. :-)
  524. - -- 
  525.  Pete Gontier // EC Technology // gurgle@netcom.com
  526.  
  527. +++++++++++++++++++++++++++
  528.  
  529. From: Bruce.Hoult@bbs.actrix.gen.nz
  530. Date: 17 Sep 92 05:42:50 GMT
  531. Organization: Actrix Information Exchange
  532.  
  533. In article <1992Sep15.185019.22483@unlinfo.unl.edu> mgleason@cse.unl.edu (Mike Gleason) writes:
  534. > I think J. McCarthy & M. Mora started a good idea by posting code snippets here,
  535. > so here's a freebie function that clears an area of memory (which can start
  536. > on an odd boundary).  It's much faster than using memset(ptr,0,n) because
  537. > this function uses move.l's for the majority of the block.  It compiles
  538. > under Think C, but the asm {} blocks may break other compilers.
  539.  
  540. You should add in a possible 2 byte move at the start and end to align
  541. the pointer on a longword boundary.  This will increase speed on the
  542. 32-bit bus machines.
  543.  
  544. You should unroll the main loop to do several move.l's each time around.
  545.  
  546. You should use dbra for the loop control (only two bytes longer than your
  547. version and much faster)...
  548.  
  549.     bra @3
  550. @1  swap fours
  551. @2  move.l zero,(p)+  # or several of them..
  552. @3  dbra fours, @2
  553.     swap fours
  554.     dbra fours, @1
  555.  
  556. - -- 
  557. Bruce.Hoult@bbs.actrix.gen.nz   Twisted pair: +64 4 477 2116
  558. BIX: brucehoult                 Last Resort:  PO Box 4145 Wellington, NZ
  559. "Cray's producing a 500 MIPS personal computer with 256MB RAM and 8 GB
  560. hard disk that fits in your pocket!"   "Great!  Is it PC compatible?"
  561.  
  562. +++++++++++++++++++++++++++
  563.  
  564. From: Bruce.Hoult@bbs.actrix.gen.nz
  565. Date: 17 Sep 92 10:08:16 GMT
  566. Organization: Actrix Information Exchange
  567.  
  568. In article <1992Sep16.230916.18166@Cigna.COM> nagel@Cigna.COM (Mark Nagel) writes:
  569.  
  570. > I'm curious about this.  I picked up a Motorola 68K family processor
  571. > manual, but it doesn't have instruction timing info.  I have noticed
  572. > that THINK C uses MOVEQ.L #0, D0, for example, rather than CLR.L
  573. > D0.  I gather from this that MOVEQ.L is faster, but I'd still like
  574. > to see timings.  Anyone know a good assembler book for the 68K that
  575. > has info like that?  Something along the lines of "Zen and the Art
  576. > of Assembly Language Programming" would be wonderful.
  577.  
  578. My official Motorola  68000 (M68000UM/AD REV 4 1986) and 68020
  579. (MC68020UM/AD REV 1 1985) books both have tables of timing
  580. information, but the 68020 one is full of disclaimers about how
  581. complex figuring timings is on modern architectures, and in fact I
  582. think motorola quit publishing instruction timing tables.  You've
  583. really got to try *your* instruction sequence to find out, unless
  584. you've got really intimate knowledge of the undocumented internals of
  585. the pipeline etc.
  586. - -- 
  587. Bruce.Hoult@bbs.actrix.gen.nz   Twisted pair: +64 4 477 2116
  588. BIX: brucehoult                 Last Resort:  PO Box 4145 Wellington, NZ
  589. "Cray's producing a 500 MIPS personal computer with 256MB RAM and 8 GB
  590. hard disk that fits in your pocket!"   "Great!  Is it PC compatible?"
  591.  
  592. +++++++++++++++++++++++++++
  593.  
  594. From: mgleason@cse.unl.edu (Mike Gleason)
  595. Date: 17 Sep 92 18:29:11 GMT
  596. Organization: NCEMRSoft
  597.  
  598. Bruce.Hoult@bbs.actrix.gen.nz writes:
  599.  
  600. >You should unroll the main loop to do several move.l's each time around.
  601.  
  602. >You should use dbra for the loop control (only two bytes longer than your
  603. >version and much faster)...
  604.  
  605. I tried this for the main block, but if I recall, dbra's loop counter
  606. was acting like a 16-bit word instead of a nice big longword.
  607.  
  608. Some other folks have sent me some tips, so I will tweak it more using
  609. these tricks that aren't covered in my VAX Assembler book.  I have attempted
  610. to get my hands on a 68000 assembly book for the mac, but so far all the
  611. books mentioned in the FAQ (and the one E. Wylie suggested recently) are
  612. either out of print or my book store can't order them :-(
  613.  
  614. - --
  615. - --mg                                                      mgleason@cse.unl.edu
  616.  
  617. +++++++++++++++++++++++++++
  618.  
  619. From: mgleason@cse.unl.edu (Mike Gleason)
  620. Date: 18 Sep 92 05:27:49 GMT
  621. Organization: NCEMRSoft
  622.  
  623. Here's a much improved BlockZero function.  This one now long word aligns,
  624. and instead of using one small move.l loop to clear 4 bytes at a time, this
  625. version clears 144 bytes per loop iteration, then 16 bytes at a time when
  626. the block has less than 144 dirty bytes left, then 1 byte at a time for any
  627. remaining bytes.  In other words, it performs OK on small blocks, pretty
  628. good on medium size blocks, and excellent on large blocks.  Of course there
  629. aren't many times where one would need to zero a big block, since most big
  630. blocks are pointers that can be cleared the same time they are allocated,
  631. but it still makes a good general-purpose bzero.
  632.  
  633. Thanks to everyone who responded, especially John Bruner and Michael Hecht.
  634. I'm sure there are more optimizations that could be done, but I'll let the
  635. Gods of the 68000 worry about that :-)
  636.  
  637. Here it is, it requires Think C to compile.
  638.  
  639. /* BlockZero.c */
  640.  
  641. /* Handy macro: */
  642. #define ZERO(block,size) BlockZero(&(block), (long) (size))
  643.  
  644. void BlockZero(void *area, long n);
  645.  
  646. #define PTR             a0              /* Our copy of 'area.' */
  647. #define COUNT           d0              /* Our copy of 'n.' */
  648.  
  649. /*
  650.  *  Using registers d1 - d7, and a1 - a5 to hold zeroes for use
  651.  *  with MOVEM.  Could use a6 also if you can trick the inline
  652.  *  assembler to not use LINK/UNLK.
  653.  */
  654. #define nAddrRegsUsed   5
  655. #define nDataRegsUsed   7
  656.  
  657. /*
  658.  *  One MOVEM instruction will clear this many bytes at a time.
  659.  */
  660. #define ZSize           ((nAddrRegsUsed + nDataRegsUsed) * sizeof (long))
  661.  
  662. /*
  663.  *  This is how many MOVEM instructions you want in your loop.  For each
  664.  *  extra one you add, then large blocks will clear faster; however
  665.  *  smaller blocks will be slower because it will use the intermediate
  666.  *  loop, where only 16 bytes are cleared at a time.
  667.  */
  668. #define UnrolledLoops   3
  669.  
  670. /*
  671.  *  For each UnrolledLoop, do one of these.
  672.  */
  673. #define Loop            movem.l d1-d7/a1-a5, -(PTR)
  674.  
  675. /*
  676.  *  This is how many bytes are cleared by all of your MOVEMs before
  677.  *  we have to decrement the count and start another loop iteration.
  678.  */
  679. #define TotalSize       (ZSize * UnrolledLoops)
  680.  
  681. void BlockZero(void *area, long n)
  682. {
  683.     asm {
  684.         movem.l         d0-d7/a0-a5, -(sp)
  685.  
  686.         move.l          n, COUNT        ; Could use index from the SP
  687.         movea.l         area, PTR       ; for these instead of a6.
  688.  
  689.         add.l           COUNT, PTR      ; Start at end of block,
  690.                                         ; and go backwards.
  691.  
  692.         move.w          PTR, d1         ; Find (area + n) % 4.
  693.         andi.w          #3, d1          
  694.  
  695.         sub.l           d1, COUNT       ; We will byte-zero this
  696.                                         ; many bytes to longword align,
  697.                                         ; so subtract this from the
  698.                                         ; total.
  699.         
  700.         moveq.l         #0, d2
  701.         
  702.         bra             @2              ; Zero the last 3 or so
  703.     @1: move.b          d2, -(PTR)      ; bytes to align PTR on a
  704.     @2: dbra            d1, @1          ; longword boundary.
  705.  
  706.                                         ; Clear out as many registers
  707.                                         ; as possible to use with MOVEM.
  708.  
  709.         move.l          d2, d1          ; Don't need d1 for scratch.
  710.         move.l          d2, d3
  711.         move.l          d2, d4
  712.         
  713.         cmpi.l          #TotalSize, COUNT
  714.         bls             @6              ; If it is a smaller block, then
  715.                                         ; jump to the section that clears
  716.                                         ; 16 at a time.
  717.  
  718.                                         ; Otherwise we'll need to clear
  719.                                         ; out the rest of these registers
  720.                                         ; to use in a huge MOVEM.
  721.         move.l          d2, d5
  722.         move.l          d2, d6
  723.         move.l          d2, d7
  724.         movea.l         d2, a1
  725.         movea.l         a1, a2
  726.         movea.l         a1, a3
  727.         movea.l         a1, a4
  728.         movea.l         a1, a5
  729.  
  730.                                         ; Now zero as much as we can
  731.                                         ; in blocks of 144 (3 movem's
  732.                                         ; of 48 bytes each).
  733.  
  734.         bra             @4
  735.     @3: Loop                            ; Add more Loops here if you
  736.         Loop                            ; like, but adjust the #defines
  737.         Loop                            ; above.
  738.     @4: subi.l          #TotalSize, COUNT
  739.         bge             @3
  740.  
  741.                                         ; The remaining block is now
  742.                                         ; less than TotalSize, so now
  743.                                         ; zero as much as we can
  744.                                         ; in blocks of 16.
  745.  
  746.         addi.l          #TotalSize, COUNT
  747.  
  748.         bra             @6
  749.     @5: movem.l         d1-d4, -(PTR)
  750.     @6: subi.l          #16, COUNT
  751.         bge             @5
  752.                                         ; The remaining block is now
  753.                                         ; less than 16, so now
  754.                                         ; use byte-zeroing.
  755.  
  756.         addi.l          #16, COUNT
  757.         bra             @8
  758.     @7: move.b          d2, -(PTR)
  759.     @8: dbra            COUNT, @7
  760.                                         ; Restore nuked registers.
  761.         movem.l         (sp)+,d0-d7/a0-a5
  762.     }
  763. }   /* BlockZero */
  764.  
  765. /* eof BlockZero.c */
  766. - --
  767. ______________________________________________________________________________
  768. mike gleason                 mgleason@cse.unl.edu             NCEMRSoft, baby!
  769.  
  770. +++++++++++++++++++++++++++
  771.  
  772. From: d88-jwa@musta.nada.kth.se (Jon Wtte)
  773. Date: 18 Sep 92 09:59:59 GMT
  774. Organization: Royal Institute of Technology, Stockholm, Sweden
  775.  
  776. > mgleason@cse.unl.edu (Mike Gleason) writes:
  777.  
  778.    I tried this for the main block, but if I recall, dbra's loop counter
  779.    was acting like a 16-bit word instead of a nice big longword.
  780.  
  781. Well, using the SWAP function you can use DBRA as a 32-bit counter.
  782. Still beats the MS-DOS programming model :-)
  783.  
  784. - -- 
  785. Jon W{tte, h+@nada.kth.se, Sweden, Phone +46-8-107069
  786.  
  787. Help eradicate FIDO-Net <-> Usenet gateways in our time!
  788.  
  789. +++++++++++++++++++++++++++
  790.  
  791. From: Bruce.Hoult@bbs.actrix.gen.nz
  792. Date: 18 Sep 92 07:55:21 GMT
  793. Organization: Actrix Information Exchange
  794.  
  795. In article <1992Sep17.182911.27693@unlinfo.unl.edu> mgleason@cse.unl.edu (Mike Gleason) writes:
  796. > Bruce.Hoult@bbs.actrix.gen.nz writes:
  797. > >You should use dbra for the loop control (only two bytes longer than your
  798. > >version and much faster)...
  799. > I tried this for the main block, but if I recall, dbra's loop counter
  800. > was acting like a 16-bit word instead of a nice big longword.
  801.  
  802. Correct -- that's why the code I showed used *two* DBRA's in nested
  803. loops, with the tricky little SWAPs to get the high word of the count
  804. register into the low word for the outer DBRA and back again.  It's a
  805. little bit ugly but correctly handles a 32-bit count, is only 2 bytes
  806. bigger than what you were doing, and the extra SWAPs only get executed
  807. once every 65536 loops so their overhead is almost zero.  All of which
  808. make this method (thanks to Lawrence for originally pointing the
  809. method out!) overall tidier than the obvious nested DBRA method of
  810. putting 16-bit counts in two different registers -- which has a little
  811. less overhead every 65536 loops, but uses at minimum an extra MOVE.L
  812. and SWAP in the loop prologue and uses an extra precious register,
  813. for the same size code.
  814.  
  815. Isn't it amazing how much fun saving a couple of bytes or cycles can
  816. be?  ;-)
  817. - -- 
  818. Bruce.Hoult@bbs.actrix.gen.nz   Twisted pair: +64 4 477 2116
  819. BIX: brucehoult                 Last Resort:  PO Box 4145 Wellington, NZ
  820. "Cray's producing a 500 MIPS personal computer with 256MB RAM and 8 GB
  821. hard disk that fits in your pocket!"   "Great!  Is it PC compatible?"
  822.  
  823. +++++++++++++++++++++++++++
  824.  
  825. From: wombat@claris.com (Scott Lindsey)
  826. Date: 18 Sep 92 09:18:30 GMT
  827. Organization: Claris Corporation, Vancouver WA
  828.  
  829. In article <keith-160992104732@kip-58.taligent.com>, keith@taligent.com (Keith Rollin) writes:
  830. > On the other hand, I don't
  831. > know what the timing differences between MOVE.L and CLR.L are, so perhaps a
  832.  
  833. Well, according to the 5th edition of the M68000 Programmer's Reference Manual
  834. from Motorola,
  835.  
  836.     MOVE.L #<data>,(An)+    20(3/2)
  837.     CLR.L (An)+             24(2/4)  + 16(4/0)
  838.  
  839. where the first number is clock periods, and the 2 parenthesized are bus read &
  840. write cycles.  the 16(4/0) is the time required for the (An)+ effective address
  841. calculation.  So on a 68000, the MOVE beats the CLR.
  842.  
  843. The manual also includes timings for the 68010.  The MOVE timing is same,
  844. but the CLR timing is 12(1/2) for (An)+ with no additional time for address
  845. calculation.  So CLR is the winner.  I don't have timings for 020, 030, 040's,
  846. but one would expect them to be more like the 010 than the 000.  Note that the
  847. 010 also has a "loop mode" where opcode fetches are suppressed, speeding up
  848. the loop even more.
  849.  
  850. So I would guess that if you're optimizing for the 68000 (which needs it the
  851. most) then use MOVE, but use CLR if you're optimizing for > 68000.
  852.  
  853.  
  854. - --
  855. Scott Lindsey <wombat@claris.com>
  856. QUIT
  857.  
  858. Scott Lindsey <wombat@claris.com>
  859.  
  860. +++++++++++++++++++++++++++
  861.  
  862. From: peterc@cubetech.com (Peter Creath)
  863. Date: Thu, 17 Sep 92 22:25:37 CDT
  864. Organization: Cube Technologies
  865.  
  866. Here's my optimization on Mike Gleason's BlockZero.c snippet:
  867.  
  868. (I'm gonna remove the comments within the code and explain it here...)
  869.  
  870. This is shorter, primarily because the code itself (not the declarations)
  871. is entirely in assembly.  Therefore, it can be used by any Pascal
  872. or C compiler with an inline assembler.
  873.  
  874. This is also slightly faster and smaller, since I killed possible
  875. inefficiencies in the compiled code.  The original routine was designed
  876. for speed, not for size, so I added an option that compiles a MUCH
  877. smaller (but slower) version:
  878.  
  879. #define FAST    /* leave undefined for the SMALL version */
  880. #define ZERO(a) BlockZero(&(a), sizeof (a))
  881.  
  882. {
  883.     HParamBlockRec  pb;
  884.     ZERO(pb);
  885. }
  886.  
  887. void BlockZero(void *area, register unsigned long n);
  888.  
  889. void BlockZero(void *area, register unsigned long n)
  890. {
  891. register char               *p = (char *)area;
  892. register unsigned long      temp;
  893. register unsigned long      zero;
  894.  
  895. #ifdef FAST
  896. asm {
  897.     tst.l   n
  898.     beq.s   @skipit                /* only if len > 0 */
  899.         move.w    p,temp
  900.         andi.w    #0x01,temp        /* if odd offset, */
  901.         beq.s    @skipeven
  902.             clr.b    (p)+        /* clear odd byte and */
  903.             subq.l    #0x01,n        /* make offset even */
  904. @skipeven:
  905.         move.l    n,temp
  906.         asr.l    #0x02,temp        /* len/4 (# of longs in area) */
  907.         bra.s    @fourloop
  908. @clrloop:                        /* clear out longs speedily */
  909.             clr.l    (p)+
  910. @fourloop:
  911.             dbf        temp,@clrloop
  912. @nofours:
  913.         move.b    n,temp
  914.         andi.b    #0x03,temp        /* check remainder (len % 4) */
  915.         bra.s    @oddloop
  916. @clearodd:
  917.             clr.b    (p)+        /* clear remaining bytes */
  918. @oddloop:
  919.             dbf        temp, @clearodd
  920. @skipit:
  921.     }
  922. #else    /* if SMALL */
  923. asm {
  924.     move.l    n,temp
  925.     bra.s    @loopback
  926. @loop:
  927.     clr.b    (p)+
  928. @loopback:
  929.     dbf        temp,@loop
  930.     }
  931. #endif
  932. }   /* BlockZero */
  933.  
  934. /* eof BlockZero.c */
  935.  
  936.  
  937. - ----------------------------------------------------------------------------
  938. Peter Creath                 "When I was a boy I was told that anybody could
  939. peterc@cubetech.com           become president; I'm beginning to believe it."
  940.                                                            -- Clarence Darrow
  941.  
  942. +++++++++++++++++++++++++++
  943.  
  944. From: mgleason@cse.unl.edu (Mike Gleason)
  945. Date: 21 Sep 92 03:10:42 GMT
  946. Organization: NCEMRSoft
  947.  
  948. peterc@cubetech.com (Peter Creath) writes:
  949.  
  950. >Lines: 75
  951.  
  952. >Here's my optimization on Mike Gleason's [original] BlockZero.c snippet:
  953.  
  954. >(I'm gonna remove the comments within the code and explain it here...)
  955.  
  956. >This is shorter, primarily because the code itself (not the declarations)
  957. >is entirely in assembly.  Therefore, it can be used by any Pascal
  958. >or C compiler with an inline assembler.
  959.  
  960. >This is also slightly faster and smaller, since I killed possible
  961. >inefficiencies in the compiled code.  The original routine was designed
  962. >for speed, not for size, so I added an option that compiles a MUCH
  963. >smaller (but slower) version:
  964.  
  965. Thanks for the improvements; unfortunately they were made to the first
  966. version.  The second one I posted is over 3 times faster.  It compiles
  967. to about 146 bytes (as opposed to 84 bytes for version 1), so you may
  968. want to re-optimize it for size if the extra space is bothersome.
  969.  
  970. - --mg
  971.  
  972. p.s., here's the benchmarks of my functions.  Please don't make fun of my
  973. slow 7.x MHz CPU :-)
  974.  
  975. Function 0 is Symantec's memset;
  976.          1 is my first BlockZero;
  977.      2 is the new BlockZero.
  978.          3 is Michael Hecht's wzbzeri;
  979.  
  980. Function 0:             7 bytes in         89 ticks    59.91 KB/sec
  981. Function 1:             7 bytes in        112 ticks    47.61 KB/sec
  982. Function 2:             7 bytes in        162 ticks    32.91 KB/sec
  983. Function 3:             7 bytes in        170 ticks    31.36 KB/sec
  984.  
  985. Function 0:            99 bytes in        464 ticks   162.52 KB/sec
  986. Function 1:            99 bytes in        216 ticks   349.12 KB/sec
  987. Function 2:            99 bytes in        194 ticks   388.71 KB/sec
  988. Function 3:            99 bytes in        261 ticks   288.93 KB/sec
  989.  
  990. Function 0:           335 bytes in       1423 ticks   179.32 KB/sec
  991. Function 1:           335 bytes in        495 ticks   515.51 KB/sec
  992. Function 2:           335 bytes in        204 ticks  1250.86 KB/sec
  993. Function 3:           335 bytes in        460 ticks   554.73 KB/sec
  994.  
  995. Function 0:          2048 bytes in       8154 ticks   191.32 KB/sec
  996. Function 1:          2048 bytes in       2499 ticks   624.25 KB/sec
  997. Function 2:          2048 bytes in        910 ticks  1714.29 KB/sec
  998. Function 3:          2048 bytes in       1291 ticks  1208.37 KB/sec
  999.  
  1000. Function 0:        308294 bytes in    1243151 ticks   188.90 KB/sec
  1001. Function 1:        308294 bytes in     358464 ticks   655.11 KB/sec
  1002. Function 2:        308294 bytes in     114221 ticks  2055.96 KB/sec
  1003. Function 3:        308294 bytes in     170072 ticks  1380.79 KB/sec
  1004.  
  1005. - --
  1006. - --mg                                                      mgleason@cse.unl.edu
  1007.  
  1008. +++++++++++++++++++++++++++
  1009.  
  1010. From: keith@taligent.com (Keith Rollin)
  1011. Date: 21 Sep 92 18:17:57 GMT
  1012. Organization: Taligent
  1013.  
  1014. In article <1992Sep21.031042.22722@unlinfo.unl.edu>, mgleason@cse.unl.edu
  1015. (Mike Gleason) wrote:
  1016. > p.s., here's the benchmarks of my functions.  Please don't make fun of my
  1017. > slow 7.x MHz CPU :-)
  1018. > Function 0 is Symantec's memset;
  1019. >          1 is my first BlockZero;
  1020. >      2 is the new BlockZero.
  1021. >          3 is Michael Hecht's wzbzeri;
  1022. > Function 2:             7 bytes in        162 ticks    32.91 KB/sec
  1023. > Function 2:            99 bytes in        194 ticks   388.71 KB/sec
  1024. > Function 2:           335 bytes in        204 ticks  1250.86 KB/sec
  1025.  
  1026. I'm sorry, but I gotta make fun of Mike's slow 7.x MHz CPU.
  1027.  
  1028. NEARLY 3 SECONDS TO CLEAR 7 BYTES???
  1029.  
  1030. Also, what's the deal with it taking 162 "units" to clear 7 bytes, and only
  1031. 20% longer to clear more than 12 times that much? Or 194 units to clear 99
  1032. bytes and only 10 units more to clear over 3 times that much? The
  1033. overhead's gotta be killer.
  1034.  
  1035. And the math doesn't work... (7 bytes / 162 ticks) * (60 ticks / 1 second)
  1036. comes to .00259 KB/second. You'd have to assume Mike ran 12,693 iterations
  1037. in order to get the tickcount he did on that first test.
  1038.  
  1039. - -----
  1040. Keith Rollin
  1041. Phantom Programmer
  1042. Taligent, Inc.
  1043.  
  1044. +++++++++++++++++++++++++++
  1045.  
  1046. From: mgleason@cse.unl.edu (Mike Gleason)
  1047. Date: 21 Sep 92 22:36:09 GMT
  1048. Organization: NCEMRSoft
  1049.  
  1050. keith@taligent.com (Keith Rollin) writes:
  1051.  
  1052. >In article <1992Sep21.031042.22722@unlinfo.unl.edu>, mgleason@cse.unl.edu
  1053. >(Mike Gleason) wrote:
  1054. >> 
  1055. >> p.s., here's the benchmarks of my functions.  Please don't make fun of my
  1056. >> slow 7.x MHz CPU :-)
  1057. >> 
  1058. >> Function 0 is Symantec's memset;
  1059. >>          1 is my first BlockZero;
  1060. >>      2 is the new BlockZero.
  1061. >>          3 is Michael Hecht's wzbzeri;
  1062. >> 
  1063. >> Function 2:             7 bytes in        162 ticks    32.91 KB/sec
  1064. >> Function 2:            99 bytes in        194 ticks   388.71 KB/sec
  1065. >> Function 2:           335 bytes in        204 ticks  1250.86 KB/sec
  1066. >> 
  1067.  
  1068. >I'm sorry, but I gotta make fun of Mike's slow 7.x MHz CPU.
  1069.  
  1070. >NEARLY 3 SECONDS TO CLEAR 7 BYTES???
  1071.  
  1072. :-) I evidently forgot to mention that I was using VIA_ticks() that comes
  1073. with Symantec's ANSI library.  According to them there are "approximately
  1074. 780,000" per second.  Originally my test suite was using system Ticks, but
  1075. 60 units per second isn't enough so I decided to try using the VIA timer
  1076. that Symantec's profiler uses.
  1077.  
  1078. >Also, what's the deal with it taking 162 "units" to clear 7 bytes, and only
  1079. >20% longer to clear more than 12 times that much? Or 194 units to clear 99
  1080. >bytes and only 10 units more to clear over 3 times that much? The
  1081. >overhead's gotta be killer.
  1082.  
  1083. There is a bit of overhead.  Here's a bit of pseudo-code to illustrate it:
  1084. (Did the second version of the code get through?  You apparently haven't
  1085. seen it and I have had an email request.  I guess I will just append it 
  1086. again at the end of this message; sorry if this is wasting bandwidth.)
  1087.  
  1088.    make a copy of 'n' for the counter;
  1089.    make a copy of the pointer to the area to be zeroed;
  1090.    align our ptr on a longword boundary;
  1091.    if (n >= 144) then
  1092.       zero 144 at a time, subtract amount zeroed from n;
  1093.    if (n >= 16) then
  1094.       zero 16 a time, subtract amount zeroed from n;
  1095.    if (n >= 1) then
  1096.       zero 1 at a time.
  1097.  
  1098. If you look at the results for Symantec's memset(), which is just one byte
  1099. at a time, it doesn't do much better for small sizes, despite having little
  1100. overhead.  It just looks like mine has a lot of overhead because it does
  1101. so much better on big blocks.
  1102.  
  1103. Function 0: (memset)    7 bytes in         89 ticks    59.91 KB/sec
  1104. Function 0:            99 bytes in        464 ticks   162.52 KB/sec
  1105. Function 0:           335 bytes in       1423 ticks   179.32 KB/sec
  1106.  
  1107. - --mg
  1108.  
  1109. (Version 2 of BlockZero follows...)
  1110.  
  1111. /* BlockZero.c */
  1112.  
  1113. /* Handy macro: */
  1114. #define ZERO(block,size) BlockZero(&(block), (long) (size))
  1115.  
  1116. void BlockZero(void *area, long n);
  1117.  
  1118. #define PTR             a0              /* Our copy of 'area.' */
  1119. #define COUNT           d0              /* Our copy of 'n.' */
  1120.  
  1121. /*
  1122.  *  Using registers d1 - d7, and a1 - a5 to hold zeroes for use
  1123.  *  with MOVEM.  Could use a6 also if you can trick the inline
  1124.  *  assembler to not use LINK/UNLK.
  1125.  */
  1126. #define nAddrRegsUsed   5
  1127. #define nDataRegsUsed   7
  1128.  
  1129. /*
  1130.  *  One MOVEM instruction will clear this many bytes at a time.
  1131.  */
  1132. #define ZSize           ((nAddrRegsUsed + nDataRegsUsed) * sizeof (long))
  1133.  
  1134. /*
  1135.  *  This is how many MOVEM instructions you want in your loop.  For each
  1136.  *  extra one you add, then large blocks will clear faster; however
  1137.  *  smaller blocks will be slower because it will use the intermediate
  1138.  *  loop, where only 16 bytes are cleared at a time.
  1139.  */
  1140. #define UnrolledLoops   3
  1141.  
  1142. /*
  1143.  *  For each UnrolledLoop, do one of these.
  1144.  */
  1145. #define Loop            movem.l d1-d7/a1-a5, -(PTR)
  1146.  
  1147. /*
  1148.  *  This is how many bytes are cleared by all of your MOVEMs before
  1149.  *  we have to decrement the count and start another loop iteration.
  1150.  */
  1151. #define TotalSize       (ZSize * UnrolledLoops)
  1152.  
  1153. void BlockZero(void *area, long n)
  1154. {
  1155.     asm {
  1156.         movem.l         d0-d7/a0-a5, -(sp)
  1157.  
  1158.         move.l          n, COUNT        ; Could use index from the SP
  1159.         movea.l         area, PTR       ; for these instead of a6.
  1160.  
  1161.         add.l           COUNT, PTR      ; Start at end of block,
  1162.                                         ; and go backwards.
  1163.  
  1164.         move.w          PTR, d1         ; Find (area + n) % 4.
  1165.         andi.w          #3, d1          
  1166.  
  1167.         sub.l           d1, COUNT       ; We will byte-zero this
  1168.                                         ; many bytes to longword align,
  1169.                                         ; so subtract this from the
  1170.                                         ; total.
  1171.         
  1172.         moveq.l         #0, d2
  1173.         
  1174.         bra             @2              ; Zero the last 3 or so
  1175.     @1: move.b          d2, -(PTR)      ; bytes to align PTR on a
  1176.     @2: dbra            d1, @1          ; longword boundary.
  1177.  
  1178.                                         ; Clear out as many registers
  1179.                                         ; as possible to use with MOVEM.
  1180.  
  1181.         move.l          d2, d1          ; Don't need d1 for scratch.
  1182.         move.l          d2, d3
  1183.         move.l          d2, d4
  1184.         
  1185.         cmpi.l          #TotalSize, COUNT
  1186.         bls             @6              ; If it is a smaller block, then
  1187.                                         ; jump to the section that clears
  1188.                                         ; 16 at a time.
  1189.  
  1190.                                         ; Otherwise we'll need to clear
  1191.                                         ; out the rest of these registers
  1192.                                         ; to use in a huge MOVEM.
  1193.         move.l          d2, d5
  1194.         move.l          d2, d6
  1195.         move.l          d2, d7
  1196.         movea.l         d2, a1
  1197.         movea.l         a1, a2
  1198.         movea.l         a1, a3
  1199.         movea.l         a1, a4
  1200.         movea.l         a1, a5
  1201.  
  1202.                                         ; Now zero as much as we can
  1203.                                         ; in blocks of 144 (3 movem's
  1204.                                         ; of 48 bytes each).
  1205.  
  1206.         bra             @4
  1207.     @3: Loop                            ; Add more Loops here if you
  1208.         Loop                            ; like, but adjust the #defines
  1209.         Loop                            ; above.
  1210.     @4: subi.l          #TotalSize, COUNT
  1211.         bge             @3
  1212.  
  1213.                                         ; The remaining block is now
  1214.                                         ; less than TotalSize, so now
  1215.                                         ; zero as much as we can
  1216.                                         ; in blocks of 16.
  1217.  
  1218.         addi.l          #TotalSize, COUNT
  1219.  
  1220.         bra             @6
  1221.     @5: movem.l         d1-d4, -(PTR)
  1222.     @6: subi.l          #16, COUNT
  1223.         bge             @5
  1224.                                         ; The remaining block is now
  1225.                                         ; less than 16, so now
  1226.                                         ; use byte-zeroing.
  1227.  
  1228.         addi.l          #16, COUNT
  1229.         bra             @8
  1230.     @7: move.b          d2, -(PTR)
  1231.     @8: dbra            COUNT, @7
  1232.                                         ; Restore nuked registers.
  1233.         movem.l         (sp)+,d0-d7/a0-a5
  1234.     }
  1235. }   /* BlockZero */
  1236.  
  1237. /* eof BlockZero.c */
  1238. - --
  1239. /*
  1240.  * Mike Gleason, NCEMRSoft Worldwide Development.      mgleason@cse.unl.edu
  1241.  * Patriots fan, and damn proud of it!     "Bienvenido a Macintosh" --7.0e1
  1242.  */
  1243.  
  1244. +++++++++++++++++++++++++++
  1245.  
  1246. From: wombat@claris.com (Scott Lindsey)
  1247. Date: 21 Sep 92 23:13:23 GMT
  1248. Organization: Claris Corporation, Vancouver WA
  1249.  
  1250. In article <D88-JWA.92Sep18144437@dront.nada.kth.se>, d88-jwa@dront.nada.kth.se (Jon Wtte) writes:
  1251. > How about MOVEQ.L?
  1252. On the 68000, MOVEQ can only move 8 bits into a data register; the 8 bits are
  1253. sign-extended into a long.
  1254.  
  1255. MOVEQ's timing is 8(2/0); 4(1/0) on an '010.
  1256.  
  1257. - --
  1258. Scott Lindsey <wombat@claris.com>
  1259.  
  1260. +++++++++++++++++++++++++++
  1261.  
  1262. From: ldo@waikato.ac.nz (Lawrence D'Oliveiro, Waikato University)
  1263. Date: 23 Sep 92 06:08:56 GMT
  1264. Organization: University of Waikato, Hamilton, New Zealand
  1265.  
  1266. In article <1992Sep21.223609.4608@unlinfo.unl.edu>, mgleason@cse.unl.edu (Mike Gleason) writes:
  1267.  
  1268. > :-) I evidently forgot to mention that I was using VIA_ticks() that comes
  1269. > with Symantec's ANSI library.  According to them there are "approximately
  1270. > 780,000" per second.  Originally my test suite was using system Ticks, but
  1271. > 60 units per second isn't enough so I decided to try using the VIA timer
  1272. > that Symantec's profiler uses.
  1273.  
  1274. Why not just use the Time Manager? You can get microsecond accuracy (none
  1275. of this "approximately 780,000" business). Details in IM6.
  1276.  
  1277. Lawrence D'Oliveiro                       fone: +64-7-856-2889
  1278. Computer Services Dept                     fax: +64-7-838-4066
  1279. University of Waikato            electric mail: ldo@waikato.ac.nz
  1280. Hamilton, New Zealand    37^ 47' 26" S, 175^ 19' 7" E, GMT+12:00
  1281.  
  1282. ---------------------------
  1283.  
  1284. End of C.S.M.P. Digest
  1285. **********************
  1286.