diff --git a/.gitignore b/.gitignore index ef7cd62..9517f08 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ packages/*.rpm packages/sourceforge.sh packages/version src/*.pyc +src/*.pyo irpf90.make irpf90_entities IRPF90_temp diff --git a/src/command_line.py b/src/command_line.py index b01ba7b..b83bee1 100644 --- a/src/command_line.py +++ b/src/command_line.py @@ -39,6 +39,7 @@ options['i'] = [ 'init' , 'Initialize current directory', 0 ] options['D'] = [ 'define' , 'Define variable', 1 ] options['o'] = [ 'checkopt' , 'Show where optimization may be required', 0 ] options['p'] = [ 'preprocess' , 'Preprocess file', 1 ] +options['g'] = [ 'profile' , 'Generate profile code', 0 ] options['t'] = [ 'touch' , 'Display which entities are touched', 1 ] options['m'] = [ 'memory' , 'Debug memory info', 0 ] options['z'] = [ 'openmp' , 'Automatic openMP tasks (may not work)', 0 ] diff --git a/src/irpf90.py b/src/irpf90.py index 57f4af6..e658eda 100644 --- a/src/irpf90.py +++ b/src/irpf90.py @@ -66,6 +66,10 @@ def main(): for x in parents: print "- %s"%(x,) + if command_line.do_profile: + import profile + profile.run() + if not command_line.do_run: return diff --git a/src/makefile.py b/src/makefile.py index 7cdcef8..96827e8 100644 --- a/src/makefile.py +++ b/src/makefile.py @@ -73,6 +73,8 @@ def run(): result += " %sirp_touches.irp.F90"%(irpdir) if command_line.do_openmp: result += " %sirp_locks.irp.F90"%(irpdir) + if command_line.do_profile: + result += " %sirp_profile.irp.F90"%(irpdir) for m in mod: result += " %s%s.irp.F90"%(irpdir,m.name[:-4]) result += " %s%s.irp.module.F90"%(irpdir,m.name[:-4]) @@ -86,8 +88,10 @@ def run(): print >>file, result print >>file, "OBJ1 = $(patsubst %%, %s%%,$(notdir $(OBJ))) %sirp_touches.irp.o"%(irpdir,irpdir), + if command_line.do_profile: + print >>file, " %sirp_profile.irp.o"%(irpdir), " %sirp_rdtsc.o"%(irpdir), if command_line.do_openmp: - print >>file, " %sirp_locks.irp.o"%(irpdir) + print >>file, " %sirp_locks.irp.o"%(irpdir), else: print >>file, "" @@ -117,6 +121,9 @@ def run(): mds = filter(lambda x: not x.is_main,mod) mds = map(lambda x: " %s%s.irp.o %s%s.irp.o"%(irpdir,x.name[:-4],irpdir,x.name[:-4]),mds) print >>file," ".join(mds) + if command_line.do_profile: + print >>file, "%sirp_profile.irp.o:"%(irpdir), + print >>file," ".join(mds) if command_line.do_openmp: print >>file, "%sirp_locks.irp.o:"%(irpdir), print >>file," ".join(mds) diff --git a/src/module.py b/src/module.py index 2eb6a36..3e3fe05 100644 --- a/src/module.py +++ b/src/module.py @@ -184,6 +184,8 @@ class Fmodule(object): result = map(lambda x: x.text, result) if self.is_main: temp = [ "program irp_program" ] + if command_line.do_profile: + temp += [ "call irp_init_timer()" ] if command_line.do_openmp: temp += [ "!$OMP PARALLEL" ] temp += [ "!$OMP MASTER" ] @@ -191,6 +193,8 @@ class Fmodule(object): if command_line.do_openmp: temp += [ "!$OMP END MASTER" ] temp += [ "!$OMP END PARALLEL" ] + if command_line.do_profile: + temp += [ "call irp_print_timer()" ] temp += [ " call irp_finalize_%s()"%(irp_id) ] temp += [ "end program" ] result = temp + result diff --git a/src/profile.py b/src/profile.py new file mode 100644 index 0000000..4732a2c --- /dev/null +++ b/src/profile.py @@ -0,0 +1,92 @@ +#!/usr/bin/python + +rdtsc = """ +#define uint64_t unsigned long +//#ifdef __i386 +uint64_t irp_rdtsc_() { + uint64_t x; + __asm__ volatile ("rdtsc" : "=A" (x)); + return x; +} +#if __amd64 +uint64_t irp_rdtsc_() { + uint64_t a, d; + __asm__ volatile ("rdtsc" : "=a" (a), "=d" (d)); + return (d<<32) | a; +} +#endif +""" + +import subprocess +import tempfile +import os +from variables import variables + +def build_rdtsc(): + file,filename = tempfile.mkstemp() + filename += ".c" + file = open(filename,'w') + file.write(rdtsc) + file.close() + p = subprocess.Popen(["gcc","-O3",filename,"-c","-o","IRPF90_temp/irp_rdtsc.o"]) + p.communicate() + os.remove(filename) + +def build_module(): + data = """ +module irp_timer + double precision :: irp_profile(2,%(n)d) + character*(64) :: irp_profile_label(%(n)d) +end module + +subroutine irp_init_timer + use irp_timer + implicit none + irp_profile = 0. +%(text)s +end + +subroutine irp_set_timer(i,value) + use irp_timer + implicit none + integer, intent(in) :: i + integer*8, intent(in) :: value + irp_profile(1,i) = dble(value) + irp_profile(2,i) = irp_profile(2,i)+1.d0 +end + +subroutine irp_print_timer() + use irp_timer + implicit none + integer :: i + print '(16X,5(2X,A16))', 'Num Calls', 'Tot Cycles', 'Avge Cycles', & + 'Tot Secs(1GHz)', 'Avge Secs(1GHz)' + do i=1,%(n)d + if (irp_profile(2,i) > 0.) then + print '(A16,5(2X,F16.4))', irp_profile_label(i), irp_profile(2,i), & + irp_profile(1,i), irp_profile(1,i)/irp_profile(2,i), & + irp_profile(1,i)*1.d-9, 1.d-9*irp_profile(1,i)/irp_profile(2,i) + endif + enddo +end + """ + label = {} + for i in variables: + vi = variables[i] + label[vi.label] = vi.name + text = [] + for l in label: + text.append(" irp_profile_label(%d) = '%s'"%(l,label[l])) + text.sort() + text = '\n'.join(text) + data = data%{'text': text, 'n':len(label.keys())} + 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() diff --git a/src/variable.py b/src/variable.py index 89bd434..351bfd0 100644 --- a/src/variable.py +++ b/src/variable.py @@ -33,10 +33,11 @@ from command_line import command_line class Variable(object): ############################################################ - def __init__(self,text,name = None): + def __init__(self,text,label,name = None): assert type(text) == list assert len(text) > 0 assert type(text[0]) == Begin_provider + self.label = label self.text = text if name is not None: self._name = name @@ -259,8 +260,9 @@ class Variable(object): result.append(" implicit none") if command_line.do_debug: length = str(len("touch_%s"%(name))) - result += [ " character*(%s) :: irp_here = 'touch_%s'"%(length,name), - " call irp_enter(irp_here)" ] + result += [ " character*(%s) :: irp_here = 'touch_%s'"%(length,name) ] + if command_line.do_debug: + result += [ " call irp_enter(irp_here)" ] result += map( lambda x: " %s_is_built = .False."%(x), parents) result.append(" %s_is_built = .True."%(name)) if command_line.do_debug: @@ -555,6 +557,9 @@ class Variable(object): if inside: text.append( (vars,line) ) text += map( lambda x: ([],Simple_line(line.i,x,line.filename)), call_provides(vars) ) + if command_line.do_profile and type(line) == Begin_provider: + text.append( ( [], Declaration(line.i," integer*8 :: irp_rdtsc, irp_rdtsc1, irp_rdtsc2",line.filename) ) ) + text.append( ( [], Simple_line(line.i," irp_rdtsc1 = irp_rdtsc()",line.filename) ) ) if type(line) == End_provider: if inside: break @@ -570,6 +575,9 @@ class Variable(object): elif type(line) == Cont_provider: pass elif type(line) == End_provider: + if command_line.do_profile: + result += [ " irp_rdtsc2 = irp_rdtsc()" , + " call irp_set_timer(%d,(irp_rdtsc2-irp_rdtsc1))"%self.label ] result.append( "end subroutine bld_%s"%(name) ) break else: diff --git a/src/variables.py b/src/variables.py index 7cfba32..c86c844 100644 --- a/src/variables.py +++ b/src/variables.py @@ -34,6 +34,7 @@ from util import * def create_variables(): from preprocessed_text import preprocessed_text result = {} + icount = 0 for filename, text in preprocessed_text: buffer = [] inside = False @@ -44,10 +45,11 @@ def create_variables(): buffer.append(line) if type(line) == End_provider: inside = False - v = Variable(buffer) + icount += 1 + v = Variable(buffer,icount) result[v.name] = v for other in v.others: - result[other] = Variable(buffer,other) + result[other] = Variable(buffer,icount,other) buffer = [] return result