|
||||
Title: What does the following code do???? Post by johny_cage on Oct 23rd, 2007, 10:52am void duff(register char *to, register char *from, register int count) { register int n=(count+7)/8; switch(count%8){ case 0: do{ *to++ = *from++; case 7: *to++ = *from++; case 6: *to++ = *from++; case 5: *to++ = *from++; case 4: *to++ = *from++; case 3: *to++ = *from++; case 2: *to++ = *from++; case 1: *to++ = *from++; }while( --n >0); } } Is the above valid C code? If so, what is it trying to acheive and why would anyone do something like the above? |
||||
Title: Re: What does the following code do???? Post by SMQ on Oct 23rd, 2007, 11:15am It's Duff's Device (http://en.wikipedia.org/wiki/Duff%27s_device) and was used to perform a very fast copy operation in the days before optimizing compilers. --SMQ |
||||
Title: Re: What does the following code do???? Post by johny_cage on Oct 23rd, 2007, 11:22am can u give us, example to show how it was used at that time???? |
||||
Title: Re: What does the following code do???? Post by SMQ on Oct 23rd, 2007, 11:31am Just like you posted it. The function you posted copies count characters from the address pointed to by from to the address pointed to by to in an efficient manner. It uses the switch statement to copy the first count % 8 characters, then the do loop to copy in blocks of eight from there forward. By partially unrolling the loop, fewer branches are needed and the code runs faster. Modern compilers can automatically generate similar code from a simple loop. --SMQ |
||||
Title: Re: What does the following code do???? Post by johny_cage on Oct 23rd, 2007, 1:05pm till now it is a bouncer for me. Please write a main function for this, so that i can understand how to call this... |
||||
Title: Re: What does the following code do???? Post by towr on Oct 23rd, 2007, 1:14pm If you ignore the "register" bits: int main() { char from[13] = {1,2,3,4,5,6,7,8,9,10,11,12,13}; char to[13] duff(to, from, 13); } |
||||
Title: Re: What does the following code do???? Post by SMQ on Oct 23rd, 2007, 2:12pm on 10/23/07 at 13:05:23, johny_cage wrote:
Dude, it just copies characters from one string/array/memory location to another ... efficiently. #include <stdio.h> #include <stdlib.h> #include <string.h> #include <malloc.h> #include <time.h> /* some data to copy */ const char * jabberwocky = "'Twas brillig, and the slithy toves\n" "Did gyre and gimble in the wabe:\n" "All mimsy were the borogoves,\n" "And the mome raths outgrabe.\n\n" "\"Beware the Jabberwock, my son!\n" "The jaws that bite, the claws that catch!\n" "Beware the Jubjub bird, and shun\n" "The frumious Bandersnatch!\"\n\n" "He took his vorpal sword in hand:\n" "Long time the manxome foe he sought--\n" "So rested he by the Tumtum tree,\n" "And stood awhile in thought.\n\n" "And, as in uffish thought he stood,\n" "The Jabberwock, with eyes of flame,\n" "Came whiffling through the tulgey wood,\n" "And burbled as it came!\n\n" "One, two! One, two! And through and through\n" "The vorpal blade went snicker-snack!\n" "He left it dead, and with its head\n" "He went galumphing back.\n\n" "\"And hast thou slain the Jabberwock?\n" "Come to my arms, my beamish boy!\n" "O frabjous day! Callooh! Callay!\"\n" "He chortled in his joy.\n\n" "'Twas brillig, and the slithy toves\n" "Did gyre and gimble in the wabe:\n" "All mimsy were the borogoves,\n" "And the mome raths outgrabe.\n\n"; /* a naive copy method */ void naive(char *to, const char *from, int count) { int i; for(i = 0; i < count; i++) { to[i] = from[i]; } } /* an efficient copy method */ void duff(register char *to, register const char *from, register int count) { register int n = (count + 7) / 8; switch (count % 8) { case 0: do { *to++ = *from++; case 7: *to++ = *from++; case 6: *to++ = *from++; case 5: *to++ = *from++; case 4: *to++ = *from++; case 3: *to++ = *from++; case 2: *to++ = *from++; case 1: *to++ = *from++; } while (--n > 0); } } /* copy some data using both methods and report timings */ int main(int argc, char *argv[]) { char *dest; int length, i, n; time_t before, after; /* check for correct usage */ if (argc != 2 || atoi(argv[1]) == 0) { fprintf(stderr, "usage: %s n\n n: the number of times to copy\n\n", argv[0]); return -1; } /* initialize variables */ length = strlen(jabberwocky) + 1; dest = (char *)malloc(length); n = atoi(argv[1]); /* time the naive copy */ before = time(0); for(i = 0; i < n; i++) { naive(dest, jabberwocky, length); } after = time(0); printf("Time to copy using naive method: %f seconds\n", difftime(after, before)); /* time the duff copy */ before = time(0); for(i = 0; i < n; i++) { duff(dest, jabberwocky, length); } after = time(0); printf("Time to copy using Duff method: %f seconds\n", difftime(after, before)); return 0; } Running this on my computer gives: D:\Personal\wwu>gcc -O0 duff.c -o duff D:\Personal\wwu>duff 10000000 Time to copy using naive method: 42.000000 seconds Time to copy using Duff method: 39.000000 seconds So it's not even that much of an improvement in efficiency on modern hardware. --SMQ |
||||
Title: Re: What does the following code do???? Post by KWillets on Oct 23rd, 2007, 4:51pm Just curious, try this: case 0: do { to[0] = from[0]; case 7: to[1] = from[1]; ... case 1: to[7] = from[7]; to += 8; from += 8; It's somewhat moot since char's are usually masked off from 32-64 bit words (IIRC) and are no longer simple operands, but an int version might show some differences. My guess above is that constant indices will allow the assignments to be ILP'ed. |
||||
Title: Re: What does the following code do???? Post by johny_cage on Oct 24th, 2007, 2:40am Thanks SMQ for your wonderful program. void duff(register char *to, register const char *from, register int count) { register int n = (count + 7) / 8; switch (count % 8 ) { case 0: do { *to++ = *from++; case 7: *to++ = *from++; case 6: *to++ = *from++; case 5: *to++ = *from++; case 4: *to++ = *from++; case 3: *to++ = *from++; case 2: *to++ = *from++; case 1: *to++ = *from++; } while (--n > 0); } } Please explain me one thing, if length i.e. count is not a modulo of 8, then it will not going to enter into case 0, thus no do-while loop will going to execute. And all the other CASEs are count as LABEL in do-while loop not as an CASE of SWITCH. Then how it copies the data...??? ??? |
||||
Title: Re: What does the following code do???? Post by towr on Oct 24th, 2007, 3:09am on 10/24/07 at 02:40:58, johny_cage wrote:
Quote:
A rough sketch (from switch down; and I'm just guessing on how switch is actually implemented): SWITCH_TABLE = {CASE_0, CASE_1, CASE_2, CASE_3, CASE_4, CASE_5, CASE_6, CASE_7}; GOTO SWITCH_TABLE[count %8] CASE_0: DO_LBL: *to++ = *from++; CASE_7: *to++ = *from++; CASE_6: *to++ = *from++; CASE_5: *to++ = *from++; CASE_4: *to++ = *from++; CASE_3: *to++ = *from++; CASE_2: *to++ = *from++; CASE_1: *to++ = *from++; IF (--n > 0) GOTO DO_LBL |
||||
Title: Re: What does the following code do???? Post by johny_cage on Oct 24th, 2007, 4:57am wow :o thats so nice of you towr.... thanks... now i got it right. :) |
||||
Title: Re: What does the following code do???? Post by KWillets on Oct 25th, 2007, 11:35am It's faster if the dependencies are removed: void duff(register char *to, register const char *from, register int count) { register int n = (count + 7) / 8; register int incr = (count % 8 )||8; switch (count % 8 ) { case 0: do { to[7] = from[7]; case 7: to[6] = from[6]; case 6: to[5] = from[5]; case 5: to[4] = from[4]; case 4: to[3] = from[3]; case 3: to[2] = from[2]; case 2: to[1] = from[1]; case 1: to[0] = from[0]; to += incr; from += incr; incr = 8; } while (--n > 0); } } $ ./duff 5000000 Time to copy using naive method: 21.000000 seconds Time to copy using Duff method: 10.000000 seconds |
||||
Title: Re: What does the following code do???? Post by SMQ on Oct 25th, 2007, 12:17pm True, but bear in mind that the "device" was originally written in 1983, on a VAX, and even then was more an implementation curiosity than a serious proposal for an optimized copy function. (For reference, here is Duff's take on it (http://www.lysator.liu.se/c/duffs-device.html).) With modern architecture unrolling short loops is rarely profitable (the CPU's branch predictor removes much if not all of the overhead), and, as you note, there are better ways to optimize a copy. These days Duff's device is primarily noted for its 1) novelty, 2) compactness, and 3) ability to cause consternation. ;) --SMQ |
||||
Title: Re: What does the following code do???? Post by KWillets on Oct 25th, 2007, 2:01pm It's a curiosity. It was interesting to see if it had any effect on newer processors. |
||||
Title: Re: What does the following code do???? Post by Grimbal on Oct 26th, 2007, 2:20am On newer processors, you would probably want to take advantage of 32-bit or 64-bit transfers. |
||||
Powered by YaBB 1 Gold - SP 1.4! Forum software copyright © 2000-2004 Yet another Bulletin Board |