#!/usr/bin/env python2
#   IRPF90 is a Fortran90 preprocessor written in Python for programming using
#   the Implicit Reference to Parameters (IRP) method.
#   Copyright (C) 2009 Anthony SCEMAMA 
#
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 2 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License along
#   with this program; if not, write to the Free Software Foundation, Inc.,
#   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
#   Anthony Scemama
#   LCPQ - IRSAMC - CNRS
#   Universite Paul Sabatier
#   118, route de Narbonne      
#   31062 Toulouse Cedex 4      
#   scemama@irsamc.ups-tlse.fr


rdtsc = """
#ifdef __i386
double irp_rdtsc_(void) {
  unsigned long long x;
  __asm__ volatile ("rdtsc" : "=A" (x));
  return (double) x;
}
#elif __amd64
double irp_rdtsc_(void) {
  unsigned long long a, d;
  __asm__ volatile ("rdtsc" : "=a" (a), "=d" (d));
  return (double)((d<<32) | a);
}
#endif
"""

import subprocess
import tempfile
import os
import threading
from irpf90_t import irpdir

def build_rdtsc():
  filename = irpdir+"irp_rdtsc.c"
  file = open(filename,'w')
  file.write(rdtsc)
  file.close()
  def t():
    p = subprocess.Popen(["gcc","-O2",filename,"-c","-o","irp_rdtsc.o"])
    p.communicate()
    os.remove(filename)

  threading.Thread(target=t).start()

def build_module():
  from variables import variables
  data = """
module irp_timer
 double precision :: irp_profile(3,%(n)d) 
 integer          :: irp_order(%(n)d) 
 character*(64)   :: irp_profile_label(%(n)d)
 double precision :: irp_rdtsc_shift

 contains

   subroutine profile_sort ()
    implicit none
    character*(64)         :: xtmp
    integer                :: i, i0, j, jmax

    do i=1,size(irp_profile_label)
     irp_order(i)=i
    enddo
    do i=1,size(irp_profile_label)
     xtmp = irp_profile_label(i)
     i0 = irp_order(i)
     j = i-1
     do j=i-1,1,-1
      if ( irp_profile_label(j) > xtmp ) then
       irp_profile_label(j+1) = irp_profile_label(j)
       irp_order(j+1) = irp_order(j)
      else
       exit
      endif
     enddo
     irp_profile_label(j+1) = xtmp
     irp_order(j+1) = i0
    enddo
   end subroutine profile_sort

end module

subroutine irp_init_timer
 use irp_timer
 implicit none
 integer :: i
 double precision :: irp_rdtsc, t0
 irp_profile = 0.d0
 irp_rdtsc_shift = 0.d0
 do i=1,1000000
   t0 = irp_rdtsc()
 enddo
 irp_rdtsc_shift = 1.d-6*(irp_rdtsc()-t0)
%(text)s
end

subroutine irp_set_timer(i,value)
 use irp_timer
 implicit none
 integer, intent(in) :: i
 double precision, intent(inout) :: value
 value = value - irp_rdtsc_shift
 irp_profile(1,i) = irp_profile(1,i) + value
 irp_profile(2,i) = irp_profile(2,i) + value*value
 irp_profile(3,i) = irp_profile(3,i) + 1.d0
end

subroutine irp_print_timer()
 use irp_timer
 implicit none
 integer :: i, ii
 double precision :: error, sigma2, average, average2, frequency, t0
 double precision :: irp_rdtsc
 t0 = irp_rdtsc()
 call sleep(1)
 frequency = (irp_rdtsc()-t0-irp_rdtsc_shift)

 call profile_sort()
 print '(A24,A8,A17,A20,A13,A20)', '', 'N.Calls', 'Tot Cycles', 'Avg Cycles', &
                          'Tot Secs', 'Avg Secs'
   print '(A)', '---------------------------------------------------'// &
                '---------------------------------------------------'
 do ii=1,%(n)d
  i = irp_order(ii)
  if (irp_profile(3,i) > 0.) then
   error = 0.d0
   average  = irp_profile(1,i)/irp_profile(3,i)
   if (irp_profile(3,i) > 1.d0) then
     average2 = irp_profile(2,i)/irp_profile(3,i)
     sigma2   = (average2 - average*average)
     error = sqrt(sigma2/(irp_profile(3,i)+1.d0))
   endif
   print '(A24 , F8.0 , X,F12.0 , X,F12.0,A3,F8.0, X,F12.8, X,F8.5,A3,F8.5 )', &
     irp_profile_label(ii), &
     irp_profile(3,i), &
     irp_profile(1,i), &
     average, '+/-', error, &
     irp_profile(1,i)/frequency, &
     average/frequency, '+/-', error/frequency
  endif
 enddo
 print *, 'Frequency     :', frequency*1.d-9, ' GHz'
 print *, 'rdtsc latency :', irp_rdtsc_shift, ' cycles'
end
  """
  label = {}
  for i in variables:
    vi = variables[i]
    label[vi.label] = vi.same_as
  text = []
  lmax = 0
  for l in label:
    text.append(" irp_profile_label(%d) = '%s'"%(l,label[l]))
    lmax = max(lmax,l)
  text.sort()
  text = '\n'.join(text)
  data = data%{'text': text, 'n':lmax}
  file = open("IRPF90_temp/irp_profile.irp.F90",'w')
  file.write(data)
  file.close()

def run():
  build_module()
  build_rdtsc()

if __name__ == "__main__":
  build_rdtsc()
