10
0
mirror of https://gitlab.com/scemama/irpf90.git synced 2024-12-22 12:23:32 +01:00

Add template. Repare OMP_Lock

This commit is contained in:
Thomas Applencourt 2017-02-16 18:10:21 -06:00
parent 982d771c61
commit 974775a9a5
13 changed files with 423 additions and 421 deletions

View File

@ -271,13 +271,21 @@ def create_build_remaining(f,ninja):
if extension.lower() in ['f', 'f90']: if extension.lower() in ['f', 'f90']:
result = ["build {target_o}: compile_fortran_{irp_id} {target_i}"] 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']: elif extension.lower() in ['c']:
result = ["build {target_o}: compile_c_{irp_id} {target_i}"] result = ["build {target_o}: compile_c_{irp_id} {target_i}"]
elif extension.lower() in ['cxx', 'cpp']: elif extension.lower() in ['cxx', 'cpp']:
result = ["build {target_o}: compile_cxx_{irp_id} {target_i}"] result = ["build {target_o}: compile_cxx_{irp_id} {target_i}"]
result += [" short_in = {short_target_i}", " short_out = {short_target_o}", ""] 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): def create_makefile(d_flags,d_var,irpf90_flags,ninja=True):

View File

@ -42,8 +42,8 @@ class Entity(object):
############################################################ ############################################################
def __init__(self, text, label, name=None, comm_world=None): def __init__(self, text, label, name=None, comm_world=None):
# (list[str], str, int, Irpy_comm_world) # (list[str], str, int, Irpy_comm_world)
'''Instantiate the object. '''Instantiate the object.
Args: Args:
text: List of lines between BEGIN_PROVIDER and END_PROVIDER included text: List of lines between BEGIN_PROVIDER and END_PROVIDER included
@ -59,18 +59,17 @@ class Entity(object):
self.label = label self.label = label
self.text = text 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.name = name if name else self.same_as
self.comm_world = comm_world self.comm_world = comm_world
# ~ # ~ # ~ # ~ # ~ # ~
# G l o b a l P r o p e r t y # G l o b a l P r o p e r t y
# ~ # ~ # ~ # ~ # ~ # ~
@irpy.lazy_property @irpy.lazy_property
def d_entity(self): def d_entity(self):
# () -> Dict[str,Entity] # () -> Dict[str,Entity]
'''Create an alias to the global dictionary of Entity. '''Create an alias to the global dictionary of Entity.
Note: Be aware of the possiblity of Cyclic Dependency. Note: Be aware of the possiblity of Cyclic Dependency.
@ -79,7 +78,7 @@ class Entity(object):
@irpy.lazy_property @irpy.lazy_property
def cm_t_filename_parsed_text(self): 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 '''Create an alias to the global tuple for parsed text
Note: self.comm_world.t_filename_parsed_text need d_entity. Note: self.comm_world.t_filename_parsed_text need d_entity.
@ -89,22 +88,21 @@ class Entity(object):
@irpy.lazy_property @irpy.lazy_property
def d_type_lines(self): def d_type_lines(self):
# () -> Dict[Line, Tuple[int,Line] ] # () -> Dict[Line, Tuple[int,Line] ]
'''Contruct a mapping table between the type of the line and the possition''' '''Contruct a mapping table between the type of the line and the possition'''
from collections import defaultdict from collections import defaultdict
d = defaultdict(list) d = defaultdict(list)
for i, line in enumerate(self.text): for i, line in enumerate(self.text):
d[type(line)] += [(i, line)] d[type(line)] += [(i, line)]
return d 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 # 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 @irpy.lazy_property
def is_main(self): def is_main(self):
# () -> bool # () -> bool
'''Check if this Entity is the main one '''Check if this Entity is the main one
Exemple: Exemple:
BEGIN_PROVIDER [pi, double precision] & BEGIN_PROVIDER [pi, double precision] &
@ -114,11 +112,10 @@ class Entity(object):
''' '''
return self.name == self.same_as return self.name == self.same_as
@irpy.lazy_property @irpy.lazy_property
def prototype(self): def prototype(self):
# () -> Line # () -> Line
'''Find the declaration statement associated with the name of the provider '''Find the declaration statement associated with the name of the provider
Exemple: Exemple:
BEGIN_PROVIDER [pi, double precision] & BEGIN_PROVIDER [pi, double precision] &
@ -127,33 +124,33 @@ class Entity(object):
if self.name == e, will return BEGIN_PROVIDER [e, double preision] if self.name == e, will return BEGIN_PROVIDER [e, double preision]
''' '''
d = self.d_type_lines d = self.d_type_lines
return next(line for _,line in d[Begin_provider]+d[Cont_provider] if line.filename[1] == self.name) return next(line for _, line in d[Begin_provider] + d[Cont_provider]
if line.filename[1] == self.name)
@irpy.lazy_property @irpy.lazy_property
def l_name(self): def l_name(self):
# () -> List[str] # () -> List[str]
d = self.d_type_lines d = self.d_type_lines
return [line.filename[1] for _,line in d[Begin_provider]+d[Cont_provider] ] return [line.filename[1] for _, line in d[Begin_provider] + d[Cont_provider]]
@irpy.lazy_property @irpy.lazy_property
def l_others_name(self): def l_others_name(self):
# () -> List[str] # () -> List[str]
'''Extract the other entity-name defined''' '''Extract the other entity-name defined'''
return [name for name in self.l_name if not name == self.name] return [name for name in self.l_name if not name == self.name]
@irpy.lazy_property @irpy.lazy_property
def doc(self): def doc(self):
# () -> List[str] # () -> List[str]
doc = [line.text.lstrip()[1:] for _,line in self.d_type_lines[Doc]] doc = [line.text.lstrip()[1:] for _, line in self.d_type_lines[Doc]]
if not doc: if not doc:
logger.warning("Entity '%s' is not documented" % (self.name)) logger.warning("Entity '%s' is not documented" % (self.name))
return doc return doc
@irpy.lazy_property @irpy.lazy_property
def documented(self): def documented(self):
#() -> bool #() -> bool
return bool(self.doc) return bool(self.doc)
# ~ # ~ # ~ # ~ # ~ # ~
@ -162,8 +159,8 @@ class Entity(object):
@irpy.lazy_property_mutable @irpy.lazy_property_mutable
def is_written(self): def is_written(self):
#() -> bool #() -> bool
'''Check if it will be written on disk''' '''Check if it will be written on disk'''
return any(self.d_entity[i].is_written for i in self.parents) return any(self.d_entity[i].is_written for i in self.parents)
@irpy.lazy_property @irpy.lazy_property
@ -171,7 +168,7 @@ class Entity(object):
if not self.is_main: if not self.is_main:
result = [] result = []
else: else:
from util import mangled from util import mangled
name = self.name name = self.name
result = [ \ result = [ \
"subroutine writer_%s(irp_num)"%(name), "subroutine writer_%s(irp_num)"%(name),
@ -210,7 +207,7 @@ class Entity(object):
@irpy.lazy_property_mutable @irpy.lazy_property_mutable
def is_read(self): 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) return any(self.d_entity[i].is_read for i in self.parents)
@irpy.lazy_property @irpy.lazy_property
@ -218,7 +215,7 @@ class Entity(object):
if not self.is_main: if not self.is_main:
result = [] result = []
else: else:
from util import mangled from util import mangled
name = self.name name = self.name
result = [ \ result = [ \
"subroutine reader_%s(irp_num)"%(name), "subroutine reader_%s(irp_num)"%(name),
@ -255,7 +252,7 @@ class Entity(object):
@irpy.lazy_property @irpy.lazy_property
def is_source_touch(self): 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 @irpy.lazy_property_mutable
def is_self_touched(self): def is_self_touched(self):
@ -267,8 +264,8 @@ class Entity(object):
'''If any of the children is touched, the entity is touched''' '''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): if self.is_self_touched or any(self.d_entity[i].is_touched for i in self.children):
return True return True
return False return False
# ~ # ~ # ~ # ~ # ~ # ~
# INCLUDE, USE, CALL # INCLUDE, USE, CALL
@ -276,23 +273,23 @@ class Entity(object):
@irpy.lazy_property @irpy.lazy_property
def includes(self): def includes(self):
# () -> str # () -> str
'''Extract the name of include who need be to be include in this Entity''' '''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]] return [line.filename for _, line in self.d_type_lines[Include]]
@irpy.lazy_property @irpy.lazy_property
def uses(self): def uses(self):
'''Extract the name of module who are used in this Entity''' '''Extract the name of module who are used in this Entity'''
return [line.filename for _,line in self.d_type_lines[Use]] return [line.filename for _, line in self.d_type_lines[Use]]
@irpy.lazy_property @irpy.lazy_property
def calls(self): 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): def extract_name(line):
return line.text.split('(', 1)[0].split()[1].lower() 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 # Array Dimension
@ -300,8 +297,8 @@ class Entity(object):
@irpy.lazy_property @irpy.lazy_property
def dim(self): def dim(self):
# () -> List[str] # () -> List[str]
'''Extract the dimension of the needed array in a form of list of variable name '''Extract the dimension of the needed array in a form of list of variable name
Exemple: Exemple:
BEGIN_PROVIDER [real, ao_num ] BEGIN_PROVIDER [real, ao_num ]
@ -324,7 +321,6 @@ class Entity(object):
else: else:
return map(str.strip, x[1:-1].split(',')) return map(str.strip, x[1:-1].split(','))
@irpy.lazy_property @irpy.lazy_property
def allocate(self): def allocate(self):
# () -> List[Str] # () -> List[Str]
@ -338,62 +334,54 @@ class Entity(object):
# ~ # ~ # ~ # ~ # ~ # ~
# D e c l a r a t i o n # 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 @irpy.lazy_property
def type(self): def type(self):
# () -> str # () -> str
'''Compute the fortran type code of the entity''' '''Compute the fortran type code of the entity'''
type_ = self.prototype.text.split(',')[0].split('[')[1].strip() type_ = self.prototype.text.split(',')[0].split('[')[1].strip()
if not type_: if not type_:
logger.error( "Error in definition of %s." % (self.name)) logger.error("Error in definition of %s." % (self.name))
sys.exit(1) sys.exit(1)
if self.dim: if self.dim:
return "%s, allocatable" % (type_) return "%s, allocatable" % (type_)
else: else:
return type_ return type_
@irpy.lazy_property @irpy.lazy_property
def header(self): def d_header(self):
# () -> List[str] # () -> List[str]
'''Compute all the code needed to inistanticant the entity''' '''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
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 @irpy.lazy_property
def fmodule(self): def fmodule(self):
# () -> str # () -> 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] name = self.prototype.filename[0].replace('/', '__').split('.irp.f')[0]
return '%s_mod' % name return '%s_mod' % name
############################################################ ############################################################
@irpy.lazy_property @irpy.lazy_property
def regexp(self): def regexp(self):
# () -> Regex # () -> Regex
'''Compile a regex targeted to 'search' the name of this entity''' '''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 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 @irpy.lazy_property
def toucher(self): def d_touche_template(self):
# () -> List[str] # () -> List[str]
'''Fabric the f90 routine who handle the cache invalidation''' '''Fabric the f90 routine who handle the cache invalidation'''
# Only one by EntityColleciton # Only one by EntityColleciton
if not self.is_main: if not self.is_main:
return [] return {}
template = ''' from util import mangled
SUBROUTINE touch_{name}
{#l_module} return {
{name} 'name': self.name,
{/l_module} '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)]}
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
########################################################## ##########################################################
@irpy.lazy_property @irpy.lazy_property
def free(self): def free(self):
# () -> List[ str ] # () -> List[ str ]
'''Compute an part of a subroutine used to free a variable''' '''Compute an part of a subroutine used to free a variable'''
name = self.name name = self.name
result = ["!", result = ["!", "! >>> FREE %s" % (name), " %s_is_built = .False." % (self.same_as)]
"! >>> FREE %s" % (name),
" %s_is_built = .False." % (self.same_as)]
if self.dim: if self.dim:
result += [ result += [" if (allocated(%s)) then" % (name), " deallocate (%s)" % (name)]
" if (allocated(%s)) then"%(name),
" deallocate (%s)"%(name)]
if command_line.do_memory: if command_line.do_memory:
result += " print *, 'Deallocating %s'"%(name) result += " print *, 'Deallocating %s'" % (name)
result += [" endif"] result += [" endif"]
@ -522,190 +427,59 @@ END SUBROUTINE touch_{name}
########################################################## ##########################################################
@irpy.lazy_property @irpy.lazy_property
def provider(self): def provider(self):
# () -> List[str] # () -> List[str]
'''Create the fortran90 code for the EntityCollection''' '''Create the fortran90 code for the EntityCollection'''
if not self.is_main: if not self.is_main:
return [] return []
from ashes import AshesEnv from util import mangled
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
import util
name = self.name name = self.name
var = self.d_entity[name] l_module = [x for x in build_use([self.name] + self.to_provide, self.d_entity,use=False)]
l_module = [ {'name':x} for x in build_use([self.name] + self.to_provide, self.d_entity)] l_children = [x for x in mangled(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) ]
in_ = ['depend(in: %s)' % n for n in self.to_provide] l = ashes_env.render('provider.f90', {
out_ = ['depend(out: %s)' % n for n in self.l_name] 'name': name,
do_task = [ {'depend':' '.join(in_ + out_) } ] if command_line.do_Task else [] '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() @irpy.lazy_property
ashes_env.register_source('provide',template) def allocater(self):
if not self.is_main:
return []
l = ashes_env.render('provide', {'name': name, from util import mangled
'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 = ("""
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}
l_dim = [{'name': name, 'rank': i + 1, 'value': dimsize(k)} for i, k in enumerate(self.dim)]
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 ) 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 @irpy.lazy_property
def builder(self): def builder(self):
@ -717,9 +491,12 @@ end subroutine
# ~#~#~#~#~# # ~#~#~#~#~#
#Next return the first element of the iterator #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)) ps_text = next(text for filename, text in self.cm_t_filename_parsed_text
begin = next(i for i, (_, line) in enumerate(ps_text) if isinstance(line, Begin_provider) if line.filename[1] == self.same_as) if self.prototype.filename[0].startswith(filename))
end = next(begin + i for i, (_, line) in enumerate(ps_text[begin:]) if isinstance(line, End_provider)) 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] # Now we now that the text is betern ps_text[begin:end]
_, line_prototype = ps_text[begin] _, line_prototype = ps_text[begin]
@ -736,23 +513,13 @@ end subroutine
text.append(([], Simple_line(line_prototype.i, " irp_rdtsc1 = irp_rdtsc()", text.append(([], Simple_line(line_prototype.i, " irp_rdtsc1 = irp_rdtsc()",
line_prototype.filename))) line_prototype.filename)))
remove = 1
for vars, line in ps_text[begin + 1:end]: 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.append((vars, line))
text += map(lambda x: ([], Simple_line(line.i, x, line.filename)), text += map(lambda x: ([], Simple_line(line.i, x, line.filename)),
build_call_provide(vars, self.d_entity)) 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. # Create the subroutine.
# ~#~#~#~#~# # ~#~#~#~#~#
@ -763,13 +530,19 @@ end subroutine
# Add the use statement # Add the use statement
result += ["subroutine bld_%s" % (self.name)] 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 import parsed_text
# Move the variable to top, and add the 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: if command_line.do_profile:
result += [ result += [
@ -790,7 +563,7 @@ end subroutine
@irpy.lazy_property_mutable @irpy.lazy_property_mutable
def needed_by(self): def needed_by(self):
#Set by parsed_text.build_needs(...) #Set by parsed_text.build_needs(...)
return [] return []
@irpy.lazy_property @irpy.lazy_property
def children(self): def children(self):
@ -821,5 +594,3 @@ end subroutine
error.fail(self.prototype, "Cyclic dependencies:\n%s" % (str(self._parents))) error.fail(self.prototype, "Cyclic dependencies:\n%s" % (str(self._parents)))
return result return result

View File

@ -286,7 +286,7 @@ class Irpy_comm_world(object):
# Module data # Module data
if m.has_irp_module: if m.has_irp_module:
filename = os.path.join(irpdir, '%s.irp.module.F90' % m.filename) 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) lazy_write_file(filename, '%s\n' % text)
# Subroutines # Subroutines
@ -312,17 +312,8 @@ class Irpy_comm_world(object):
def create_lock(self): def create_lock(self):
from util import lazy_write_file from util import lazy_write_file
l = sorted(self.d_entity.keys()) from util import ashes_env
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", ""]
str_ = ashes_env.render('irp_lock.F90', {'entity':sorted(self.d_entity)})
filename = os.path.join(irpf90_t.irpdir, 'irp_locks.irp.F90') filename = os.path.join(irpf90_t.irpdir, 'irp_locks.irp.F90')
lazy_write_file(filename, '\n'.join(out)) lazy_write_file(filename, str_)

View File

@ -74,19 +74,17 @@ class Fmodule(object):
@irpy.lazy_property @irpy.lazy_property
def head(self): def head(self):
'''The module who containt the declaration of the entity''' '''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: d_template = {'name' : self.name,
result = ["module %s" % (self.name)] 'use':list(self.use),'usr_declaration':list(self.dec),
result += body 'irp_declaration':[e.d_header for e in self.l_entity],
result += ["end module %s" % (self.name)] '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: else:
result = [] return []
return result
@irpy.lazy_property @irpy.lazy_property
def has_irp_module(self): def has_irp_module(self):
@ -106,7 +104,9 @@ class Fmodule(object):
result = [] result = []
for var in self.l_entity: for var in self.l_entity:
result += var.provider result += var.provider
result += var.builder if not var.is_protected:
result += var.builder
result += var.allocater
if var.is_read: if var.is_read:
result += var.reader result += var.reader
if var.is_written: if var.is_written:
@ -213,14 +213,14 @@ class Fmodule(object):
Because user can define F90 Type, we need to keep the correct order. Because user can define F90 Type, we need to keep the correct order.
Warning: Warning:
If we uniquify that can cause a problem with the type in guess. If we uniquify that can cause a problem.
```type toto ```TYPE toto
integer :: n INTEGER :: n
end type toto END TYPE toto
integer :: n INTEGER :: n
``` ```
Fix: Fix:
We need to support Type keyword. We need to support TYPE keyword.
''' '''

View File

@ -57,8 +57,10 @@ simple_dict = {
"subst": Subst, "subst": Subst,
"end_doc": End_doc, "end_doc": End_doc,
"begin_provider": Begin_provider, "begin_provider": Begin_provider,
"begin_provider_immu": Begin_provider,
"&begin_provider": Cont_provider, "&begin_provider": Cont_provider,
"end_provider": End_provider, "end_provider": End_provider,
"end_provider_immu": End_provider,
"assert": Assert, "assert": Assert,
"touch": Touch, "touch": Touch,
"soft_touch": SoftTouch, "soft_touch": SoftTouch,
@ -674,8 +676,10 @@ def irp_simple_statements(text):
if command_line.do_profile: if command_line.do_profile:
temp += [Simple_line(0, "call irp_init_timer()", line.filename)] temp += [Simple_line(0, "call irp_init_timer()", line.filename)]
if command_line.do_openmp: # Need to choose between lazy lock or are big full initialization
temp += [Simple_line(0, " call irp_init_locks_%s()" % (irp_id), line.filename)] # 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)] temp += [Call(0, " call %s" % (program_name), line.filename)]
if command_line.do_profile: if command_line.do_profile:
temp += [Simple_line(0, "call irp_print_timer()", line.filename)] temp += [Simple_line(0, "call irp_print_timer()", line.filename)]

View File

@ -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}

View File

@ -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}

View File

@ -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}

40
src/templates/module.f90 Normal file
View File

@ -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}

View File

@ -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}

26
src/templates/touch.f90 Normal file
View File

@ -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}

View File

@ -26,39 +26,28 @@
from irpf90_t import irp_id,irpdir from irpf90_t import irp_id,irpdir
import os import os
from util import lazy_write_file from command_line import command_line
def create(modules,variables): def create(modules,variables):
# (Dict[str,Module]. Dict[str, Variable]) -> None # (Dict[str,Module]. Dict[str, Variable]) -> None
'''Create the fortran90 finalize subroutine and the touched one''' '''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] 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: d_template_finalize = {'id':irp_id,
out += var.toucher 'use':[m.name for m in modules.values() if not m.is_main and m.has_irp_module],
if var.dim: 'entity_array':
finalize += " if (allocated(%s)) then\n"%v [{'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 += " %s_is_built = .False.\n"%var.same_as
finalize += " deallocate(%s)\n"%v
finalize += " endif\n"
finalize += "end\n" 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]}
if out:
out = map(lambda x: "%s\n"%(x),out) import util
str_out = util.ashes_env.render('touch.f90', d_template_touch) + util.ashes_env.render('finalize.f90', d_template_finalize)
out += finalize
filename=os.path.join(irpdir,'irp_touches.irp.F90') 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__': if __name__ == '__main__':
create() create()

View File

@ -42,6 +42,17 @@ logging.basicConfig(level=logging.INFO)
logger = logging.getLogger('Irpf90') logger = logging.getLogger('Irpf90')
logger.setLevel(30) 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 # / / _ 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 # 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): def build_dim(l_dim, colons=False):
# (List[str],bool) -> str # (List[str],bool) -> str
'''Contruct a valid fortran90 array dimension code from a list dimension '''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) ''' '''Create a uniq list of providier (merge the multione) '''
return OrderedUniqueList(d_ent[name].same_as for name in l_ent) 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 # (List, Dict[str,Entity]) -> list
'''Contruct the fortran90 'use' statement for the list of entity''' '''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): def build_call_provide(l_ent, d_ent):
# (List, Dict[str,Entity]) -> list # (List, Dict[str,Entity]) -> list