Source code for jube2.result_types.keyvaluesresult

# JUBE Benchmarking Environment
# Copyright (C) 2008-2024
# Forschungszentrum Juelich GmbH, Juelich Supercomputing Centre
# http://www.fz-juelich.de/jsc/jube
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""KeyValuesResulttype definition"""

from __future__ import (print_function,
                        unicode_literals,
                        division)

from jube2.result import Result
import jube2.log
import xml.etree.ElementTree as ET
import operator
import jube2.util.util
import jube2.util.output

LOGGER = jube2.log.get_logger(__name__)


[docs]class KeyValuesResult(Result): """A generic key value result type"""
[docs] class KeyValuesData(Result.ResultData): """Key value data""" def __init__(self, other_or_name): if type(other_or_name) is str: Result.ResultData.__init__(self, other_or_name) elif type(other_or_name) is Result.ResultData: self._name = other_or_name.name self._data = list() self._keys = list() self._benchmark_ids = list() @property def keys(self): """Return keys""" return self._keys @property def data(self): """Return table data""" return self._data @property def data_dict(self): """Return unordered dictionary representation of data""" result_dict = dict() for i, key in enumerate(self._keys): result_dict[key] = list() for data in self._data: result_dict[key].append(data[i]) return result_dict @property def benchmark_ids(self): """Return benchmark ids""" return self._benchmark_ids
[docs] def add_key_value_data(self, keys, data, benchmark_ids): """Add a list of additional rows to current result data""" order = list() last_index = len(self._keys) # Find matching rows for key in keys: if key in self._keys: index = self._keys.index(key) # Check weather key occurs multiple times while index in order: try: index = self._keys.index(key, index + 1) except ValueError: index = len(self._keys) self._keys.append(key) else: index = len(self._keys) self._keys.append(key) order.append(index) # Fill up existing rows if last_index != len(self._keys): for row in self._data: row += ["" for key in self._keys[last_index:]] # Add new rows for row in data: new_row = ["" for key in self._keys] for i, index in enumerate(order): new_row[index] = row[i] self._data.append(new_row) if type(benchmark_ids) is int: self._benchmark_ids.append(benchmark_ids) if type(benchmark_ids) is list: self._benchmark_ids += benchmark_ids
[docs] def add_id_information(self, reverse=False): """Add additional id key to table data.""" id_key = KeyValuesResult.DataKey("id") if id_key not in self._keys: # Add key at the beginning of keys list self._keys.insert(0, id_key) for i, data in enumerate(self._data): data.insert(0, self._benchmark_ids[i]) # Sort data by using new id key (stable sort) self._data.sort(key=operator.itemgetter(0), reverse=reverse) for i, data in enumerate(self._data): self._data[i][0] = str(data[0])
[docs] def add_result_data(self, result_data): """Add additional result data""" if self.name != result_data.name: raise RuntimeError("Cannot combine to different result sets.") self.add_key_value_data(result_data.keys, result_data.data, result_data.benchmark_ids)
[docs] def create_result(self, show=True, filename=None, **kwargs): """Create result representation""" raise NotImplementedError("")
[docs] class DataKey(object): """Class represents one data key """ def __init__(self, name, title=None, format_string=None, unit=None): self._name = name self._title = title self._format_string = format_string self._unit = unit @property def title(self): """Key title""" return self._title @property def name(self): """Key name""" return self._name @property def format(self): """Key data format""" return self._format_string @property def unit(self): """Key data unit""" return self._unit @unit.setter def unit(self, unit): """Set key data unit""" self._unit = unit @property def resulting_name(self): """Column name based on name, title and unit""" if self._title is not None: name = self._title else: name = self._name if self._unit is not None: name += "[{0}]".format(self._unit) return name
[docs] def etree_repr(self): """Return etree object representation""" key_etree = ET.Element("key") key_etree.text = self._name if self._format_string is not None: key_etree.attrib["format"] = self._format_string if self._title is not None: key_etree.attrib["title"] = self._title return key_etree
def __eq__(self, other): return self.resulting_name == other.resulting_name def __hash__(self): return hash(self.resulting_name)
def __init__(self, name, sort_names=None, res_filter=None): Result.__init__(self, name, res_filter) self._keys = list() if sort_names is None: self._sort_names = list() else: self._sort_names = sort_names
[docs] def add_key(self, name, format_string=None, title=None, unit=None): """Add an additional key to the dataset""" self._keys.append(KeyValuesResult.DataKey(name, title, format_string, unit))
[docs] def create_result_data(self, select=None, exclude=None): """Create result data""" result_data = KeyValuesResult.KeyValuesData(self._name) if exclude is None: exclude = [] if select is None: select = [key.name for key in self._keys] else: # Check whether the same column name appears in select and exclude if set(select) & set(exclude): LOGGER.error("Error when checking the select and exclude names: " "A pattern or parameter name occurs in both select " "and exclude") exit() # Read pattern/parameter units if available units = self._load_units([key.name for key in self._keys]) for key in self._keys: if key.name in units: key.unit = units[key.name] sort_data = list() for dataset in self._analyse_data(): # Add additional data if needed for sort_name in self._sort_names: if sort_name not in dataset: dataset[sort_name] = None sort_data.append(dataset) # Sort the resultset if len(self._sort_names) > 0: LOGGER.debug("sort using: {0}".format(",".join(self._sort_names))) # Use CompType for sorting to allow comparison of None values sort_data = \ sorted(sort_data, key=lambda x: [jube2.util.util.CompType(x[sort_name]) for sort_name in self._sort_names]) # Check for correctness of exclude and select names key_names = [key.name for key in self._keys] # Help lists for multiple columns unique_select = [] multiple_select = [] for select_name in select: # Check if given names exist in keys if select_name not in key_names: LOGGER.warning("The result table does not contain a pattern " "or parameter with the name '{0}'. This " "name will be ignored for selection." .format(select_name)) # Check whether the given name occurs only once if select_name not in unique_select: unique_select.append(select_name) elif select_name not in multiple_select: multiple_select.append(select_name) LOGGER.warning("The pattern or parameter name {} occurs more " "than once. These additional occurrences are " "ignored for selection.".format(select_name)) # Help lists for multiple columns unique_exclude = [] multiple_exclude = [] for exclude_name in exclude: # Check if given names exist in keys if exclude_name not in key_names: LOGGER.warning("The result table does not contain a pattern " "or parameter with the name '{0}'. This " "name will be ignored for exclusion." .format(exclude_name)) # Check whether the given name occurs only once if exclude_name not in unique_exclude: unique_exclude.append(exclude_name) elif exclude_name not in multiple_exclude: multiple_exclude.append(exclude_name) LOGGER.warning("The pattern or parameter name {} occurs more " "than once. These additional occurrences are " "ignored for exclusion.".format(exclude_name)) # Select and exclude table columns self._keys = [key for key in self._keys if key.name in select and \ key.name not in exclude] # Create table data table_data = list() for dataset in sort_data: row = list() cnt = 0 for key in self._keys: if key.name in dataset: # Cnt number of final entries to avoid complete empty # result entries cnt += 1 # Set null value if dataset[key.name] is None: value = "" else: # Format data values to create string representation if key.format is not None: value = jube2.util.output.format_value( key.format, dataset[key.name]) else: value = str(dataset[key.name]) row.append(value) else: row.append(None) if cnt > 0: table_data.append(row) # Add data to toe result set result_data.add_key_value_data(self._keys, table_data, self._benchmark.id) return result_data