## JUBE Benchmarking Environment
# Copyright (C) 2008-2023
# 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/>.
"""Gives benchmark related info"""
from __future__ import (print_function,
unicode_literals,
division)
import jube2.util.util
import jube2.util.output
import jube2.conf
import jube2.jubeio
import os
import time
import textwrap
import operator
[docs]def print_benchmarks_info(path):
"""Print list of all benchmarks, found in given directory"""
# Get list of all files and directories in given path
if not os.path.isdir(path):
raise OSError("Not a directory: \"{0}\"".format(path))
dir_list = os.listdir(path)
benchmark_info = list()
# Search for possible benchmark dirs
for dir_name in dir_list:
dir_path = os.path.join(path, dir_name)
configuration_file = \
os.path.join(dir_path, jube2.conf.CONFIGURATION_FILENAME)
if os.path.isdir(dir_path) and os.path.exists(configuration_file):
try:
id_number = int(dir_name)
parser = jube2.jubeio.Parser(configuration_file)
name_str, comment_str, tags = parser.benchmark_info_from_xml()
tags_str = jube2.conf.DEFAULT_SEPARATOR.join(tags)
# Read timestamps from timestamps file
timestamps = \
jube2.util.util.read_timestamps(
os.path.join(dir_path, jube2.conf.TIMESTAMPS_INFO))
if "start" in timestamps:
time_start = timestamps["start"]
else:
time_start = time.strftime(
"%Y-%m-%d %H:%M:%S",
time.localtime(os.path.getctime(configuration_file)))
if "change" in timestamps:
time_change = timestamps["change"]
else:
time_change = time.strftime(
"%Y-%m-%d %H:%M:%S",
time.localtime(os.path.getmtime(dir_path)))
benchmark_info.append([id_number, name_str, time_start,
time_change, comment_str, tags_str])
except ValueError:
pass
# sort using id
benchmark_info = sorted(benchmark_info, key=operator.itemgetter(0))
# convert id to string
for info in benchmark_info:
info[0] = str(info[0])
# add header
benchmark_info = [("id", "name", "started", "last change",
"comment", "tags")] + benchmark_info
if len(benchmark_info) > 1:
infostr = (jube2.util.output.text_boxed("Benchmarks found in \"{0}\":".
format(path)) + "\n" +
jube2.util.output.text_table(benchmark_info,
use_header_line=True))
print(infostr)
else:
print("No Benchmarks found in \"{0}\"".format(path))
[docs]def print_benchmark_info(benchmark):
"""Print information concerning a single benchmark"""
infostr = \
jube2.util.output.text_boxed("{0} id:{1} tags:{2}\n\n{3}"
.format(benchmark.name,
benchmark.id,
jube2.conf.DEFAULT_SEPARATOR.join(
benchmark.tags),
benchmark.comment))
print(infostr)
continue_possible = False
print(" Directory: {0}"
.format(os.path.abspath(benchmark.bench_dir)))
# Read timestamps from timestamps file
timestamps = jube2.util.util.read_timestamps(
os.path.join(benchmark.bench_dir, jube2.conf.TIMESTAMPS_INFO))
if "start" in timestamps:
time_start = timestamps["start"]
else:
# Starttime is workpackage.xml creation time
time_start = time.strftime(
"%Y-%m-%d %H:%M:%S",
time.localtime(os.path.getctime(os.path.join(
benchmark.bench_dir, jube2.conf.CONFIGURATION_FILENAME))))
if "change" in timestamps:
time_change = timestamps["change"]
else:
time_change = time.strftime(
"%Y-%m-%d %H:%M:%S",
time.localtime(os.path.getmtime(benchmark.bench_dir)))
print("\n Started: {0}".format(time_start))
print("Last change: {0}".format(time_change))
# Create step overview
step_info = [("step name", "depends", "#work", "#error", "#done",
"last finished")]
for step_name, workpackages in benchmark.workpackages.items():
cnt_done = 0
cnt_error = 0
last_finish = time.localtime(0)
depends = jube2.conf.DEFAULT_SEPARATOR.join(
benchmark.steps[step_name].depend)
for workpackage in workpackages:
if workpackage.done:
cnt_done += 1
# Read timestamp from done_file if it is available otherwise
# use mtime
done_file = os.path.join(workpackage.workpackage_dir,
jube2.conf.WORKPACKAGE_DONE_FILENAME)
done_file_f = open(done_file, "r")
done_str = done_file_f.read().strip()
done_file_f.close()
try:
done_time = time.strptime(done_str, "%Y-%m-%d %H:%M:%S")
except ValueError:
done_time = time.localtime(os.path.getmtime(done_file))
last_finish = max(last_finish, done_time)
if workpackage.error:
cnt_error += 1
if last_finish > time.localtime(0):
last_finish_str = time.strftime("%Y-%m-%d %H:%M:%S", last_finish)
else:
last_finish_str = ""
continue_possible = continue_possible or \
(len(workpackages) != cnt_done)
# Create #workpackages string
iterations = benchmark.steps[step_name].iterations
if benchmark.steps[step_name].iterations > 1:
cnt = "{0}*{1}".format(len(workpackages) // iterations, iterations)
else:
cnt = str(len(workpackages))
step_info.append((step_name, depends, cnt, str(cnt_error),
str(cnt_done), last_finish_str))
print(
"\n" + jube2.util.output.text_table(step_info, use_header_line=True,
indent=1))
if continue_possible:
print("\n--- Benchmark not finished! ---\n")
else:
print("\n--- Benchmark finished ---\n")
print(jube2.util.output.text_line())
[docs]def print_step_info(benchmark, step_name, parametrization_only=False,
parametrization_only_csv=False):
"""Print information concerning a single step in a specific benchmark"""
if step_name not in benchmark.workpackages:
print("Step \"{0}\" not found in benchmark \"{1}\"."
.format(step_name, benchmark.name))
return
if parametrization_only_csv:
parametrization_only = True
if not parametrization_only:
print(jube2.util.output.text_boxed(
"{0} Step: {1}".format(benchmark.name, step_name)))
step = benchmark.steps[step_name]
# Get all possible error filenames
error_file_names = set()
for operation in step.operations:
if operation.stderr_filename is not None:
error_file_names.add(operation.stderr_filename)
else:
error_file_names.add("stderr")
wp_info = [("id", "started?", "error?", "done?", "work_dir")]
error_dict = dict()
parameter_list = list()
useable_parameter = None
for workpackage in benchmark.workpackages[step_name]:
# Parameter substitution to use alt_work_dir
parameter = \
dict([[par.name, par.value] for par in
workpackage.parameterset.constant_parameter_dict.values()])
# Save available parameter names
if useable_parameter is None:
useable_parameter = [name for name in parameter.keys()]
useable_parameter.sort()
id_str = str(workpackage.id)
started_str = str(workpackage.started).lower()
error_str = str(workpackage.error).lower()
done_str = str(workpackage.done).lower()
work_dir = workpackage.work_dir
if step.alt_work_dir is not None:
work_dir = jube2.util.util.substitution(step.alt_work_dir,
parameter)
# collect parameterization
parameter_list.append(dict())
parameter_list[-1]["id"] = str(workpackage.id)
for parameter in workpackage.parameterset:
parameter_list[-1][parameter.name] = parameter.value
# Read error-files
for error_file_name in error_file_names:
if os.path.exists(os.path.join(work_dir, error_file_name)):
error_file = open(os.path.join(work_dir, error_file_name), "r")
error_string = error_file.read().strip()
if len(error_string) > 0:
error_dict[os.path.abspath(os.path.join(
work_dir, error_file_name))] = error_string
error_file.close()
# Store info data
wp_info.append(
(id_str, started_str, error_str, done_str,
os.path.abspath(work_dir)))
if not parametrization_only:
print("Workpackages:")
print(jube2.util.output.text_table(wp_info, use_header_line=True,
indent=1, auto_linebreak=False))
if (useable_parameter is not None) and (not parametrization_only):
print("Available parameter:")
wraps = textwrap.wrap(", ".join(useable_parameter), 80)
for wrap in wraps:
print(wrap)
print("")
if not parametrization_only:
print("Parameterization:")
for parameter_dict in parameter_list:
print(" ID: {0}".format(parameter_dict["id"]))
for name, value in parameter_dict.items():
if name != "id":
print(" {0}: {1}".format(name, value))
print("")
else:
# Create parameterization table
table_data = list()
table_data.append(list())
table_data[0].append("id")
if len(parameter_list) > 0:
for name in parameter_list[0]:
if name != "id":
table_data[0].append(name)
for parameter_dict in parameter_list:
table_data.append(list())
for name in table_data[0]:
table_data[-1].append(parameter_dict[name])
print(jube2.util.output.text_table(
table_data, use_header_line=True, indent=1, align_right=True,
auto_linebreak=False,
style="csv" if parametrization_only_csv else "pretty",
separator=(parametrization_only_csv if (parametrization_only_csv)
else None)))
if not parametrization_only:
if len(error_dict) > 0:
print("!!! Errors found !!!:")
for error_file in error_dict:
print(">>> {0}:".format(error_file))
try:
print("{0}\n".format(error_dict[error_file]))
except UnicodeDecodeError:
print("\n")
[docs]def print_workpackage_info(benchmark, workpackage):
"""Print information concerning a single workpackage in a specific benchmark"""
print(jube2.util.output.text_boxed(
"{0} Workpackage with ID {1}".format(benchmark.name, workpackage.id)))
print("Step: {}".format(workpackage.step.name))
print("")
# Get and print workpackage status
if workpackage.error:
status = "ERROR"
elif not workpackage.done:
status = "RUNNING"
else:
status = "DONE"
print("Status: {}".format(status))
print("")
print("Iteration {}".format(workpackage.iteration))
print("Cycle {}".format(workpackage.cycle))
print("")
# Print parents id
if workpackage.parents:
parent_str = "Workpackage Parents by ID: "
for parent in workpackage.parents:
parent_str += "{}".format(parent.id)
print(parent_str)
# Print sibling id
if workpackage.iteration_siblings:
sibling_str = "Iteration Sibling by ID: "
for sibling in workpackage.iteration_siblings:
sibling_str += "{}".format(sibling.id)
print(sibling_str)
print("")
# Print parameterization
print("Parameterization:")
for parameter in workpackage.parameterset:
if parameter.name != "id":
print(" {0}: {1}".format(parameter.name, parameter.value))
print("")
# Print environments
if workpackage.env:
env_str = ""
for env_name, value in workpackage.env.items():
if (env_name not in ["PWD", "OLDPWD", "_"]) and \
(env_name not in os.environ or os.environ[env_name] != value):
env_str += " {0}: {1}\n".format(env_name, value)
if env_str:
print("Environment:")
print(env_str)
print("")
if os.environ:
env_str = ""
for env_name in os.environ:
if (env_name not in ["PWD", "OLDPWD", "_"]) and \
(env_name not in workpackage.env):
env_str += " {0}\n".format(env_name)
if env_str:
print("Environment:")
print(env_str)
print("")
[docs]def print_benchmark_status(benchmark):
"""Print overall workpackage status in the following order
RUNNING: At least one WP is still active
ERROR: At least one WP raised an errror
FINISHED: All WPs are finalized and no error was raised
"""
error = False
running = False
for step_name in benchmark.workpackages:
for workpackage in benchmark.workpackages[step_name]:
running = \
(not workpackage.done and not workpackage.error) or running
error = workpackage.error or error
if running:
print("RUNNING")
elif error:
print("ERROR")
else:
print("FINISHED")