def get_userbuffer_group(func_name, parameters, i): """internal function used by process_func_parameters""" p = parameters[i] p2 = parameters[i + 1] p3 = parameters[i + 2] if RE.match(r'mpi_i?(alltoall|allgather|gather|scatter)', func_name, re.IGNORECASE): type = "inplace" if RE.search(r'send', p['name'], re.IGNORECASE) and RE.search( r'scatter', func_name, re.IGNORECASE): type = "noinplace" elif RE.search(r'recv', p['name'], re.IGNORECASE) and not RE.search( r'scatter', func_name, re.IGNORECASE): type = "noinplace" if RE.search(r'alltoallw', func_name, re.IGNORECASE): group_kind = "USERBUFFER-%s-w" % (type) group_count = 4 elif p3['kind'] == "DATATYPE": group_kind = "USERBUFFER-%s" % (type) group_count = 3 else: group_kind = "USERBUFFER-%s-v" % (type) group_count = 4 elif RE.match(r'mpi_i?neighbor', func_name, re.IGNORECASE): if RE.search(r'alltoallw', func_name, re.IGNORECASE): group_kind = "USERBUFFER-neighbor-w" group_count = 4 elif p3['kind'] == "DATATYPE": group_kind = "USERBUFFER-neighbor" group_count = 3 else: group_kind = "USERBUFFER-neighbor-v" group_count = 4 elif RE.match(r'mpi_i?(allreduce|reduce|scan|exscan)', func_name, re.IGNORECASE): group_kind = "USERBUFFER-reduce" group_count = 5 elif RE.match(r'mpi_p(send|recv)_init', func_name, re.IGNORECASE): group_kind = "USERBUFFER-partition" group_count = 4 elif RE.search(r'XFER_NUM_ELEM', p2['kind']) and RE.search( r'DATATYPE', p3['kind']): group_kind = "USERBUFFER-simple" group_count = 3 else: group_kind, group_count = None, 0 return (group_kind, group_count)
def parse_param_attributes(p): """Parse the parameter attribute string and populate common fields""" # this filter function should result in identical results as the JSON if RE.search(r'direction\s*=\s*out', p['t'], re.IGNORECASE): p['param_direction'] = 'out' elif RE.search(r'direction\s*=\s*inout', p['t'], re.IGNORECASE): p['param_direction'] = 'inout' else: p['param_direction'] = 'in' if RE.search(r'length\s*=\s*\[(.*)\]', p['t']): # only the case of MPI_Group_range_{excl,incl} where length=[n, 3] p['length'] = RE.m.group(1).replace(' ', '').split(',') elif RE.search(r'length\s*=\s*([^,\s]*)', p['t']): p['length'] = RE.m.group(1) else: p['length'] = None if RE.search(r'large_only', p['t']): p['large_only'] = True else: p['large_only'] = False if RE.search(r'pointer\s*=\s*True', p['t']): p['pointer'] = True elif RE.search(r'pointer\s*=\s*False', p['t']): p['pointer'] = False else: p['pointer'] = None if RE.search(r'suppress=.*c_parameter', p['t']): p['suppress'] = "c_parameter" else: p['suppress'] = '' if RE.search(r'func_type\s*=\s*(\w+)', p['t']): p['func_type'] = RE.m.group(1) else: p['func_type'] = '' if RE.search(r'constant\s*=\s*True', p['t']): p['constant'] = True else: p['constant'] = False if RE.search(r'asynchronous\s*=\s*True', p['t']): p['asynchronous'] = True else: p['asynchronous'] = False
def load_mpi_api(api_txt, gen_in_dir=""): """Load mpi standard api into global (G) lists and dictionaries.""" cur_func, cur_name = '', '' stage = '' with open(api_txt, "r") as In: for line in In: # -- stage header -- if RE.match(r'(MPI\w+):\s*(.*)', line): name, attr = RE.m.group(1, 2) key = name.lower() stage = "FUNC" cur_name = name if key in G.FUNCS: cur_func = G.FUNCS[key] if RE.search(r'not_implemented', attr): cur_func['not_implemented'] = True else: cur_func = { 'name': name, 'parameters': [], 'attrs': attr, 'desc': "" } G.FUNCS[key] = cur_func if gen_in_dir: cur_func['dir'] = gen_in_dir elif RE.match(r'(\w+)', line): print("Unexpected leading word [%s] in %s" % (RE.m.group(1), api_txt), file=sys.stderr) # anything with unexpected unindented word resets stage stage = '' # -- per-stage parsing -- elif stage == "FUNC": if RE.match(r'\s+\.(\w+):\s*(.*)', line): key, val = RE.m.group(1, 2) cur_func[key] = val elif RE.match(r'\s+(\w+):\s*(\w+)(.*)', line): name, kind, t = RE.m.group(1, 2, 3) if name == 'index': # avoid -Wshadow warning name = 'indx' p = {'name': name, 'kind': kind} if RE.match(r'(.*),\s*\[(.*)\]\s*$', t): t, p['desc'] = RE.m.group(1, 2) p['t'] = t # we include all extra attributes in a 't' string for flexibity # we'll parse the common fields also to improve code readability parse_param_attributes(p) cur_func['parameters'].append(p) elif RE.match(r'{\s*-+\s*(\w+)\s*-+(.*)', line): stage = "code-" + RE.m.group(1) if stage not in cur_func: cur_func[stage] = [] # "error_check" may include list of parameters checked # "handle_ptr" may include list of parameters converted cur_func[stage + "-tail"] = RE.m.group(2).replace( ' ', '').split(',') elif RE.match(r'{', line): stage = "FUNC-body" if 'body' not in cur_func: cur_func['body'] = [] elif RE.match(r'\/\*', line): # man page notes stage = "FUNC-notes" # 'notes' and 'notes2' goes before and after auto-generated notes if RE.match(r'\/\*\s*-+\s*notes-2\s*-+', line): cur_func['notes2'] = [] elif 'notes' not in cur_func: cur_func['notes'] = [] else: cur_func['notes2'] = [] elif stage == "FUNC-body": if RE.match(r'}', line): stage = "FUNC" else: line = re.sub(r'^ ', '', line) cur_func['body'].append(line) elif RE.match(r'(code-\w+)', stage): if RE.match(r'}', line): stage = "FUNC" else: line = re.sub(r'^ ', '', line) cur_func[stage].append(line) elif stage == "FUNC-notes": if RE.match(r'\*\/', line): stage = "FUNC" else: line = re.sub(r'^ ', '', line) if 'notes2' in cur_func: cur_func['notes2'].append(line) else: cur_func['notes'].append(line)