Explanation, please!

Daniel R. Levy levy at ttrdc.UUCP
Sun Aug 28 13:24:29 AEST 1988


In article <653 at paris.ICS.UCI.EDU>, schmidt at bonnie.ics.uci.edu (Douglas C. Schmidt) writes:
> Hi,
> 
>    Since I posted my original question there has been a great deal of
> abstract discussion about the relative merits of the loop unrolling
> scheme.  The topic has piqued my curiousity, so I when ahead and
> implemented a short test program, included below, to test Duff's
> device against the ``ordinary for loop w/index variable'' technique.
> See for yourself....   
> 
> After some quick testing I found that gcc 1.26 -O on a Sun 3 and a
> Sequent Balance was pretty heavily in favor of the regular (non-Duff)
> loop.  Your mileage may vary.  I realize that there may be other
> tests, and if anyone has a better version, I'd like to see it!

[schmidt's program deleted, please refer to parent article if you want it]

I modified this program to run under System V, changed the arrays to be dynam-
ically allocated, and changed both the Duff and ordinary copies to use register
pointers instead of global pointers (for the Duff copy) and array indexing (for
the ordinary copy).  I then tried it on a SVR2 3B20, a SVR3 3B2, a Sun-3, and a
Sun-4 both with and without -O optimization (using the standard pcc-type C
compiler on each system).  The result?  Duff wins by about 10%-20% on all
machines tested.

Here is the code thus modified:


#include <sys/types.h>
#include <sys/times.h>
#include <sys/param.h>

double Start_Timer();
double Return_Elapsed_Time();

#define DEFAULT_NUM 100000

main(argc,argv) char **argv; {
   double Elapsed_Time_Duff;
   double Elapsed_Time_Ordinary;
   int    Count = argc > 1 ? atoi(argv[1]) : DEFAULT_NUM;
   int i;
   register int *A, *B;
   register int n;
   register int *A_end;
   int *array1, *array2;
   char *malloc();

   if (Count <= 0) {
       printf("Bad Count\n");
       return 1;
   } else {
       printf("Count=%d\n", Count);
   }

   if (!(array1=(int *)malloc(sizeof(int) * Count))) {
      printf("Can't malloc %u bytes for array1\n", sizeof(int) * Count);
      return 1;
   } else if (!(array2=(int *)malloc(sizeof(int) * Count))) {
      printf ("Can't malloc %u bytes for array2\n", sizeof(int) * Count);
      return 1;
   }
   
   for (i = 0;i < Count ;i++) {
      array1[i] = i + 1;
      array2[i] = i;
   }
      
   printf("Starting Duff's device timing...\n");
   Start_Timer();

   {
      n = (Count + 7) / 8;
      A = array1;
      B = array2;

      switch(Count & 0x7) {
         case 0:  do { *A++ = *B++;
         case 7:       *A++ = *B++;
         case 6:       *A++ = *B++;
         case 5:       *A++ = *B++;
         case 4:       *A++ = *B++;
         case 3:       *A++ = *B++;
         case 2:       *A++ = *B++;
         case 1:       *A++ = *B++;
                  } while (--n > 0);
      }
   }

   Elapsed_Time_Duff = Return_Elapsed_Time(0.0 );
   printf("Elapsed time = %.3lf\n",Elapsed_Time_Duff);

   for (i = 0;i < Count ;i++) {
      if (array1[i] != array2[i]) {
         printf("Yow, problems at location %d!\n",i);
         break;
      }
   }

   for (i = 0;i < Count ;i++) {
      array1[i] = i + 1;
      array2[i] = i;
   }

   printf("Starting ordinary copy timing...\n");
   Start_Timer();

   {
      A = array1;
      B = array2;
      A_end = array1 + Count - 1;

      while (A <= A_end)
         *A++ = *B++;
   }

   Elapsed_Time_Ordinary = Return_Elapsed_Time(0.0 );
   printf("Elapsed time = %.3lf\n",Elapsed_Time_Ordinary);

   for (i = 0;i < Count ;i++) {
      if (array1[i] != array2[i]) { 
         printf("Yow, problems at location %d!\n",i);
         break;
      }
   }
   printf("Duff/Ordinary copy time ratio = %.3lf\n",
      Elapsed_Time_Duff/Elapsed_Time_Ordinary);

}      


/* no such thing as "negative time"! */
#define  ERROR_VALUE -1.0   

static struct tms Old_Time;
static struct tms New_Time;
static int    Timer_Set = 0;

#ifdef __STDC__
double Start_Timer(void)
#else
double Start_Timer()
#endif
{
   Timer_Set = 1;
   times(&Old_Time);		/* set starting process time */
   return ((double)Old_Time.tms_utime)/(double)HZ;
}

/* returns process time since Last_Time (if parameter is not DEFAULT_TIME, */
/* i.e., (double) 0.0 ),otherwise, if parameter == DEFAULT_TIME then       */
/* the time since the Old_Time was set is returned.  Returns ERROR_VALUE   */
/* if Start_Timer() is not called first */
#ifdef __STDC__
double Return_Elapsed_Time(double Last_Time)
#else
double Return_Elapsed_Time(Last_Time) 
double Last_Time;
#endif
{
   if (!Timer_Set) {
      return(ERROR_VALUE);
   }   
   else {
    /* get process time */
      times(&New_Time);
      if (Last_Time == 0.0) {
	 return ((double)(New_Time.tms_utime - Old_Time.tms_utime))/(double) HZ;
      }
      else {
	 return (((double)New_Time.tms_utime)/(double)HZ) - Last_Time;
      }
   }
}


-- 
|------------Dan Levy------------|  THE OPINIONS EXPRESSED HEREIN ARE MINE ONLY
| Bell Labs Area 61 (R.I.P., TTY)|  AND ARE NOT TO BE IMPUTED TO AT&T.
|        Skokie, Illinois        | 
|-----Path:  att!ttbcad!levy-----|



More information about the Comp.lang.c mailing list