From 7a9d15eaf381b85aa3b404e9c8a2b14c7adecf22 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Keck <jean-baptiste.keck@imag.fr> Date: Sun, 18 Mar 2018 13:31:26 +0100 Subject: [PATCH] better domain and operator reports --- hysop/backend/device/opencl/opencl_env.py | 73 +++++++------- hysop/core/graph/computational_graph.py | 114 ++++++++++++++-------- hysop/domain/box.py | 3 +- hysop/fields/cartesian_discrete_field.py | 4 +- hysop/tools/string_utils.py | 11 +++ hysop/topology/cartesian_topology.py | 4 +- 6 files changed, 124 insertions(+), 85 deletions(-) diff --git a/hysop/backend/device/opencl/opencl_env.py b/hysop/backend/device/opencl/opencl_env.py index 0ae68d67c..49f11d0e0 100644 --- a/hysop/backend/device/opencl/opencl_env.py +++ b/hysop/backend/device/opencl/opencl_env.py @@ -8,6 +8,7 @@ from hysop.tools.types import check_instance, first_not_None from hysop.tools.io_utils import IO from hysop.tools.units import bytes2str from hysop.tools.warning import HysopWarning +from hysop.tools.string_utils import framed_str from hysop.backend.device.opencl import cl, clTools, __OPENCL_PROFILE__, OPENCL_KERNEL_DUMP_FOLDER from hysop.backend.device.opencl.opencl_tools import convert_device_type, convert_precision @@ -69,25 +70,28 @@ class OpenClEnvironment(TaggedObject): platform_id = first_not_None(platform_id, __DEFAULT_PLATFORM_ID__) device_id = first_not_None(device_id, __DEFAULT_DEVICE_ID__) device_type = first_not_None(device_type, DeviceType.ALL) - + msg=\ -'''== Creating OpenCL environment == - name: {} - platform_id: {} - device_id: {} - device_type: {} - gl_sharing: {} - communicator size: {} -'''.format(name, platform_id, device_id, +''' name: {} + platform_id: {} + device_id: {} + device_type: {} + gl_sharing: {} + comm size: {}'''.format( + name, platform_id, device_id, device_type, gl_sharing, mpi_params.size) - vprint(msg) - + device_type = convert_device_type(device_type) - - # OpenCL platform - platform = get_platform(platform_id, strict=strict) - # OpenCL device - device = get_device(platform, device_id, device_type, strict=strict) + try: + # OpenCL platform + platform = get_platform(platform_id, strict=strict) + # OpenCL device + device = get_device(platform, device_id, device_type, strict=strict) + except: + title=' while creating the following OpenCL environment ' + msg=framed_str(title=title, msg=msg) + print msg+'\n' + raise # OpenCL context context = get_context(device, gl_sharing) # OpenCL default queue @@ -103,6 +107,7 @@ class OpenClEnvironment(TaggedObject): if pos>0: name = name[:pos] name=name.strip() + self._platform = platform self._device = device @@ -111,14 +116,16 @@ class OpenClEnvironment(TaggedObject): self._cl_version = self._parse_opencl_version() try: - device_type_str = cl.device_type.to_string(device.type), + device_type_str = cl.device_type.to_string(device.type) except ValueError: device_type_str = 'UNKNOWN DEVICE TYPE {}'.format(device.type) self.device_type_str = device_type_str - msg=\ -''' -- Platform -- + msg+=\ +''' + + -- Platform -- *plat id: {} *name: {} *version: {} @@ -128,19 +135,21 @@ class OpenClEnvironment(TaggedObject): *name: {} *type: {} *version: {} - *global mem size: {} -'''.format( -platform_id, platform.name, platform.version, -device_id, device.name, device_type_str, + *global mem size: {}'''.format( +platform_id, platform.name.strip(), platform.version, +device_id, device.name.strip(), device_type_str, device.opencl_c_version, bytes2str(device.global_mem_size)) if context.properties: + msg+='\n' msg+='\n -- Context --' msg+='\n *properties: {}'.format(context.properties) - msg+='\n' if queue.properties: + msg+='\n' msg+='\n -- Queue --' msg+='\n *properties: {}'.format(queue.properties) - msg+='\n' + + title=' Creating OpenCL environment {} '.format(self.tag) + msg=framed_str(title=title, msg=msg) vprint(msg) # Floating point codegeneration mode @@ -156,20 +165,6 @@ device.opencl_c_version, bytes2str(device.global_mem_size)) self.default_build_opts.append('-cl-nv-verbose') self.macros = {} - # Kernels configuration dictionary - if self.device.name == 'Cayman': - from hysop.backend.device.opencl.device_config.config_cayman import \ - kernels_config as _kernel_cfg - elif self.device.name in ['Tesla K20m', 'Tesla K20Xm']: - from hysop.backend.device.opencl.device_config.config_k20m import \ - kernels_config as _kernel_cfg - else: - vprint('/!\\ Get a default kernels config for {}'.format(self.device.name.strip())) - from hysop.backend.device.opencl.device_config.config_default import \ - kernels_config as _kernel_cfg - self.kernels_config = _kernel_cfg - - vprint('=================================\n') self._mpi_params = mpi_params self.is_master = (mpi_params.rank==0) diff --git a/hysop/core/graph/computational_graph.py b/hysop/core/graph/computational_graph.py index 73b441fac..c47877b82 100644 --- a/hysop/core/graph/computational_graph.py +++ b/hysop/core/graph/computational_graph.py @@ -1,6 +1,8 @@ from hysop import __DEBUG__, __VERBOSE__, vprint, dprint from hysop.tools.decorators import debug from hysop.tools.types import to_list, to_set +from hysop.tools.string_utils import framed_str +from hysop.tools.numpywrappers import npw from hysop.core.graph.graph import not_implemented, initialized, discretized, \ ready, graph_built, not_initialized from hysop.core.graph.graph import Graph, ComputationalGraphNodeData, gt, graph_draw @@ -67,7 +69,7 @@ class ComputationalGraph(ComputationalGraphNode): sinputs = '' def sorted_reqs(reqs): return sorted(reqs, key=lambda x: \ - '{:15s}'.format('{}::{}'.format(x.operator.name, x.field.name))) + '{}::{}'.format(x.operator.name, x.field.name)) for field, mreqs in requirements.input_field_requirements.iteritems(): for td, reqs in mreqs.requirements.iteritems(): for req in reqs: @@ -106,60 +108,91 @@ class ComputationalGraph(ComputationalGraphNode): return ss def domain_report(self): - ss = '== ComputationalGraph {} domain and operator report =='.format(self.name) domains = self.get_domains() - for (domain,ops) in domains.iteritems(): + ops={} + for (domain,operators) in domains.iteritems(): if (domain is None): continue - ss += '\n>{}'.format(domain.short_description()) - name_size = max(len(op.name) for op in ops) - for op in sorted(ops, key=lambda x: x.name): + for op in sorted(operators, key=lambda x: x.name): finputs = ','.join( sorted([f.name for f in op.input_fields if f.domain is domain])) foutputs =','.join( sorted([f.name for f in op.output_fields if f.domain is domain])) pinputs = ','.join( sorted([p for p in op.input_params])) poutputs =','.join( sorted([p for p in op.output_params])) - infields = '[{}]'.format(finputs) if finputs else '' + infields = '[{}]'.format(finputs) if finputs else '' outfields = '[{}]'.format(foutputs) if foutputs else '' - inparams = '[{}]'.format(pinputs) if pinputs else '' + inparams = '[{}]'.format(pinputs) if pinputs else '' outparams = '[{}]'.format(poutputs) if poutputs else '' - ss += '\n *{:<{name_size}} {:<{in_size}} -> {}'.format( - op.name, - 'in={}{}{}'.format(infields, 'x' if infields and inparams else '', inparams), - 'out={}{}{}'.format(outfields, 'x' if outfields and outparams else '', outparams), - name_size=name_size, - in_size=(max(len(x) for x in finputs) + 7) if finputs else 7) - if None in domains: - ops = domains[None] - ss += '\n>Domainless operators:' - name_size = max(len(op.name) for op in ops) - for op in sorted(ops, key=lambda x: x.name): + + inputs = '{}{}{}'.format(infields, 'x' if infields and inparams else '', inparams) + outputs = '{}{}{}'.format(outfields, 'x' if outfields and outparams else '', outparams) + + if inputs == '': + outputs='no inputs' + if outputs == '': + outputs='no outputs' + ops.setdefault(domain, []).append( (op.name, inputs, outputs, type(op).__name__) ) + + if (None in domains): + opeators = domains[None] + for op in sorted(operators, key=lambda x: x.name): pinputs = ','.join( sorted([p for p in op.input_params])) poutputs =','.join( sorted([p for p in op.output_params])) inparams = '[{}]'.format(pinputs) if pinputs else '' outparams = '[{}]'.format(poutputs) if poutputs else '' - ss += '\n *{:<{name_size}} {:<{in_size}} -> {}'.format( - op.name, - 'in={}'.format(inparams), - 'out={}'.format(outparams), - name_size=name_size, - in_size=max(len(x) for x in pinputs) + 7) - l=len('== ComputationalGraph {} domain and operator report =='.format(self.name)) - ss += '\n{}\n'.format(l*'=') - return ss + + inputs='{}'.format(inparams) + outputs='{}'.format(outparams) + if inputs == '': + outputs='no inputs' + if outputs == '': + outputs='no outputs' + ops.setdefault(None, []).append( (op.name, inputs, outputs, type(op).__name__) ) + + name_size = max(len(s[0]) for ss in ops.values() for s in ss) + in_size = max(len(s[1]) for ss in ops.values() for s in ss) + out_size = max(len(s[2]) for ss in ops.values() for s in ss) + type_size = max(len(s[3]) for ss in ops.values() for s in ss) + + ss = '' + for (domain,dops) in ops.iteritems(): + if (domain is None): + continue + ss += '\n>{}'.format(domain.short_description()) + ss += '\n {:<{name_size}} {:<{in_size}} {:<{out_size}} {:<{type_size}}'.format( + 'OPERATOR', 'INPUTS', 'OUTPUTS', 'OPERATOR TYPE', + name_size=name_size, in_size=in_size, + out_size=out_size, type_size=type_size) + for (opname, inputs, outputs, optype) in dops: + ss += '\n {:<{name_size}} {:<{in_size}} -> {:<{out_size}} {:<{type_size}}'.format( + opname, inputs, outputs, optype, + name_size=name_size, in_size=in_size, + out_size=out_size, type_size=type_size) + if (None in domains): + ss += '\n>Domainless operators:' + ss += '\n {:<{name_size}} {:<{in_size}} {:<{out_size}} {:<{type_size}}'.format( + 'OPERATOR', 'INPUTS', 'OUTPUTS', 'OPERATOR TYPE', + name_size=name_size, in_size=in_size, + out_size=out_size, type_size=type_size) + for (opname, inputs, outputs, optype) in ops[None]: + ss += '\n {:<{name_size}} {:<{in_size}} -> {:<{out_size}} {:<{type_size}}'.format( + opname, inputs, outputs, optype, + name_size=name_size, in_size=in_size, + out_size=out_size, type_size=type_size) + + title=' ComputationalGraph {} domain and operator report '.format(self.name) + return '\n{}\n'.format(framed_str(title=title, msg=ss[1:])) def topology_report(self): - ss = '== ComputationalGraph {} topology and operator report =='.format(self.name) + ss='' for (backend,topologies) in self.get_topologies().iteritems(): ss += '\n {}:'.format(backend.short_description()) ss += '\n *'+'\n *'.join(t.short_description() for t in sorted(topologies, key=lambda x: x.id)) - l=len('== ComputationalGraph {} topology and operator report =='.format(self.name)) - ss += '\n{}\n'.format(l*'=') - return ss + title = ' ComputationalGraph {} topology report '.format(self.name) + return '\n{}\n'.format(framed_str(title=title, msg=ss[1:])) def operator_report(self): - ss = '== ComputationalGraph {} final operator report =='.format(self.name) reduced_graph = self.reduced_graph operators = reduced_graph.vertex_properties['operators'] ops = [] @@ -186,14 +219,13 @@ class ComputationalGraph(ComputationalGraphNode): ops.append( (op.name, inputs, outputs, type(op).__name__) ) - import math - isize = int(math.floor(math.log(len(self.sorted_nodes)-1))) + isize = int(npw.ceil(npw.log10(len(self.sorted_nodes)-1))) name_size = max(len(s[0]) for s in ops) in_size = max(len(s[1]) for s in ops) out_size = max(len(s[2]) for s in ops) type_size = max(len(s[3]) for s in ops) - ss += '\n {:<{isize}} {:<{name_size}} {:<{in_size}} {:<{out_size}} {:<{type_size}}'.format( + ss = ' {:<{isize}} {:<{name_size}} {:<{in_size}} {:<{out_size}} {:<{type_size}}'.format( 'ID', 'OPERATOR', 'INPUTS', 'OUTPUTS', 'OPERATOR TYPE', isize=isize, name_size=name_size, in_size=in_size, @@ -204,8 +236,9 @@ class ComputationalGraph(ComputationalGraphNode): isize=isize, name_size=name_size, in_size=in_size, out_size=out_size, type_size=type_size) - return ss + title = ' ComputationalGraph {} final operator report '.format(self.name) + return '\n{}\n'.format(framed_str(title=title, msg=ss)) def get_domains(self): domains = {} @@ -491,10 +524,9 @@ class ComputationalGraph(ComputationalGraphNode): requests += op.get_work_properties() if __DEBUG__ or (__VERBOSE__ and self.level==0) or self.__FORCE_REPORTS__: srequests = str(requests) - print '\n== ComputationalGraph {} work properties report =='.format(self.name) - print srequests if (srequests != '') else ' *no extra work requested*' - print '='*len('== ComputationalGraph {} work properties report =='.format(self.name)) - print + ss = (srequests if (srequests != '') else ' *no extra work requested*') + title= ' ComputationalGraph {} work properties report '.format(self.name) + vprint('\n{}\n'.format(framed_str(title=title, msg=ss))) return requests @debug diff --git a/hysop/domain/box.py b/hysop/domain/box.py index d8932e3fb..83a1359b9 100644 --- a/hysop/domain/box.py +++ b/hysop/domain/box.py @@ -76,7 +76,8 @@ class BoxView(DomainView): """ Return a short description of this Box as a string. """ - return 'Box(O=[{}], L=[{}], BC=[{}], current_task={})'.format( + return 'Box(tag={}, O=[{}], L=[{}], BC=[{}], current_task={})'.format( + self.tag, ','.join(('{:1.1f}'.format(val) for val in self.origin)), ','.join(('{:1.1f}'.format(val) for val in self.length)), ','.join(('{}/{}'.format(str(lb)[:3],str(rb)[:3]) for (lb,rb) in \ diff --git a/hysop/fields/cartesian_discrete_field.py b/hysop/fields/cartesian_discrete_field.py index db021f048..a7e9c2df7 100644 --- a/hysop/fields/cartesian_discrete_field.py +++ b/hysop/fields/cartesian_discrete_field.py @@ -830,9 +830,9 @@ class CartesianDiscreteField(CartesianDiscreteFieldView, DiscreteField): self._has_ghosts = (topology.mesh.ghosts>0).any() if allocate_data: - msg='\nAllocation of field {} ({}) on backend {}' + msg='\nAllocation of discrete field {} ({}) on {} and {}' msg+='\n (compute_res={}, ghosts={}, nb_comp={}, dtype={})' - msg=msg.format(self.name, self.tag, self.backend.kind, + msg=msg.format(self.name, self.full_tag, self.backend.full_tag, self.topology.topology.full_tag, self.compute_resolution, self.ghosts, self.nb_components, self.dtype) vprint(msg) data = tuple(self.backend.empty(shape=self.shape, dtype=self.dtype) diff --git a/hysop/tools/string_utils.py b/hysop/tools/string_utils.py index a6100c186..6aa9c2d97 100644 --- a/hysop/tools/string_utils.py +++ b/hysop/tools/string_utils.py @@ -27,3 +27,14 @@ def vprint_banner(msg, c='*'): vprint(c*len(msg)) vprint(msg) vprint(c*len(msg)) + +def framed_str(title, msg, c='=', at_border=2): + """ + Format a message to fit between two separation lines + containing a title. + """ + length = max(len(m) for m in msg.split('\n')) + title = c*at_border + title + c*at_border + header = title + c*max(0, length-len(title)) + footer = c*len(header) + return '{}\n{}\n{}'.format(header, msg, footer) diff --git a/hysop/topology/cartesian_topology.py b/hysop/topology/cartesian_topology.py index a10804390..e276861dc 100644 --- a/hysop/topology/cartesian_topology.py +++ b/hysop/topology/cartesian_topology.py @@ -360,10 +360,10 @@ class CartesianTopologyView(TopologyView): Returns a short description of the current TopologyView. Short version of long_description(). """ - s='CartesianTopology[tag={}, task_id={}, pcoords={}, pshape={}, ' + s='CartesianTopology[tag={}, domain={}, task_id={}, pcoords={}, pshape={}, ' s+='distr.={}, periods={}, shape={}, ghosts={}]' s = s.format( - self.tag, self.task_id, + self.tag, self.domain.domain.full_tag, self.task_id, self.proc_coords, self.proc_shape, '[{}]'.format(','.join('T' if per else 'F' for per in self.is_distributed)), '[{}]'.format(','.join('T' if per else 'F' for per in self.is_periodic)), -- GitLab