From 974775a9a59b23eb4be0a0d664eca67e0ff50d3b Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Thu, 16 Feb 2017 18:10:21 -0600 Subject: [PATCH] Add template. Repare OMP_Lock --- src/build_file.py | 10 +- src/entity.py | 497 ++++++++++-------------------------- src/irpy_files.py | 17 +- src/module.py | 34 +-- src/preprocessed_text.py | 8 +- src/templates/allocater.f90 | 47 ++++ src/templates/finalize.f90 | 13 + src/templates/irp_lock.f90 | 31 +++ src/templates/module.f90 | 40 +++ src/templates/provider.f90 | 43 ++++ src/templates/touch.f90 | 26 ++ src/touches.py | 35 +-- src/util.py | 43 +++- 13 files changed, 423 insertions(+), 421 deletions(-) create mode 100644 src/templates/allocater.f90 create mode 100644 src/templates/finalize.f90 create mode 100644 src/templates/irp_lock.f90 create mode 100644 src/templates/module.f90 create mode 100644 src/templates/provider.f90 create mode 100644 src/templates/touch.f90 diff --git a/src/build_file.py b/src/build_file.py index 8094f12..2115734 100644 --- a/src/build_file.py +++ b/src/build_file.py @@ -271,13 +271,21 @@ def create_build_remaining(f,ninja): if extension.lower() in ['f', 'f90']: result = ["build {target_o}: compile_fortran_{irp_id} {target_i}"] + result_make = [ + '{target_o}: {target_i}', + '\t@printf "F: {short_target_o} -> {short_target_i}\\n"', + "\t@$(FC) $(FCFLAGS) -c $^ -o $@", ""] + elif extension.lower() in ['c']: result = ["build {target_o}: compile_c_{irp_id} {target_i}"] elif extension.lower() in ['cxx', 'cpp']: result = ["build {target_o}: compile_cxx_{irp_id} {target_i}"] result += [" short_in = {short_target_i}", " short_out = {short_target_o}", ""] - return '\n'.join(result).format(**locals()) + + result_final = result if ninja else result_make + + return '\n'.join(result_final).format(**locals()) def create_makefile(d_flags,d_var,irpf90_flags,ninja=True): diff --git a/src/entity.py b/src/entity.py index f48d095..33ee3ea 100644 --- a/src/entity.py +++ b/src/entity.py @@ -42,8 +42,8 @@ class Entity(object): ############################################################ def __init__(self, text, label, name=None, comm_world=None): - # (list[str], str, int, Irpy_comm_world) - '''Instantiate the object. + # (list[str], str, int, Irpy_comm_world) + '''Instantiate the object. Args: text: List of lines between BEGIN_PROVIDER and END_PROVIDER included @@ -59,18 +59,17 @@ class Entity(object): self.label = label self.text = text - self.same_as = text[0].filename[1] + self.same_as = text[0].filename[1] self.name = name if name else self.same_as self.comm_world = comm_world - # ~ # ~ # ~ # G l o b a l P r o p e r t y # ~ # ~ # ~ @irpy.lazy_property def d_entity(self): - # () -> Dict[str,Entity] + # () -> Dict[str,Entity] '''Create an alias to the global dictionary of Entity. Note: Be aware of the possiblity of Cyclic Dependency. @@ -79,7 +78,7 @@ class Entity(object): @irpy.lazy_property def cm_t_filename_parsed_text(self): - # () -> Tuple[str, Parsed_text] + # () -> Tuple[str, Parsed_text] '''Create an alias to the global tuple for parsed text Note: self.comm_world.t_filename_parsed_text need d_entity. @@ -89,22 +88,21 @@ class Entity(object): @irpy.lazy_property def d_type_lines(self): - # () -> Dict[Line, Tuple[int,Line] ] - '''Contruct a mapping table between the type of the line and the possition''' + # () -> Dict[Line, Tuple[int,Line] ] + '''Contruct a mapping table between the type of the line and the possition''' from collections import defaultdict d = defaultdict(list) for i, line in enumerate(self.text): d[type(line)] += [(i, line)] return d - # ~ # ~ # ~ # M u l t i p l e P r o v i d e r H a n d l e r # ~ # ~ # ~ @irpy.lazy_property def is_main(self): - # () -> bool - '''Check if this Entity is the main one + # () -> bool + '''Check if this Entity is the main one Exemple: BEGIN_PROVIDER [pi, double precision] & @@ -114,11 +112,10 @@ class Entity(object): ''' return self.name == self.same_as - @irpy.lazy_property def prototype(self): - # () -> Line - '''Find the declaration statement associated with the name of the provider + # () -> Line + '''Find the declaration statement associated with the name of the provider Exemple: BEGIN_PROVIDER [pi, double precision] & @@ -127,33 +124,33 @@ class Entity(object): if self.name == e, will return BEGIN_PROVIDER [e, double preision] ''' - d = self.d_type_lines - return next(line for _,line in d[Begin_provider]+d[Cont_provider] if line.filename[1] == self.name) + d = self.d_type_lines + return next(line for _, line in d[Begin_provider] + d[Cont_provider] + if line.filename[1] == self.name) @irpy.lazy_property def l_name(self): - # () -> List[str] - d = self.d_type_lines - return [line.filename[1] for _,line in d[Begin_provider]+d[Cont_provider] ] + # () -> List[str] + d = self.d_type_lines + return [line.filename[1] for _, line in d[Begin_provider] + d[Cont_provider]] @irpy.lazy_property def l_others_name(self): - # () -> List[str] - '''Extract the other entity-name defined''' - return [name for name in self.l_name if not name == self.name] - + # () -> List[str] + '''Extract the other entity-name defined''' + return [name for name in self.l_name if not name == self.name] @irpy.lazy_property def doc(self): - # () -> List[str] - doc = [line.text.lstrip()[1:] for _,line in self.d_type_lines[Doc]] + # () -> List[str] + doc = [line.text.lstrip()[1:] for _, line in self.d_type_lines[Doc]] if not doc: logger.warning("Entity '%s' is not documented" % (self.name)) return doc @irpy.lazy_property def documented(self): - #() -> bool + #() -> bool return bool(self.doc) # ~ # ~ # ~ @@ -162,8 +159,8 @@ class Entity(object): @irpy.lazy_property_mutable def is_written(self): - #() -> bool - '''Check if it will be written on disk''' + #() -> bool + '''Check if it will be written on disk''' return any(self.d_entity[i].is_written for i in self.parents) @irpy.lazy_property @@ -171,7 +168,7 @@ class Entity(object): if not self.is_main: result = [] else: - from util import mangled + from util import mangled name = self.name result = [ \ "subroutine writer_%s(irp_num)"%(name), @@ -210,7 +207,7 @@ class Entity(object): @irpy.lazy_property_mutable def is_read(self): - '''Check if it will be read from disk''' + '''Check if it will be read from disk''' return any(self.d_entity[i].is_read for i in self.parents) @irpy.lazy_property @@ -218,7 +215,7 @@ class Entity(object): if not self.is_main: result = [] else: - from util import mangled + from util import mangled name = self.name result = [ \ "subroutine reader_%s(irp_num)"%(name), @@ -255,7 +252,7 @@ class Entity(object): @irpy.lazy_property def is_source_touch(self): - return (Touch in self.d_type_lines or SoftTouch in self.d_type_lines) + return (Touch in self.d_type_lines or SoftTouch in self.d_type_lines) @irpy.lazy_property_mutable def is_self_touched(self): @@ -267,8 +264,8 @@ class Entity(object): '''If any of the children is touched, the entity is touched''' if self.is_self_touched or any(self.d_entity[i].is_touched for i in self.children): return True - - return False + + return False # ~ # ~ # ~ # INCLUDE, USE, CALL @@ -276,23 +273,23 @@ class Entity(object): @irpy.lazy_property def includes(self): - # () -> str - '''Extract the name of include who need be to be include in this Entity''' - return [line.filename for _,line in self.d_type_lines[Include]] + # () -> str + '''Extract the name of include who need be to be include in this Entity''' + return [line.filename for _, line in self.d_type_lines[Include]] @irpy.lazy_property def uses(self): - '''Extract the name of module who are used in this Entity''' - return [line.filename for _,line in self.d_type_lines[Use]] + '''Extract the name of module who are used in this Entity''' + return [line.filename for _, line in self.d_type_lines[Use]] @irpy.lazy_property def calls(self): - '''Extract the name ofthe function called by the entity''' + '''Extract the name ofthe function called by the entity''' - def extract_name(line): - return line.text.split('(', 1)[0].split()[1].lower() + def extract_name(line): + return line.text.split('(', 1)[0].split()[1].lower() - return [extract_name(line) for _,line in self.d_type_lines[Call] ] + return [extract_name(line) for _, line in self.d_type_lines[Call]] # ~ # ~ # ~ # Array Dimension @@ -300,8 +297,8 @@ class Entity(object): @irpy.lazy_property def dim(self): - # () -> List[str] - '''Extract the dimension of the needed array in a form of list of variable name + # () -> List[str] + '''Extract the dimension of the needed array in a form of list of variable name Exemple: BEGIN_PROVIDER [real, ao_num ] @@ -324,7 +321,6 @@ class Entity(object): else: return map(str.strip, x[1:-1].split(',')) - @irpy.lazy_property def allocate(self): # () -> List[Str] @@ -338,62 +334,54 @@ class Entity(object): # ~ # ~ # ~ # D e c l a r a t i o n # ~ # ~ # ~ - + @irpy.lazy_property + def is_protected(self): + return self.text[0].lower.startswith('begin_provider_immu') + @irpy.lazy_property def type(self): - # () -> str - '''Compute the fortran type code of the entity''' + # () -> str + '''Compute the fortran type code of the entity''' type_ = self.prototype.text.split(',')[0].split('[')[1].strip() - if not type_: - logger.error( "Error in definition of %s." % (self.name)) - sys.exit(1) + if not type_: + logger.error("Error in definition of %s." % (self.name)) + sys.exit(1) - if self.dim: + if self.dim: return "%s, allocatable" % (type_) else: return type_ @irpy.lazy_property - def header(self): - # () -> List[str] - '''Compute all the code needed to inistanticant the entity''' - - - name = self.name - str_ = " {type_} :: {name} {dim}".format(type_=self.type, name=name, dim=build_dim(self.dim, colons=True)) - - if command_line.coarray: - if not self.dim: - str_ += " [*]" - else: - str_ += " [:]" - - l = [str_] - if self.dim and command_line.align != '1': - l += [" !DIR$ ATTRIBUTES ALIGN: %s :: %s" % (command_line.align, name)] - - if self.is_main: - l += [" logical :: %s_is_built = .False." % (name)] - - return l + def d_header(self): + # () -> List[str] + '''Compute all the code needed to inistanticant the entity''' + import util + d_template = { + 'name': self.name, + 'type': self.type, + 'main': self.is_main, + 'dim': build_dim(self.dim,colons=True), + 'protected': '\n'.join(self.allocater+self.builder) if self.is_protected else False} + return d_template ############################################################ @irpy.lazy_property def fmodule(self): # () -> str - '''Contruct the name of the module who will contain the entity''' + '''Contruct the name of the module who will contain the entity''' name = self.prototype.filename[0].replace('/', '__').split('.irp.f')[0] return '%s_mod' % name ############################################################ @irpy.lazy_property def regexp(self): - # () -> Regex + # () -> Regex '''Compile a regex targeted to 'search' the name of this entity''' - import re + import re return re.compile(r"([^a-z0-9'\"_]|^)%s([^a-z0-9_]|$)" % (self.name), re.I).search # ~ # ~ # ~ @@ -401,118 +389,35 @@ class Entity(object): # ~ # ~ # ~ @irpy.lazy_property - def toucher(self): - # () -> List[str] - '''Fabric the f90 routine who handle the cache invalidation''' + def d_touche_template(self): + # () -> List[str] + '''Fabric the f90 routine who handle the cache invalidation''' # Only one by EntityColleciton if not self.is_main: - return [] + return {} - template = ''' -SUBROUTINE touch_{name} + from util import mangled - {#l_module} - {name} - {/l_module} - - IMPLICIT NONE - {?do_debug} - CHARACTER*(6+{@size key=name/}),PARAMETER :: irp_here = 'touch_{name}' - {/do_debug} - - {?do_debug} - CALL irp_enter(irp_here) - {/do_debug} - - {#l_ancestor} - {name}_is_built = .FALSE. - {/l_ancestor} - - {name}_is_built = .TRUE. - - {?do_debug} - CALL irp_leave(irp_here) - {/do_debug} - -END SUBROUTINE touch_{name} -''' - - # Only one by EntityColleciton - if not self.is_main: - return [] - - from util import mangled - l_parents = [{'name':n} for n in mangled(self.parents,self.d_entity)] - name = self.name - l_module= [ {'name':n} for n in build_use(self.parents+[name],self.d_entity)] - - from ashes import AshesEnv - ashes_env = AshesEnv() - ashes_env.register_source('touch',template) - - l = ashes_env.render('touch', {'name': name, - 'l_module':l_module, - 'l_ancestor':l_parents, - 'do_debug':command_line.do_debug}) - return [i for i in l.split('\n') if i] - - ########################################################## - @irpy.lazy_property - def locker(self): - if not command_line.do_openmp: - return [] - - name = self.name - result = ["subroutine irp_lock_%s(set)" % (name)] - result += [ - " use omp_lib", - " implicit none", - " logical, intent(in) :: set", - " integer(kind=omp_nest_lock_kind),save :: %s_lock" % (name), - " integer,save :: ifirst", - ] - if command_line.do_debug: - length = str(len("irp_lock_%s" % (name))) - result += [ - " character*(%s) :: irp_here = 'irp_lock_%s'" % (length, name), - " call irp_enter(irp_here)" - ] - - result += [ - " if (ifirst == 0) then", - " ifirst = 1", - " call omp_init_nest_lock(%s_lock)" % (name), - " endif", - " if (set) then", - " call omp_set_nest_lock(%s_lock)" % (name), - " else", - " call omp_unset_nest_lock(%s_lock)" % (name), - " endif", - ] - if command_line.do_debug: - result.append(" call irp_leave(irp_here)") - result.append("end subroutine irp_lock_%s" % (name)) - result.append("") - return result + return { + 'name': self.name, + 'l_module': [n for n in build_use(self.parents + [self.name], self.d_entity,use=False)], + 'l_ancestor': [n for n in mangled(self.parents, self.d_entity)]} ########################################################## + @irpy.lazy_property def free(self): - # () -> List[ str ] - '''Compute an part of a subroutine used to free a variable''' + # () -> List[ str ] + '''Compute an part of a subroutine used to free a variable''' name = self.name - result = ["!", - "! >>> FREE %s" % (name), - " %s_is_built = .False." % (self.same_as)] + result = ["!", "! >>> FREE %s" % (name), " %s_is_built = .False." % (self.same_as)] if self.dim: - result += [ - " if (allocated(%s)) then"%(name), - " deallocate (%s)"%(name)] + result += [" if (allocated(%s)) then" % (name), " deallocate (%s)" % (name)] if command_line.do_memory: - result += " print *, 'Deallocating %s'"%(name) + result += " print *, 'Deallocating %s'" % (name) result += [" endif"] @@ -522,190 +427,59 @@ END SUBROUTINE touch_{name} ########################################################## @irpy.lazy_property def provider(self): - # () -> List[str] - '''Create the fortran90 code for the EntityCollection''' + # () -> List[str] + '''Create the fortran90 code for the EntityCollection''' if not self.is_main: return [] - from ashes import AshesEnv - template = ''' -{#l_allocate} -{subroutine|s} -{/l_allocate} - -{?inline} -!DEC$ ATTRIBUTES FORCEINLINE :: provide_{name} -{/inline} -SUBROUTINE provide_{name} - - {?do_openmp} - use omp_lib - {/do_openmp} - - {#l_module} - {name} - {/l_module} - - implicit none - {?do_debug} - character*(8+{@size key=name/}),parameter :: irp_here = 'provide_{name}' - {/do_debug} - - {?do_openmp} - CALL irp_lock_{name}(.TRUE.) - {/do_openmp} - - {?do_debug} - CALL irp_enter(irp_here) - {/do_debug} - - {#l_children} - IF (.NOT.{name}_is_built) THEN - CALL provide_{name} - ENDIF - {/l_children} - - {#do_task} - !$OMP TASK DEFAULT(shared) {depend} - {/do_task} - - {#l_allocate} - CALL allocate_{name} - {/l_allocate} - - CALL bld_{name} - - {?do_task} - !$OMP END TASK - {/do_task} - - {name}_is_built = .TRUE. - - {?do_openmp} - CALL irp_lock_{name}(.FALSE.) - {/do_openmp} - - {?do_debug} - CALL irp_leave(irp_here) - {/do_debug} - -END SUBROUTINE provide_{name} -''' - from util import mangled + from util import mangled + import util name = self.name - var = self.d_entity[name] - l_module = [ {'name':x} for x in build_use([self.name] + self.to_provide, self.d_entity)] - l_allocate = [ {'name':n, 'subroutine':self.build_alloc(n)} for n in self.l_name if self.d_entity[n].dim] - l_children = [ {'name':x} for x in mangled(self.to_provide, self.d_entity) ] + l_module = [x for x in build_use([self.name] + self.to_provide, self.d_entity,use=False)] + l_children = [x for x in mangled(self.to_provide, self.d_entity)] - in_ = ['depend(in: %s)' % n for n in self.to_provide] - out_ = ['depend(out: %s)' % n for n in self.l_name] - do_task = [ {'depend':' '.join(in_ + out_) } ] if command_line.do_Task else [] + l = ashes_env.render('provider.f90', { + 'name': name, + 'l_module': l_module, + 'l_children_static': l_children, + 'do_debug': command_line.do_debug, + 'do_openmp': command_line.do_openmp, + 'do_task': command_line.do_Task, + 'do_corray': command_line.do_coarray, + 'dim': ','.join(self.dim), + }) + return [i for i in l.split('\n') if i.strip()] - ashes_env = AshesEnv() - ashes_env.register_source('provide',template) + @irpy.lazy_property + def allocater(self): + if not self.is_main: + return [] - l = ashes_env.render('provide', {'name': name, - 'l_module':l_module, - 'l_allocate':l_allocate, - 'l_children':l_children, - 'do_debug':command_line.do_debug, - 'do_openmp':command_line.do_openmp, - 'do_task':do_task}) - return [i for i in l.split('\n') if i.strip()] - - def build_alloc(self,name): - var = self.d_entity[name] - from ashes import AshesEnv - template = (""" + from util import mangled -subroutine allocate_{name} + import util + name = self.name + l_module = [x for x in build_use([self.name] + self.to_provide, self.d_entity,use=False)] + if self.is_protected: + l_module.remove(self.fmodule) - {#l_module} - {name} - {/l_module} - - character*(9+{@size key=name/}),parameter :: irp_here = 'allocate_{name}' - integer :: irp_err - - if ( allocated({name}) .AND.( & - {#l_dim} - ( SIZE({name},{rank}) /= {value} ) {@sep}.OR.{/sep} & - {/l_dim} - )) then + l_dim = [{'name': name, 'rank': i + 1, 'value': dimsize(k)} for i, k in enumerate(self.dim)] - {?do_memory} - print *, irp_here//': Deallocated {name}' - {/do_memory} - deallocate( {name}, stat=irp_err ) + l = ashes_env.render('allocater.f90', { + 'name': name, + 'l_module': l_module, + 'do_debug': command_line.do_debug, + 'do_corray': command_line.do_coarray, + 'dim': ','.join(self.dim), + 'l_dim': l_dim + }) + return [i for i in l.split('\n') if i.strip()] - if (irp_err /= 0) then - print *, irp_here//': Deallocation failed: {name}' - print *,' size: {dim}' - endif - - endif - - if ( .NOT. allocated({name}) ) then - - {?do_memory} - print *, irp_here//': Allocate {name} ({dim})' - {/do_memory} - - {^corray} - allocate({name} ({dim}), stat=irp_err) - {:else} - allocate({name} ({dim}[*]), stat=irp_err) - {/corray} - if (irp_err /= 0) then - print *, irp_here//': Allocation failed: {name}' - print *,' size: {dim}' - endif - - endif - -end subroutine - -""") - - def dimsize(x): - # (str) -> str - '''Compute the number of element in the array''' - try: - b0, b1 = x.split(':') - except ValueError: - return x - - b0_is_digit = b0.replace('-', '').isdigit() - b1_is_digit = b1.replace('-', '').isdigit() - - if b0_is_digit and b1_is_digit: - size = str(int(b1) - int(b0) + 1) - elif b0_is_digit: - size = "(%s) - (%d)" % (b1, int(b0) - 1) - elif b1_is_digit: - size = "(%d) - (%s)" % (int(b1) + 1, b0) - else: - size = "(%s) - (%s) + 1" % (b1, b0) - return size - - l_dim = [{'name':name, 'rank':i+1, 'value':dimsize(k)} for i, k in enumerate(var.dim)] - l_module = [ {'name':x} for x in build_use([var.name] + var.needs, self.d_entity) ] - - ashes_env = AshesEnv() - ashes_env.register_source('hello',template) - return ashes_env.render('hello', {'name': name, - 'dim':','.join(var.dim), - 'corray': command_line.coarray, - 'l_dim': l_dim, - 'l_module':l_module, - 'do_memory':command_line.do_memory}) - ########################################################## @irpy.lazy_property def builder(self): @@ -717,9 +491,12 @@ end subroutine # ~#~#~#~#~# #Next return the first element of the iterator - ps_text = next(text for filename, text in self.cm_t_filename_parsed_text if self.prototype.filename[0].startswith(filename)) - begin = next(i for i, (_, line) in enumerate(ps_text) if isinstance(line, Begin_provider) if line.filename[1] == self.same_as) - end = next(begin + i for i, (_, line) in enumerate(ps_text[begin:]) if isinstance(line, End_provider)) + ps_text = next(text for filename, text in self.cm_t_filename_parsed_text + if self.prototype.filename[0].startswith(filename)) + begin = next(i for i, (_, line) in enumerate(ps_text) + if isinstance(line, Begin_provider) if line.filename[1] == self.same_as) + end = next(begin + i for i, (_, line) in enumerate(ps_text[begin:]) + if isinstance(line, End_provider)) # Now we now that the text is betern ps_text[begin:end] _, line_prototype = ps_text[begin] @@ -736,23 +513,13 @@ end subroutine text.append(([], Simple_line(line_prototype.i, " irp_rdtsc1 = irp_rdtsc()", line_prototype.filename))) - remove = 1 for vars, line in ps_text[begin + 1:end]: - if 'call touch' in line.lower: - text += [([], Simple_line(line.i, '!$OMP TASKGROUP', line.filename))] - remove = -1 - text.append((vars, line)) text += map(lambda x: ([], Simple_line(line.i, x, line.filename)), build_call_provide(vars, self.d_entity)) - if remove == 0: - text += [([], Simple_line(line.i, '!$OMP END TASKGROUP', line.filename))] - - remove +=1 - # ~#~#~#~#~# # Create the subroutine. # ~#~#~#~#~# @@ -763,13 +530,19 @@ end subroutine # Add the use statement result += ["subroutine bld_%s" % (self.name)] - result += build_use([self.name] + self.needs, self.d_entity) + + l_use = build_use([self.name] + self.needs, self.d_entity,use=False) + if self.is_protected: + l_use.remove(self.fmodule) + + result += ['USE %s'%n for n in l_use] import parsed_text # Move the variable to top, and add the text - parsed_text.move_to_top_list(text, [Declaration, Implicit, Use]) + parsed_text.move_to_top_list(text, [Declaration, Implicit, Use]) - result.extend( line.text for _,line in text if not isinstance(line, (Begin_doc, End_doc, Doc, Cont_provider))) + result.extend(line.text for _, line in text + if not isinstance(line, (Begin_doc, End_doc, Doc, Cont_provider))) if command_line.do_profile: result += [ @@ -790,7 +563,7 @@ end subroutine @irpy.lazy_property_mutable def needed_by(self): #Set by parsed_text.build_needs(...) - return [] + return [] @irpy.lazy_property def children(self): @@ -821,5 +594,3 @@ end subroutine error.fail(self.prototype, "Cyclic dependencies:\n%s" % (str(self._parents))) return result - - diff --git a/src/irpy_files.py b/src/irpy_files.py index 90518a9..ef80965 100644 --- a/src/irpy_files.py +++ b/src/irpy_files.py @@ -286,7 +286,7 @@ class Irpy_comm_world(object): # Module data if m.has_irp_module: filename = os.path.join(irpdir, '%s.irp.module.F90' % m.filename) - text = '\n'.join(m.header + m.head) + text = '\n'.join(m.head) lazy_write_file(filename, '%s\n' % text) # Subroutines @@ -312,17 +312,8 @@ class Irpy_comm_world(object): def create_lock(self): from util import lazy_write_file - l = sorted(self.d_entity.keys()) - - out = [] - for v in l: - out += self.d_entity[v].locker - - out += ["subroutine irp_init_locks_%s()" % (irpf90_t.irp_id), " implicit none"] - for v in l: - out += [" call irp_lock_%s(.True.)" % v] - out += [" call irp_lock_%s(.False.)" % v] - out += ["end subroutine", ""] + from util import ashes_env + str_ = ashes_env.render('irp_lock.F90', {'entity':sorted(self.d_entity)}) filename = os.path.join(irpf90_t.irpdir, 'irp_locks.irp.F90') - lazy_write_file(filename, '\n'.join(out)) + lazy_write_file(filename, str_) diff --git a/src/module.py b/src/module.py index e222388..bd6395e 100644 --- a/src/module.py +++ b/src/module.py @@ -74,19 +74,17 @@ class Fmodule(object): @irpy.lazy_property def head(self): '''The module who containt the declaration of the entity''' - body = list(self.use) - body += list(self.dec) - body += [header for var in self.l_entity for header in var.header] + if self.use or self.dec or self.l_entity: - if body: - result = ["module %s" % (self.name)] - result += body - result += ["end module %s" % (self.name)] + d_template = {'name' : self.name, + 'use':list(self.use),'usr_declaration':list(self.dec), + 'irp_declaration':[e.d_header for e in self.l_entity], + 'coarray': command_line.coarray, + 'align': False if command_line.align == 1 else command_line.align} + return [i for i in ashes_env.render('module.f90', d_template).split('\n') if i] else: - result = [] - - return result + return [] @irpy.lazy_property def has_irp_module(self): @@ -106,7 +104,9 @@ class Fmodule(object): result = [] for var in self.l_entity: result += var.provider - result += var.builder + if not var.is_protected: + result += var.builder + result += var.allocater if var.is_read: result += var.reader if var.is_written: @@ -213,14 +213,14 @@ class Fmodule(object): Because user can define F90 Type, we need to keep the correct order. Warning: - If we uniquify that can cause a problem with the type in guess. - ```type toto - integer :: n - end type toto - integer :: n + If we uniquify that can cause a problem. + ```TYPE toto + INTEGER :: n + END TYPE toto + INTEGER :: n ``` Fix: - We need to support Type keyword. + We need to support TYPE keyword. ''' diff --git a/src/preprocessed_text.py b/src/preprocessed_text.py index 2c5cfaf..79a0092 100644 --- a/src/preprocessed_text.py +++ b/src/preprocessed_text.py @@ -57,8 +57,10 @@ simple_dict = { "subst": Subst, "end_doc": End_doc, "begin_provider": Begin_provider, + "begin_provider_immu": Begin_provider, "&begin_provider": Cont_provider, "end_provider": End_provider, + "end_provider_immu": End_provider, "assert": Assert, "touch": Touch, "soft_touch": SoftTouch, @@ -674,8 +676,10 @@ def irp_simple_statements(text): if command_line.do_profile: temp += [Simple_line(0, "call irp_init_timer()", line.filename)] - if command_line.do_openmp: - temp += [Simple_line(0, " call irp_init_locks_%s()" % (irp_id), line.filename)] +# Need to choose between lazy lock or are big full initialization +# if command_line.do_openmp: +# temp += [Simple_line(0, " call irp_init_locks_%s()" % (irp_id), line.filename)] + temp += [Call(0, " call %s" % (program_name), line.filename)] if command_line.do_profile: temp += [Simple_line(0, "call irp_print_timer()", line.filename)] diff --git a/src/templates/allocater.f90 b/src/templates/allocater.f90 new file mode 100644 index 0000000..5f213ab --- /dev/null +++ b/src/templates/allocater.f90 @@ -0,0 +1,47 @@ +{?dim} +SUBROUTINE allocate_{name} + + {#l_module} + USE {.} + {/l_module} + + IMPLICIT NONE + + CHARACTER*(9+{@size key=name/}),PARAMETER :: irp_here = 'allocate_{name}' + INTEGER :: irp_err + + IF ( ALLOCATED({name}) .AND.( & + {#l_dim} + ( SIZE({name},{rank}) /= {value} ) {@sep}.OR.{/sep} & + {/l_dim})) THEN + + {?do_memory} PRINT*, irp_here//': Deallocated {name}' {/do_memory} + DEALLOCATE({name},STAT=irp_err) + + IF (irp_err /= 0) THEN + PRINT*, irp_here//': Deallocation failed: {name}' + PRINT*,' size: {dim}' + ENDIF + + GO TO 666 + ELSE IF (.NOT.ALLOCATED({name})) THEN + GO TO 666 + ELSE + RETURN + ENDIF + + 666 CONTINUE + {?do_memory} PRINT*, irp_here//': Allocate {name} ({dim})'{/do_memory} + + {^do_corray} + ALLOCATE({name} ({dim}), STAT=irp_err) + {:else} + ALLOCATE({name} ({dim}[*]), STAT=irp_err) + {/do_corray} + + IF (irp_err /= 0) then + PRINT*, irp_here//': Allocation failed: {name}' + PRINT*,' size: {dim}' + ENDIF +END SUBROUTINE allocate_{name} +{/dim} diff --git a/src/templates/finalize.f90 b/src/templates/finalize.f90 new file mode 100644 index 0000000..8ead9c4 --- /dev/null +++ b/src/templates/finalize.f90 @@ -0,0 +1,13 @@ +SUBROUTINE irp_finalize_{id} + {#use} + USE {.} + {/use} + + IMPLICIT NONE + {#entity_array} + IF (ALLOCATED({name})) THEN + {name_root}_is_built = .FALSE. +! DEALLOCATE({name}) + ENDIF + {/entity_array} +END SUBROUTINE irp_finalize_{id} diff --git a/src/templates/irp_lock.f90 b/src/templates/irp_lock.f90 new file mode 100644 index 0000000..13c5cf6 --- /dev/null +++ b/src/templates/irp_lock.f90 @@ -0,0 +1,31 @@ +{#entity} +SUBROUTINE irp_lock_{.}(set) + + USE omp_lib + IMPLICIT NONE + LOGICAL, INTENT(in) :: set + INTEGER(KIND=omp_lock_kind),SAVE :: {.}_lock + INTEGER, SAVE :: ifirst = 0 + + {?do_debug} + CHARACTER*(9+{@size key={.}/}),PARAMETER :: irp_here = 'irp_lock_{name}' + {/do_debug} + + {?do_debug} CALL irp_enter(irp_here) {/do_debug} + + IF (ifirst == 0) then + ifirst = 1 + CALL omp_init_lock({.}_lock) + ENDIF + + IF (set) THEN + CALL omp_set_lock({.}_lock) + ELSE + CALL omp_unset_lock({.}_lock) + ENDIF + + {?do_debug} CALL irp_leach(irp_here) {/do_debug} + +END SUBROUTINE irp_lock_{.} +{/entity} + diff --git a/src/templates/module.f90 b/src/templates/module.f90 new file mode 100644 index 0000000..77ac928 --- /dev/null +++ b/src/templates/module.f90 @@ -0,0 +1,40 @@ +! -*- F90 -*- +! +!-----------------------------------------------! +! This file was generated with the irpf90 tool. ! +! ! +! DO NOT MODIFY IT BY HAND ! +!-----------------------------------------------! + + +MODULE {name} + +{#use} + USE {.} +{/use} + +{#usr_declaration} + {.} +{/usr_declaration} + +{#irp_declaration} + + {^dim} + {type} {?protected}, PROTECTED {/protected} :: {name} {?coarray} [*] {/coarray} + {:else} + + {?align} !DIR$ ATTRIBUTES ALIGN: {align} :: {name} {/align} + {type} {?protected}, PROTECTED {/protected} :: {name} {dim} {?coarray} [:] {/coarray} + {/dim} + + {?main} + LOGICAL :: {name}_is_built = .FALSE. + {/main} +{/irp_declaration} + + CONTAINS + {#irp_declaration} +{protected|s} + {/irp_declaration} + +END MODULE {name} diff --git a/src/templates/provider.f90 b/src/templates/provider.f90 new file mode 100644 index 0000000..54db996 --- /dev/null +++ b/src/templates/provider.f90 @@ -0,0 +1,43 @@ +{?inline}!DEC$ ATTRIBUTES FORCEINLINE :: provide_{name}{/inline} +SUBROUTINE provide_{name} + + {#l_module} + USE {.} + {/l_module} + + IMPLICIT NONE + + {?do_debug} + CHARACTER*(8+{@size key=name/}),PARAMETER :: irp_here = 'provide_{name}' + {/do_debug} + + {?do_debug} CALL irp_enter(irp_here) {/do_debug} + + {?do_openmp} + CALL irp_lock_{name}(.TRUE.) + IF (.NOT.{name}_is_built) THEN + {/do_openmp} + + {#l_children_static} + {@first} {?do_task}!$OMP TASKGROUP{/do_task} {/first} + {?do_openmp}!$OMP flush({.}_is_built){/do_openmp} + IF (.NOT.{.}_is_built) THEN + {?do_task}!$OMP TASK{/do_task} + CALL provide_{.} + {?do_task}!$OMP END TASK{/do_task} + ENDIF + {@last} {?do_task}!$OMP END TASKGROUP{/do_task} {/last} + {/l_children_static} + + {?dim} CALL allocate_{name} {/dim} + + CALL bld_{name} + + {?do_debug} CALL irp_enter(irp_here) {/do_debug} + + {?do_openmp} + ENDIF + CALL irp_lock_{name}(.FALSE.) + {/do_openmp} + +END SUBROUTINE provide_{name} diff --git a/src/templates/touch.f90 b/src/templates/touch.f90 new file mode 100644 index 0000000..ef49250 --- /dev/null +++ b/src/templates/touch.f90 @@ -0,0 +1,26 @@ +{#entity} + +SUBROUTINE touch_{name} + + {#l_module} + USE {.} + {/l_module} + + IMPLICIT NONE + {?do_debug} + CHARACTER*(6+{@size key=name/}),PARAMETER :: irp_here = 'touch_{name}' + {/do_debug} + + {?do_debug} CALL irp_enter(irp_here) {/do_debug} + + {#l_ancestor} + {.}_is_built = .FALSE. + {/l_ancestor} + + {name}_is_built = .TRUE. + + {?do_debug} CALL irp_leave(irp_here) {/do_debug} + +END SUBROUTINE touch_{name} + +{/entity} diff --git a/src/touches.py b/src/touches.py index c3a6382..6494a04 100644 --- a/src/touches.py +++ b/src/touches.py @@ -26,39 +26,28 @@ from irpf90_t import irp_id,irpdir import os -from util import lazy_write_file +from command_line import command_line def create(modules,variables): # (Dict[str,Module]. Dict[str, Variable]) -> None '''Create the fortran90 finalize subroutine and the touched one''' - - finalize = "subroutine irp_finalize_%s\n"%(irp_id) - for m in filter(lambda x: not modules[x].is_main and modules[x].has_irp_module, modules): - finalize += " use %s\n"%(modules[m].name) - main_modules_name =[ m.name for m in modules.values() if m.is_main] - - out = [] - for v,var in variables.iteritems(): - if var.fmodule not in main_modules_name: - out += var.toucher - if var.dim: - finalize += " if (allocated(%s)) then\n"%v - finalize += " %s_is_built = .False.\n"%var.same_as - finalize += " deallocate(%s)\n"%v - finalize += " endif\n" + d_template_finalize = {'id':irp_id, + 'use':[m.name for m in modules.values() if not m.is_main and m.has_irp_module], + 'entity_array': + [{'name':e.name,'name_root':e.same_as} for e in variables.values() if e.fmodule not in main_modules_name and e.dim]} + - finalize += "end\n" - - if out: - out = map(lambda x: "%s\n"%(x),out) - - out += finalize + d_template_touch = {'do_debug': command_line.do_debug, + 'entity':[e.d_touche_template for e in variables.values() if e.fmodule not in main_modules_name]} + + import util + str_out = util.ashes_env.render('touch.f90', d_template_touch) + util.ashes_env.render('finalize.f90', d_template_finalize) filename=os.path.join(irpdir,'irp_touches.irp.F90') - lazy_write_file(filename,''.join(out)) + util.lazy_write_file(filename,'%s\n'% util.remove_empy_lines(str_out)) if __name__ == '__main__': create() diff --git a/src/util.py b/src/util.py index f562d0c..44c3fab 100644 --- a/src/util.py +++ b/src/util.py @@ -42,6 +42,17 @@ logging.basicConfig(level=logging.INFO) logger = logging.getLogger('Irpf90') logger.setLevel(30) + +# ~#~#~#~#~# +# A S H E S _ T E M P L A T E S +# ~#~#~#~#~# +from ashes import AshesEnv +import os +ashes_env = AshesEnv([os.path.join(os.path.dirname(__file__),'templates')]) + +def remove_empy_lines(text): + return os.linesep.join([s for s in text.splitlines() if s.strip()]) + # ~#~#~#~#~# # / / _ R E L A T E D # ~#~#~#~#~# @@ -277,6 +288,28 @@ def flatten(l_2d): # ~#~#~#~#~# # I R P _ R E L A T E D # ~#~#~#~#~# +def dimsize(x): + # (str) -> str + '''Compute the number of element in the array''' + try: + b0, b1 = x.split(':') + except ValueError: + return x + + b0_is_digit = b0.replace('-', '').isdigit() + b1_is_digit = b1.replace('-', '').isdigit() + + if b0_is_digit and b1_is_digit: + size = str(int(b1) - int(b0) + 1) + elif b0_is_digit: + size = "(%s) - (%d)" % (b1, int(b0) - 1) + elif b1_is_digit: + size = "(%d) - (%s)" % (int(b1) + 1, b0) + else: + size = "(%s) - (%s) + 1" % (b1, b0) + return size + + def build_dim(l_dim, colons=False): # (List[str],bool) -> str '''Contruct a valid fortran90 array dimension code from a list dimension @@ -298,10 +331,16 @@ def mangled(l_ent, d_ent): '''Create a uniq list of providier (merge the multione) ''' return OrderedUniqueList(d_ent[name].same_as for name in l_ent) -def build_use(l_ent, d_ent): +def build_use(l_ent, d_ent,use=True): # (List, Dict[str,Entity]) -> list '''Contruct the fortran90 'use' statement for the list of entity''' - return OrderedUniqueList(" use %s" % d_ent[x].fmodule for x in l_ent) + + l_name = OrderedUniqueList(d_ent[x].fmodule for x in l_ent) + if not use: + return l_name + else: + return [" use %s" % n for n in l_name] + def build_call_provide(l_ent, d_ent): # (List, Dict[str,Entity]) -> list