Portable C Code for High Resolution Timing in Fortran





C code is given that can be compiled and called from Fortran to give a high resolution timing of elapsed wall clock time.

  • Motivation

    For performance tuning one would often like a timer that can be inserted to see how long a particular code segment takes to execute. Having identified with a profiler such as gprof which code segents are taking time, a typical timer works as

         pretim = timefunction()
    
    code segment 
    
         entim = timefucntion()
         elapse = entim - pretim 
    

    Most Fortran compilers have high resolution timers that can be inserted in code to time code segments. High resolution timers are not standard across compilers. The Fortran standard timer in Fortran 90 typically has a resolution of about one second, which is an appropriate resolution for timing many billions of flops.

  • The MPI_WTime timer
    The MPI timer MPI_Wtime() is usually a good high resolution wall clock timer, but necessitates linking to an MPI library. That is often a good alternative, even for serial code. For example, if the the command mpif77 or mpif90 is in your path (try "find mpif77") then the following code fragment shows what to do to time a code compiled with mpif77.
          include  
          call MPI_Init()
    
    ... 
    
          pretim = MPI_Wtime()
    
      code segment to be timed 
    
          entim = MPI_Wtime()
    
    .... 
    
          call MPI_Finalize() 
    

  • Compiling
    The timer code timw2.c contains two functions designed to be called by a fortran code. they are based on the gettimeofday routine from C. In redhat linux they give wall clock time in microseconds .. of course the actual resolution is probably not that good. In cygwin the resolution is .001 seconds ..

    See the sample code test4.f compiled by

     
    gcc -c timw.c 
    g77 -c test.f
    g77 -o test timw.o test.o 
    
    The code also worked with pgf77 and pgcc (Portland group compilers) and with ifort and icc (intel compilers). On cygwin, gfort and gcc worked (as well as g77 and gcc)


  • Example Fortran Code test.f
     
    
    c------------------------------------------------------------- 
         
         
          program testtimers
    c
    c  This program measures wall clock time 
    c
    c  wdiff returns the time elapsed between the call to wdiff
    c    and the previous call to wtime.  
    c    wdiff requires that the same vector time used in the 
    c    call to wtime 
    c
    c    wdiff and wtime are C functions calling gettimeofday 
    c 
    
          real*8 sum, tim(2), elapsed , smax 
          integer i, ierr, ierr2
          i = 1
          sum = 0.d0 
          print*,' input max for sum'
          print*,' suggest numbers around 10 to 20' 
          read*, smax
          call wtime(tim, ierr)
          do while (sum .lt. smax)
            sum = sum + 1./i
            i = i+1
          end do
          elapsed = wdiff(tim,ierr2) 
          print*,' elapsed time is ', elapsed,' seconds' 
          stop 
          end 
         
    c----------------------------------------------------------
    

  • C code timw.c for the timer
    Following is the C code timw.c designed for calls by a fortran program. To call from a C program delete the underscores in wtime_ and wdiff_ and recompile.

     
    
    #include 
    #include  
    /* 
       This timer returns wall clock time.   
       The first entry is current time in seconds.
       The second entry is microseconds. 
    */ 
    void wtime_(double tim[2], int *ierr2 )
    {
       struct timeval time1; 
       int ierr; 
       double elap; 
       ierr = gettimeofday(&time1, NULL) ; 
       *ierr2 = ierr; 
       if (ierr != 0 ) printf("bad return of gettimeofday, ierr = %d \n",ierr);  
       tim[0] = time1.tv_sec;
       tim[1] = time1.tv_usec; 
    }
    /* 
       This timer returns the difference between current
       wall clock time and the one returned by wtime_ and 
       returns a double precision number 
    */ 
    double wdiff_(double tim[2], int *ierr2 )
    {
       struct timeval time1;
       int ierr; 
       double wdiff; 
       ierr = gettimeofday(&time1, NULL); 
       *ierr2 = ierr; 
       if (ierr != 0 ) printf("bad return of gettime of day, ierr = %d \n", ierr); 
       tim[0] = time1.tv_sec - tim[0];
       tim[1] = time1.tv_usec - tim[1]; 
       wdiff = 1.e6*tim[0] + tim[1]; 
       return ( wdiff/1.e6) ;   
    }   
    
    
    
    
    

  • Some other timing codes and discussions

    For a further discussion of the MPI wall clock timer, see Porting Codes. Intrinsic timers and hazards of timing wrap-arounds in GNU Fortran are discussed in Intrinsic Timers. Fortran90 timers and sample codes are given in Fortran 90 Timers (from Florida State University). A University of Texas version of wrapping C functions to get Fortran timers is found at TACC User Guide Codes.