Skip to content

Commit c44126f

Browse files
author
Jean Luc Bouchot
committed
Script to generate the whole library updated
1 parent 1976182 commit c44126f

1 file changed

Lines changed: 54 additions & 69 deletions

File tree

run_tapenade_blas.py

Lines changed: 54 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66
import subprocess
77
import sys
88
from pathlib import Path
9+
from shutil import rmtree as shrm
910

1011
FORTRAN_EXTS = {".f", ".for", ".f90", ".F", ".F90"}
12+
TAPENADE_USELESS_ZONES = 3
1113

1214
def is_fortran(p: Path) -> bool:
1315
return p.suffix in FORTRAN_EXTS
@@ -8030,7 +8032,7 @@ def main():
80308032
help="AD modes to generate: d (forward scalar), dv (forward vector), b (reverse scalar), bv (reverse vector), all (all modes). Default: all")
80318033
ap.add_argument("--nbdirsmax", type=int, default=4, help="Maximum number of derivative directions for vector mode (default: 4)")
80328034
ap.add_argument("--flat", action="store_true", help="Use flat directory structure (all files in function directory, single DIFFSIZES.inc)")
8033-
ap.add_argument("--debug-genlib", default=None, required=False)
8035+
ap.add_argument("--genlib", default=None, required=False, help="Generate Tapenade external library")
80348036
ap.add_argument("--extra", nargs=argparse.REMAINDER, help="Extra args passed to Tapenade after -d/-r", default=[])
80358037
args = ap.parse_args()
80368038

@@ -8085,10 +8087,10 @@ def main():
80858087
modes = {"d", "dv", "b", "bv"}
80868088

80878089
# Determine which specific modes to run
8088-
run_d = "d" in modes
8089-
run_dv = "dv" in modes
8090-
run_b = "b" in modes
8091-
run_bv = "bv" in modes
8090+
run_d = "d" in modes or args.genlib
8091+
run_dv = not args.genlib and "dv" in modes
8092+
run_b = not args.genlib and "b" in modes
8093+
run_bv = not args.genlib and "bv" in modes
80928094

80938095
# List of non-differentiable functions to skip entirely
80948096
# See SKIPPED_FUNCTIONS.md for detailed documentation on why each is skipped
@@ -8123,9 +8125,6 @@ def run_task(task):
81238125

81248126
# Parse the Fortran function to get signature
81258127
func_name, inputs, outputs, inout_vars, func_type, all_params, parse_warnings, param_types, has_sufficient_docs = parse_fortran_function(src)
8126-
print(f"INPUTS = {inputs}")
8127-
print(f"ALL_PARAMS = {all_params}")
8128-
print(f"PARAM_TYPES = {param_types}")
81298128

81308129
if not func_name:
81318130
print(f"Skipping {src}: Could not parse function signature", file=sys.stderr)
@@ -8161,29 +8160,21 @@ def run_task(task):
81618160
flat_mode = args.flat
81628161
mode_dirs = {}
81638162

8164-
if (args.debug_genlib):
8165-
# if (False):
8163+
if (args.genlib):
81668164
# When generating the general lib useful to Tapenade, we will save everything in a tmp file
81678165
# and only the lib in a local folder used to concatenate everything afterwards.
81688166
tmp_dir = Path("TMPGENLIB").resolve()
81698167
tmp_dir.mkdir(parents=True, exist_ok=True)
81708168
func_out_dir = tmp_dir
81718169
genlib_dir = out_dir
81728170
genlib_dir.mkdir(parents=True, exist_ok=True)
8173-
if run_d:
8174-
mode_dirs['d'] = tmp_dir
8175-
if run_b:
8176-
mode_dirs['b'] = tmp_dir
8177-
if run_dv:
8178-
mode_dirs['dv'] = tmp_dir
8179-
if run_bv:
8180-
mode_dirs['bv'] = tmp_dir
8171+
mode_dirs['d'] = tmp_dir
81818172

81828173
def convert_tap_result2genlib_format(l: str) :
81838174
out = []
81848175
infos = l.split("[")[1]
81858176
use_infos = True
8186-
for c in infos[3:]: # Don't bother with the first 3 elements
8177+
for c in infos[TAPENADE_USELESS_ZONES:]: # Don't bother with the first
81878178
if(c == "]"):
81888179
break
81898180
if use_infos:
@@ -8206,14 +8197,11 @@ def parse_tap_trace4inout(fname):
82068197

82078198
# Now we read the next one, and start looking at the arguments
82088199
var2idx_mapping = dict()
8209-
idx2var_mapping = dict()
82108200
l = f.readline().strip()
8211-
for v in l.split(" ")[3:]: # The first three variables are useless in the sense that they are only used internally for tapenade
8212-
# v is a string resembling "[id]varName" where id is an identifier internal to tapenade for the zone of variable varName
8201+
for v in l.split(" ")[TAPENADE_USELESS_ZONES:]: # The first variables are useless
82138202
not_quite_id, var_name = v.split("]")
8214-
idx = int(not_quite_id[1:])
8203+
idx = int(not_quite_id[1:])-TAPENADE_USELESS_ZONES
82158204
var2idx_mapping[var_name] = idx
8216-
idx2var_mapping[idx] = var_name
82178205

82188206
# Now that the mapping has been parsed, we move towards the end of the analysis phase, and extract the summary
82198207
sought_after = "terminateFGForUnit Unit"
@@ -8335,7 +8323,7 @@ def parse_tap_trace4inout(fname):
83358323
for dep_file in main_file_removed:
83368324
cmd.append(str(dep_file))
83378325
cmd.extend(list(args.extra))
8338-
if (args.debug_genlib):
8326+
if (args.genlib):
83398327
cmd = cmd + ["-traceinout", src.stem]
83408328

83418329
try:
@@ -8344,6 +8332,7 @@ def parse_tap_trace4inout(fname):
83448332
# Format command for logging (properly quoted for shell copy-paste)
83458333
print("CMD:", cmd)
83468334
cmd_str = ' '.join(shlex.quote(str(arg)) for arg in cmd)
8335+
print(cmd_str)
83478336
logf.write(f"Command: {cmd_str}\n")
83488337
logf.write(f"Function: {func_name}\n")
83498338
logf.write(f"Parsed inputs: {inputs}\n")
@@ -8384,41 +8373,43 @@ def parse_tap_trace4inout(fname):
83848373
print(f" ERROR: Exception during forward mode execution: {e}", file=sys.stderr)
83858374
return_codes["forward"] = 999
83868375

8387-
if (args.debug_genlib) : # Everything went well, and we are trying to generate the external lib
8376+
if (args.genlib) : # Everything went well, and we are trying to generate the external lib
83888377
read_not_written, not_read_then_written, read_then_written, var2idx = parse_tap_trace4inout(mode_log_path)
8389-
print(var2idx)
8390-
param_2_tap_reordering = [var2idx[p.lower()]-3 for p in all_params]
8391-
print("Reordering is {}".format(param_2_tap_reordering))
8392-
with open("externalLib", "a") as f:
8378+
if func_type == 'FUNCTION':
8379+
param_for_genlib = all_params + [src.stem]
8380+
else:
8381+
param_for_genlib = all_params
8382+
param_2_tap_reordering = [var2idx[p.lower()] for p in param_for_genlib]
8383+
with open("DiffBlasGenLib", "a") as f:
83938384
f.write(("function " if func_type == 'FUNCTION' else "subroutine ") + src.stem + ":\n")
83948385
indent = " "
83958386
f.write(indent + "external:\n")
8396-
shape = "(" + ", ".join(["param " + str(i) for i in range(1,len(all_params)+1)]) + ")" ## TODO: Need to add ', return' in case of a function,. dpeending on whether it is within the all params or not
8387+
shape = "(" + ", ".join(["param " + str(i) for i in range(1,len(all_params)+1)] + ["result" if func_type == 'FUNCTION' else ""]) + ")" ## TODO: Need to add ', return' in case of a function,. dpeending on whether it is within the all params or not
83978388
f.write(indent + "shape: " + shape + "\n")
83988389
types = []
8399-
for p in all_params:
8390+
for p in param_for_genlib:
84008391
current_type = ""
8401-
if p in param_types['real_vars']:
8392+
if p.upper() in param_types['real_vars'] or p.lower() in param_types['real_vars']:
84028393
current_type = "metavar float" # We should probably be more precise in order to handle mixed precision things
84038394
# Namely, adapt to
84048395
# modifiedType(modifiers(ident double), float() for double / REAL*8
84058396
# float() for single precision
8406-
elif p in param_types['complex_vars']:
8397+
elif p.upper() in param_types['complex_vars'] or p.lower() in param_types['complex_vars']:
84078398
current_type = "metavar complex"
84088399
# Similar to the real variables, we should be able to be more precise in terms of precision of the complex variable
8409-
elif p in param_types['integer_vars']:
8400+
elif p.upper() in param_types['integer_vars'] or p.lower() in param_types['integer_vars']:
84108401
current_type = "metavar integer"
8411-
elif p in param_types['char_vars']:
8402+
elif p.upper() in param_types['char_vars'] or p.lower() in param_types['char_vars']:
84128403
current_type = "character()"
8413-
if p in param_types['array_vars']: # Will be "is_matrix_var" or "is_array_var" or something along those lines
8404+
if p.upper() in param_types['array_vars'] or p.lower() in param_types['array_vars']:
84148405
current_type = "arrayType(" + current_type + ", dimColons())"
8415-
84168406
types.append(current_type)
84178407
types = "(" + ", ".join(types) + ")"
84188408
f.write(indent + "type: " + types + "\n")
84198409
f.write(indent + "ReadNotWritten: (" + ", ".join([read_not_written[i] for i in param_2_tap_reordering]) + ")\n")
84208410
f.write(indent + "NotReadThenWritten: (" + ", ".join([not_read_then_written[i] for i in param_2_tap_reordering]) + ")\n")
84218411
f.write(indent + "ReadThenWritten: (" + ", ".join([read_then_written[i] for i in param_2_tap_reordering]) + ")\n")
8412+
f.write("\n")
84228413

84238414
# Run scalar reverse mode (b)
84248415
if run_b:
@@ -8818,37 +8809,31 @@ def parse_tap_trace4inout(fname):
88188809

88198810

88208811

8821-
if (args.debug_genlib):
8822-
'''
8823-
WORKING HERE
8824-
XXXXXXXXXX
8825-
Need to figure out:
8826-
-> The various parameters of a subroutine, their types
8827-
-> Convert these types into Tapenade's GenLib format
8828-
-> Link the number of a parameter in the prototype of the subroutine with its rank in tapenade's inout analysis
8829-
-> Dump everything into a single genlib file
8830-
'''
8831-
# Add tests for existence of file / correct extension / ...
8832-
file_path = fortran_dir / args.debug_genlib
8833-
8834-
tasks = []
8835-
func_stem = file_path.stem.lower()
8836-
rel = file_path.relative_to(fortran_dir)
8837-
out_dir = out_root / rel.parent
8838-
out_dir.mkdir(parents=True, exist_ok=True)
8839-
log_path = out_dir / (file_path.stem + ".tapenade.log")
8840-
# Explicitely force the diff modes for now:
8841-
run_d, run_dv, run_b, run_bv = True, False, True, False
8842-
tasks.append((file_path, out_dir, log_path, run_d, run_dv, run_b, run_bv))
8843-
constraints = parse_parameter_constraints(file_path)
8844-
parsed_function = parse_fortran_function(file_path, suppress_warnings=False)
8845-
args_are = ["function_name", "inputs", "outputs", "inout_vars", "func_type", "params", "warnings", "param_types", "has_sufficient_docs"]
8846-
for idx, v in enumerate(parsed_function):
8847-
print(f"{args_are[idx]} == {v}")
8848-
8849-
run_task(tasks[0])
8850-
8851-
return
8812+
# if (args.genlib):
8813+
# '''
8814+
# WORKING HERE
8815+
# XXXXXXXXXX
8816+
# Need to figure out:
8817+
# -> The various parameters of a subroutine, their types
8818+
# -> Convert these types into Tapenade's GenLib format
8819+
# -> Link the number of a parameter in the prototype of the subroutine with its rank in tapenade's inout analysis
8820+
# -> Dump everything into a single genlib file
8821+
# '''
8822+
# # Add tests for existence of file / correct extension / ...
8823+
# file_path = fortran_dir / args.genlib
8824+
8825+
# tasks = []
8826+
# func_stem = file_path.stem.lower()
8827+
# rel = file_path.relative_to(fortran_dir)
8828+
# out_dir = out_root / rel.parent
8829+
# out_dir.mkdir(parents=True, exist_ok=True)
8830+
# log_path = out_dir / (file_path.stem + ".tapenade.log")
8831+
# # Explicitely force the diff modes for now:
8832+
# run_d, run_dv, run_b, run_bv = True, False, False, False
8833+
# tasks.append((file_path, out_dir, log_path, run_d, run_dv, run_b, run_bv))
8834+
# run_task(tasks[0])
8835+
8836+
# return
88528837

88538838

88548839

0 commit comments

Comments
 (0)