From fb393d964d88c96d9de12e46f87fc29d0163aa1f Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Keck <Jean-Baptiste.Keck@imag.fr> Date: Mon, 18 Feb 2019 21:31:35 +0100 Subject: [PATCH] better logs for the graph builder, fixed topology priority according to discretization --- hysop/core/graph/graph_builder.py | 83 +++++++++++++++++------------- hysop/fields/field_requirements.py | 13 +++-- 2 files changed, 56 insertions(+), 40 deletions(-) diff --git a/hysop/core/graph/graph_builder.py b/hysop/core/graph/graph_builder.py index 8a9fc5069..52d8bd1d7 100644 --- a/hysop/core/graph/graph_builder.py +++ b/hysop/core/graph/graph_builder.py @@ -20,13 +20,21 @@ from hysop.operator.redistribute import Redistribute, RedistributeNotImplem from hysop.operator.transpose import Transpose, TranspositionNotImplementedError from hysop.operator.memory_reordering import MemoryReordering, MemoryReorderingNotImplementedError -DEBUG_GRAPH_BUILDER=False +# Debug level for graph building +# 0: no debug logs +# 1: print debug info about input/outputs and operator generation +# 2: print debug info about topology states in addition +GRAPH_BUILDER_DEBUG_LEVEL=1 def gprint(*args, **kwds): - if DEBUG_GRAPH_BUILDER: + level = kwds.pop('level', 1) + if GRAPH_BUILDER_DEBUG_LEVEL >= level: __builtin__.print(*args, **kwds) - else: - dprint(*args, **kwds) + +def gprint2(*args, **kwds): + kwds['level'] = 2 + gprint(*args, **kwds) + def _op_info(op, istates=None, ostates=None, @@ -101,8 +109,8 @@ class GraphBuilder(object): """ check_instance(node, ComputationalGraph) self.target_node = node - gprint('::Graph builder::') - gprint(' >Initialized graph builder for ComputationalGraph {}'.format(node.name)) + gprint('\n::Graph builder::') + gprint('>Initialized graph builder for ComputationalGraph {}'.format(node.name)) def configure(self, current_level, outputs_are_inputs, **kwds): @@ -291,35 +299,31 @@ class GraphBuilder(object): ofields[ofield] = otopo # iterate over subgraph operator input parameters - gprint(' >Input parameters') if iparams: + gprint(' >Input parameters') for iparam in sorted(iparams.values(), key=lambda x: x.name): gprint(' *{}'.format(iparam.short_description())) parameter_handler.handle_input_parameter(iparam, opnode) if (iparam.name not in output_params): input_params[iparam.name] = iparam - else: - gprint(' no input parameters') # iterate over subgraph operator output parameters - gprint(' >Output parameters') if oparams: + gprint(' >Output parameters') for oparam in sorted(oparams.values(), key=lambda x: x.name): gprint(' *{}'.format(oparam.short_description())) parameter_handler.handle_output_parameter(oparam, opnode) output_params[oparam.name] = oparam - else: - gprint(' no output parameters') # iterate over subgraph operator input fields - gprint(' >Input fields') input_states = {} if ifields: + gprint(' >Input fields') for (ifield,itopo) in sorted(ifields.iteritems(), key=lambda x: x[0].name, reverse=True): - gprint(' *{} on {}'.format(ifield.name, - 'unknown topology (to be determined)' if (itopo is None) \ - else 'topology {}'.format(itopo.id))) + gprint(' *{}{}'.format(ifield.name, + ' on an unknown topology (to be determined)' if (itopo is None) \ + else '.{}'.format(itopo.pretty_tag))) if (itopo is None): continue if isinstance(op, Problem): @@ -346,16 +350,14 @@ class GraphBuilder(object): if is_new: input_fields[ifield] = itopo input_topology_states[ifield] = (ifreqs, dstate) - else: - gprint(' no input fields') # iterate over subgraph operator output fields - gprint(' >Output fields') output_states = {} if ofields: + gprint(' >Output fields') for (ofield,otopo) in sorted(ofields.iteritems(), key=lambda x: x[0].name, reverse=True): assert (otopo is not None) - gprint(' *{} on topo {}'.format(ofield.name, otopo.id)) + gprint(' *{}.{}'.format(ofield.name, otopo.pretty_tag)) if isinstance(op, Problem): if ofield in op.final_output_topology_states.keys(): ofreqs = op.final_output_topology_states[ofield][0] @@ -374,8 +376,6 @@ class GraphBuilder(object): output_fields[ofield] = otopo output_states[ofield] = dstate output_topology_states[ofield] = (None, dstate) - else: - gprint(' no output fields') if (current_level==0) and ((op,opnode) not in deferred_operators): vertex_properties['op_info'][opnode] = _op_info(op, input_states, @@ -384,9 +384,9 @@ class GraphBuilder(object): op_input_topology_states[op] = input_states op_output_topology_states[op] = output_states - # iterate defered nodes + # iterate deferred nodes for (op,opnode) in deferred_operators: - gprint(' >Handling defered node {}'.format(op.name)) + gprint(' >Handling deferred node {}'.format(op.name)) ifields = op.input_fields input_states = op_input_topology_states[op] output_states = op_output_topology_states[op] @@ -1010,17 +1010,19 @@ class GraphBuilder(object): istate.memory_order = default_memory_order else: istate.memory_order = allowed_memory_order - gprint(' >Initial state set to {}'.format(istate)) + gprint2(' >Initial state set to {}'.format(istate)) else: istate = dtopology_states.setdefault(target_topo, CartesianTopologyState(dim)) - gprint(' >Input state is {}'.format(istate)) + gprint2(' >Input state is {}'.format(istate)) target_axes = target_dfield_requirements.axes target_memory_order = target_dfield_requirements.memory_order def topology_affinity(candidate_topo): candidate_state = self.discrete_topology_states[candidate_topo] - score = (candidate_topo is target_topo) * 100000 # skip redistribute + score = (candidate_topo is target_topo) * 1000000 # skip redistribute + score += (candidate_topo.grid_resolution + == target_topo.grid_resolution)*100000 # skip multiresolution filter (not automatically handled yet) score += ((target_axes is not None) and (candidate_state.axes in target_axes))*10000 # skip transpose score += (candidate_topo.backend is target_topo.backend)*1000 # better bandwidth @@ -1031,10 +1033,13 @@ class GraphBuilder(object): return score if (target_topo.backend.kind is Backend.HOST) and write_nodes: - gprint('REDISTRIBUTE TO HOST') - src_topos = write_nodes.keys() # give source topo priority according to topology_affinity - src_topo = sorted(src_topos, key=topology_affinity, reverse=True)[0] + src_topos = write_nodes.keys() + src_topos = sorted(src_topos, key=topology_affinity, reverse=True) + src_topo = src_topos[0] + if (src_topo is not target_topo): + gprint(' >Redistributing field {} from up to date topologies {} to host topology {}.'.format( + ifield.name, ' ,'.join(t.pretty_tag for t in src_topos), target_topo.pretty_tag)) self.transpose(src_topo, target_axes, graph, vertex_properties, edge_properties) self.redistribute(target_topo, graph, @@ -1043,10 +1048,13 @@ class GraphBuilder(object): self.reorder(target_topo, target_memory_order, graph, vertex_properties, edge_properties) elif (target_topo.backend.kind is Backend.OPENCL) and write_nodes: - gprint('REDISTRIBUTE TO DEVICE') # give source topo priority according to topology_affinity src_topos = write_nodes.keys() - src_topo = sorted(src_topos, key=topology_affinity, reverse=True)[0] + src_topos = sorted(src_topos, key=topology_affinity, reverse=True) + src_topo = src_topos[0] + if (src_topo is not target_topo): + gprint(' >Redistributing field {} from up to date topologies {} to device topology {}.'.format( + ifield.name, ' ,'.join(t.pretty_tag for t in src_topos), target_topo.pretty_tag)) self.reorder(src_topo, target_memory_order, graph, vertex_properties, edge_properties) self.redistribute(target_topo, graph, @@ -1055,14 +1063,13 @@ class GraphBuilder(object): self.transpose(target_topo, target_axes, graph, vertex_properties, edge_properties) else: - gprint('NOTHING TO REDISTRIBUTE') self.transpose(target_topo, target_axes, graph, vertex_properties, edge_properties) self.reorder(target_topo, target_memory_order, graph, vertex_properties, edge_properties) istate = dtopology_states[target_topo] - gprint(' >Input state is now {}'.format(istate)) + gprint2(' >Input state is now {}'.format(istate)) else: istate = None @@ -1113,7 +1120,7 @@ class GraphBuilder(object): ofield, output_topo) if invalidate_field: - gprint('INVALIDATE FIELD {}'.format(ofield.name)) + gprint(' >Invalidating output field {} on all topologies but {} because is has been freshly written.'.format(ofield.name, output_topo.pretty_tag)) # add dependency to all operators that reads this field # to prevent concurent read-writes. if output_topo in read_nodes: @@ -1125,6 +1132,10 @@ class GraphBuilder(object): # remove read/write dependencies and states write_nodes.clear() dtopology_states.clear() + else: + gprint(' >Keeping output field {} up to date on all topologies because is has been marked as preserved by operator.'.format(ofield.name)) + gprint(' >Up to date topologies for field {} are now {}, {}.'.format(ofield.name, output_topo.pretty_tag, + ' ,'.join(t.pretty_tag for t in write_nodes))) # add the operator node as the one that lastly wrote this field. # no other operators can be reading as this topology just been written. @@ -1136,7 +1147,7 @@ class GraphBuilder(object): else: ostate = operator.output_topology_state(ofield, input_topology_states) dtopology_states[output_topo] = ostate - gprint(' >Output state is now {}'.format(ostate)) + gprint2(' >Output state is now {}'.format(ostate)) else: ostate = None diff --git a/hysop/fields/field_requirements.py b/hysop/fields/field_requirements.py index 6f06ccb21..5cf0bf854 100644 --- a/hysop/fields/field_requirements.py +++ b/hysop/fields/field_requirements.py @@ -11,10 +11,15 @@ from hysop.core.graph.computational_node import ComputationalGraphNode from hysop.fields.continuous_field import ScalarField from hysop.fields.discrete_field import DiscreteScalarField -DEBUG_TOPO_CREATION=True +# Debug level for topology creation +# 0: no debug logs +# 1: topo creation summary for each field +# 2: topo creation details for all discrete field requirements +TOPO_CREATION_DEBUG_LEVEL=1 def gprint(*args, **kwds): - if DEBUG_TOPO_CREATION: + level = kwds.pop('level', 2) + if TOPO_CREATION_DEBUG_LEVEL >= level: __builtin__.print(*args, **kwds) @@ -426,9 +431,9 @@ class MultiFieldRequirements(object): req.set_and_check_topology(topo) all_topologies.update(known_topologies) - gprint("SUMMARY OF CREATED TOPOLOGIES FOR FIELD {}:".format(self.field.name)) + gprint("SUMMARY OF CREATED TOPOLOGIES FOR FIELD {}:".format(self.field.name), level=1) for topo in all_topologies: - gprint(" *{}".format(topo.short_description())) + gprint(" *{}".format(topo.short_description()), level=1) gprint("") -- GitLab