Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions engine/performance.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,36 +23,36 @@

@click.command()
@click.option(
"--timing-regex",
help=cli_help["timing_regex"],
"--log_file",
help=cli_help["log_file"],
)
@click.option(
"--timing-database",
help=cli_help["timing_database"],
)
@click.option("--append-time", help=cli_help["append_time"], type=bool, default=False)
def performance(timing_regex, timing_database, append_time):
timing_file_name_base, timing_regex = os.path.split(timing_regex)
def performance(log_file, timing_database, append_time):
timing_file_name_base, log_file = os.path.split(log_file)
if timing_file_name_base == "":
timing_file_name_base = "."

timing_file_name, err = file_names_from_pattern(timing_file_name_base, timing_regex)
timing_file_name, err = file_names_from_pattern(timing_file_name_base, log_file)
if err > 0:
logger.info("Did not find any files for regex %s", timing_regex)
logger.info("Did not find any files for regex %s", log_file)
sys.exit(1)

if len(timing_file_name) > 1:
logger.critical(
"Found too many files for regex '%s' in '%s':",
timing_regex,
log_file,
timing_file_name_base,
)
for tf in timing_file_name:
logger.critical(tf)
sys.exit(1)
else:
timing_file_name = timing_file_name_base + "/" + timing_file_name[0]
logger.info("Found timing file %s for regex %s", timing_file_name, timing_regex)
logger.info("Found timing file %s for regex %s", timing_file_name, log_file)

tt = TimingTree.from_logfile(timing_file_name, read_logfile)

Expand Down
502 changes: 257 additions & 245 deletions poetry.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pathlib = ">=1.0.1"
pandas = ">=2.2.3"
regex = ">=2024.11.6"
xarray = ">=2024.11.0"
types-python-dateutil = "^2.9.0"

[tool.mypy]
allow_untyped_defs = true
Expand Down
260 changes: 128 additions & 132 deletions requirements.txt

Large diffs are not rendered by default.

210 changes: 112 additions & 98 deletions requirements_dev.txt

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion templates/ICON.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
},
"performance":
{
"timing_regex": "{{codebase_install}}/run/LOG.exp.{{experiment_name}}.*",
"log_file": "{{codebase_install}}/run/LOG.exp.{{experiment_name}}.*",
"timing_names": ["integrate_nh", "nh_solve", "physics"],
"timing_database": "{{codebase_install}}/database",
"append_time": "{{append_time}}"
Expand Down
2 changes: 1 addition & 1 deletion templates/testdata.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"current_files": "{{reference}}/reference/{{experiment_name}}_{{member_id[1] if member_id|length>1 else 2}}.csv"
},
"performance": {
"timing_regex": "{{codebase_install}}/{{experiment_name}}/LOG.exp.{{experiment_name}}.run.12345678.o",
"log_file": "{{codebase_install}}/{{experiment_name}}/LOG.exp.{{experiment_name}}.run.12345678.o",
"timing_names": ["integrate_nh", "nh_solve", "physics"],
"timing_database": "{{reference}}/performance/{{experiment_name}}"
},
Expand Down
2 changes: 1 addition & 1 deletion tests/data/reference_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
37,
48
]
}
}
4 changes: 2 additions & 2 deletions tests/data/timing_example_3.txt
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ no_of_models=1
libpcre.so.1 => /usr/lib64/libpcre.so.1 (0x0000145b27b03000)
+ rm -f finish.status
+ date
Wed 28 Jun 2023 04:42:35 PM CEST
Fri 30 Jan 16:13:34 CET 2026
+ set -x
+ srun -n 4 --ntasks-per-node 4 '--threads-per-core=1' '--distribution=cyclic' /scratch/e1000/meteoswiss/scratch/huppd/add_performance_test/mch_gpu_mixed_v0.18.1.6/run/run_wrapper/balfrin_gpu.sh /scratch/e1000/meteoswiss/scratch/huppd/add_performance_test/mch_gpu_mixed_v0.18.1.6/bin/icon

Expand Down Expand Up @@ -4411,7 +4411,7 @@ input results for domain 1:
mo_atmo_model:destruct_atmo_model: destruct_patches is done
mo_atmo_model:destruct_atmo_model: clean-up finished
+ set +x
Wed 28 Jun 2023 04:42:57 PM CEST
Fri 30 Jan 16:16:34 CET 2026
OK
============================
Script run successfully: OK
Expand Down
6 changes: 3 additions & 3 deletions tests/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,10 @@ def assert_empty_df(df, msg):
assert len(df.values) == 0, f"{msg}:\n{df}"


def run_performance_cli(timing_regex, timing_database):
def run_performance_cli(log_file, timing_database):
args = [
"--timing-regex",
timing_regex,
"--log_file",
log_file,
"--timing-database",
timing_database,
]
Expand Down
6 changes: 4 additions & 2 deletions util/click_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,11 @@ def convert(self, value, param, ctx):
"current_files": r"List of current files to be tested, "
+ r"both for stats and fof files",
"factor": r"Relaxation factor for the tolerance values.",
"timing_regex": r"Regex for the file that contains the latest log.",
"log_file": r"Regex for the file that contains the latest log.",
"timing_names": r"The name of the timing entries to be displayed.",
"timing_database": r"A persistent file to keep track of performance history.",
"timing_database": r"Path to the timing database files used for performance "
+ r"reference or performance checks. This consists of three files (_meta.json, "
+ r"_0_tree.json, _0_meta.json) that store timing information.",
"append_time": r"If true: append to the performance data; If false: overwrite the "
+ r"performance data (default: false).",
"run_dir": r"Directory from where the run is started "
Expand Down
69 changes: 24 additions & 45 deletions util/icon/extract_timings.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,52 +5,27 @@

import re
import sys
from datetime import datetime

import numpy as np
from dateutil.parser import ParserError
from dateutil.parser import parse as parse_date

from util.constants import DATETIME_FORMAT
from util.log_handler import logger

TIMING_START_REGEX = r"(?: +L? ?[a-zA-Z_.]+)"
TIMING_START_REGEX = r"\s+L?\s*[a-zA-Z_.]+"
TIMING_ELEMENT_REGEX = r"(?:\[?\d+[.msh]?\d*s?\]? +)"
TIMING_REGEX = TIMING_START_REGEX + " +" + TIMING_ELEMENT_REGEX + "{6,20} *(?!.)"
TIMING_REGEX = TIMING_START_REGEX + r"\s+(?:" + TIMING_ELEMENT_REGEX + r"){6,20} *(?!.)"
HEADER_REGEX = r"name +.*calls.*"
INDENT_REGEX = r"^ *L? "
HOUR_REGEX = r"(\d+)h(\d+)m(\d+)s"
MINUTE_REGEX = r"(\d+[.]?\d*)m(\d+[.]?\d*)s"
SEC_REGEX = r"(\d+[.]?\d*)s"
NUMBER_REGEX = r"(\d+[.]?\d*)"

dateline_regexs = (
r"(?:[A-Z][a-z]{2} +){2}\d{1,2} \d{2}:\d{2}:\d{2} [A-Z]{3,4} 20\d{2}",
(
r"(?:[A-Z][a-z]{2} +)\d{1,2} (?:[A-Z][a-z]{2} +)20\d{2} \d{2}:\d{2}:\d{2} "
"[A-Z]{2} [A-Z]{3,4}"
),
)
icon_date_formats = ("%a %b %d %H:%M:%S %Z %Y", "%a %d %b %Y %H:%M:%S %p %Z")

DICT_REGEX = r"^\s*{} *: *(.*)"


def _convert_dateline_to_start_end_datetime(dateline, icon_date_format):
# LOG.check files have more dates than we need
# The dates we are interested in are always at the same position relative to the
# other dates
if len(dateline) > 2:
dateline = [dateline[1], dateline[2]]
start_time, finish_time = dateline

finish_datetime = datetime.strptime(finish_time, icon_date_format)
finish_datetime_converted = finish_datetime.strftime(DATETIME_FORMAT)

start_datetime = datetime.strptime(start_time, icon_date_format)
start_datetime_converted = start_datetime.strftime(DATETIME_FORMAT)

return (start_datetime_converted, finish_datetime_converted)


def read_logfile(filename):
with open(filename, "r", encoding="latin-1") as f:
# read file into list of lines, remove empty lines
Expand Down Expand Up @@ -121,22 +96,26 @@ def read_logfile(filename):
meta_data = {}

# get start and finish time from job
found_dateline_yes = False
start_datetime_converted = ""
finish_datetime_converted = ""
for dateline_regex, icon_date_format in zip(dateline_regexs, icon_date_formats):
dateline = re.findall(dateline_regex, full_file)

if dateline:
(
start_datetime_converted,
finish_datetime_converted,
) = _convert_dateline_to_start_end_datetime(dateline, icon_date_format)
found_dateline_yes = True
if not found_dateline_yes:
raise Exception("Could not match any regex for start and end time.")
meta_data["start_time"] = start_datetime_converted
meta_data["finish_time"] = finish_datetime_converted
# --- robust start/finish datetime extraction ---

datelines = []

for line in full_file.splitlines():
if line.count(":") >= 2:
try:
dt = parse_date(line, fuzzy=False)
datelines.append(dt)
except (ParserError, ValueError):
continue

if len(datelines) < 2:
raise Exception("Could not robustly determine start and finish time.")

start_dt = datelines[0]
finish_dt = datelines[-1]

meta_data["start_time"] = start_dt.strftime(DATETIME_FORMAT)
meta_data["finish_time"] = finish_dt.strftime(DATETIME_FORMAT)

# get meta data from ICON log (in the form "Key : Value")
revision = re.search(
Expand Down