24 Defines a decorator to trace all function calling with arguments and results
25 and count number of calls and time spent
28 def wrapper(*args, **kwargs):
30 logger = logging.getLogger()
31 if logger.isEnabledFor(logging.DEBUG):
32 callstr = func.__name__ + \
33 '(' +
', '.join([str(a)
for a
in args] +
34 [k +
'=' + str(v)
for (k, v)
in kwargs.items()]) +
')'
35 logging.debug(
'%s --> ...', callstr)
40 if logger.isEnabledFor(logging.INFO):
46 result = func(*args, **kwargs)
51 if func.__name__
not in debugStats:
52 debugStats[func.__name__] = dict(nb=0, totalTime=0)
53 debugStats[func.__name__][
'nb'] += 1
54 duration = time.time() - t0
55 debugStats[func.__name__][
'totalTime'] += duration
56 debugStats[func.__name__][
'min'] = \
57 min(duration, debugStats[func.__name__].get(
'min', duration))
58 debugStats[func.__name__][
'max'] = \
59 max(duration, debugStats[func.__name__].get(
'max', duration))
62 if callstr
is not None:
64 logging.debug(
'%s --> %s', callstr, str(result))
72 Defines a decorator that prevent this method to be executed in parallel on several files
75 def wrapper(self, *args, **kwargs):
76 if self.NO_PARALLEL_LOCK
is not None:
78 with self.NO_PARALLEL_LOCK:
84 if self.SHARED_TREE
is not None:
85 self.tree.copyFromOtherTree(self.SHARED_TREE)
86 result = func(self, *args, **kwargs)
87 if self.SHARED_TREE
is not None:
88 self.tree.copyToOtherTree(self.SHARED_TREE)
91 return func(self, *args, **kwargs)
109 Print statistics on methods and function usage
111 logger = logging.getLogger()
112 if logger.isEnabledFor(logging.INFO):
113 def _print(name, nb, vmin, vmax, mean):
114 print(
'| ' + name.ljust(30) +
'| ' + str(nb).ljust(14) +
'| ' +
115 str(vmin).ljust(23) +
'| ' + str(vmax).ljust(23) +
'| ' +
116 str(mean).ljust(23) +
'|')
117 _print(
'Name of the function',
'# of calls',
'Min (s)',
'Max (s)',
'Total (s)')
118 for funcName, values
in debugStats.items():
119 _print(funcName, values[
'nb'], values[
'min'], values[
'max'], values[
'totalTime'])
131def fortran2xml(fortranSource, parser='fxtran', parserOptions=None, wrapH=False):
133 :param fortranSource: a string containing a fortran source code
135 :param parser: path to the fxtran parser
136 :param parserOptions: dictionnary holding the parser options
137 :param wrapH: if True, content of .h file is put in a .F90 file (to force
138 fxtran to recognize it as free form) inside a module (to
139 enable the reading of files containing only a code part)
140 :returns: (includesRemoved, xml) where includesRemoved indicates if an include
141 was replaced by fxtran and xml is an ET xml document
144 ET.register_namespace(
'f', NAMESPACE)
147 if parserOptions
is None:
149 parserOptions = pyfortool.PYFT.DEFAULT_FXTRAN_OPTIONS
154 with tempfile.NamedTemporaryFile(buffering=0, suffix=
'.F90')
as file:
155 if os.path.exists(fortranSource):
159 filename = fortranSource
160 if wrapH
and filename.endswith(
'.h'):
163 with open(fortranSource,
'r', encoding=
'utf-8')
as src:
168 firstLine = [line
for line
in content.split(
'\n')
169 if not (re.search(
r'^[\t ]*!', line)
or
170 re.search(
r'^[\t ]*$', line))][0]
171 fisrtLine = firstLine.upper().split()
172 if not (
'SUBROUTINE' in fisrtLine
or 'FUNCTION' in firstLine):
175 content =
'MODULE FOO\n' + content +
'\nEND MODULE FOO'
176 file.write(content.encode(
'UTF8'))
179 file.write(fortranSource.encode(
'UTF-8'))
180 xml = subprocess.run([parser, filename,
181 '-o',
'-'] + parserOptions,
182 stdout=subprocess.PIPE, check=
True,
183 encoding=
'UTF-8').stdout
184 xml = ET.fromstring(xml, parser=ET.XMLParser(encoding=
'UTF-8'))
186 xml.find(
'./{*}file').attrib[
'name'] = fortranSource
188 file = xml.find(
'./{*}file')
189 programUnit = file.find(
'./{*}program-unit')
191 for node
in programUnit[1:-1]:
194 node.tail = node.tail[:-1]
195 file.remove(programUnit)
198 if len(set([
'-no-include',
'-noinclude']).intersection(parserOptions)) == 0:
205 includeStmts = xml.findall(
'.//{*}include')
206 for includeStmt
in includeStmts:
207 par = [p
for p
in xml.iter()
if includeStmt
in p][0]
208 par.remove(includeStmt)
211 mainfile = xml.find(
'./{*}file')
212 for file
in mainfile.findall(
'.//{*}file'):
213 par = [p
for p
in xml.iter()
if file
in p][0]
214 index = list(par).index(file)
215 if file.tail
is not None:
216 file[-1].tail = file.tail
if file[-1].tail
is None else (file[-1].tail + file.tail)
217 for node
in file[::-1]:
218 par.insert(index, node)
221 return includesDone, xml