Skip to content

Commit 13c19fb

Browse files
authored
benchmarking: generate stable nightly session names (#2115)
Signed-off-by: rlratzel <rratzel@nvidia.com>
1 parent 97a7172 commit 13c19fb

2 files changed

Lines changed: 38 additions & 17 deletions

File tree

benchmarking/tools/ci_benchmark_launcher.sh

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,12 @@ cd /opt/Curator
2828
uv pip install GitPython pynvml pyyaml rich
2929

3030
# Session name resolution:
31-
# - If NEMO_CI_SESSION_NAME is set by the launcher, use it verbatim.
32-
# - Else if this is a scheduled (cron) nightly pipeline, generate nightly-<TS>.
33-
# Generated benchmark jobs can run in child/grandchild pipelines where
34-
# CI_PIPELINE_SOURCE is parent_pipeline, so also check PARENT_PIPELINE_SOURCE.
31+
# - If NEMO_CI_SESSION_NAME is set by the generated benchmark pipeline, use it
32+
# verbatim so every benchmark job writes to the same session directory.
3533
# - Else fall back to the legacy benchmark_run_<pipeline-id> name so existing
3634
# manual launches via launch_pipeline.py keep producing the same paths.
37-
PIPELINE_SOURCE="${CI_PIPELINE_SOURCE:-}"
38-
PARENT_SOURCE="${PARENT_PIPELINE_SOURCE:-}"
3935
if [ -n "${NEMO_CI_SESSION_NAME:-}" ]; then
4036
SESSION_NAME="${NEMO_CI_SESSION_NAME}"
41-
elif [ "${PIPELINE_SOURCE}" = "schedule" ] || [ "${PARENT_SOURCE}" = "schedule" ]; then
42-
SESSION_NAME="nightly-$(date -u +%Y_%m_%d__%H_%M_%S_UTC)"
4337
else
4438
SESSION_NAME="benchmark_run_${CI_PIPELINE_ID}"
4539
fi

benchmarking/tools/generate_ci_tests.py

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
# limitations under the License.
1414

1515
import argparse
16+
import datetime as dt
17+
import os
18+
from collections.abc import Mapping
1619
from pathlib import Path
1720

1821
from ruamel.yaml import YAML
@@ -44,10 +47,30 @@ def seconds_to_time(seconds: int) -> str:
4447
return f"{hours:02d}:{minutes:02d}:{secs:02d}"
4548

4649

50+
def _pipeline_timestamp(created_at: str | None) -> str:
51+
"""Return a path-safe UTC timestamp for generated nightly session names."""
52+
if created_at:
53+
try:
54+
parsed = dt.datetime.fromisoformat(created_at)
55+
return parsed.astimezone(dt.UTC).strftime("%Y_%m_%d__%H_%M_%S_UTC")
56+
except ValueError:
57+
pass
58+
return dt.datetime.now(dt.UTC).strftime("%Y_%m_%d__%H_%M_%S_UTC")
4759

48-
def generate_job(
49-
entry: dict, scope: str, default_timeout_s: int, cleanup_timeout_s: int, min_timeout_s: int
50-
) -> dict:
60+
61+
def session_name_from_env(env: Mapping[str, str] = os.environ) -> str | None:
62+
"""Return the generated-pipeline session name, if this run should define one."""
63+
explicit = env.get("NEMO_CI_SESSION_NAME", "").strip()
64+
if explicit:
65+
return explicit
66+
67+
if env.get("CI_PIPELINE_SOURCE") == "schedule" or env.get("PARENT_PIPELINE_SOURCE") == "schedule":
68+
return f"nightly-{_pipeline_timestamp(env.get('CI_PIPELINE_CREATED_AT'))}"
69+
70+
return None
71+
72+
73+
def generate_job(entry: dict, scope: str, default_timeout_s: int, cleanup_timeout_s: int, min_timeout_s: int) -> dict:
5174
"""
5275
Generate a GitLab CI job for a single benchmark entry.
5376
@@ -79,13 +102,14 @@ def generate_job(
79102
}
80103

81104

82-
def generate_pipeline(curator_dir: str, scope: str) -> dict:
105+
def generate_pipeline(curator_dir: str, scope: str, session_name: str | None = None) -> dict:
83106
"""
84107
Generate a GitLab CI pipeline from Curator benchmark entries.
85108
86109
Args:
87110
curator_dir: Path to the Curator repository
88111
scope: Scope of the testing (nightly, release, test)
112+
session_name: Optional session name to set for all generated benchmark jobs
89113
90114
Returns:
91115
pipeline: Dictionary defining the GitLab CI pipeline
@@ -104,6 +128,8 @@ def generate_pipeline(curator_dir: str, scope: str) -> dict:
104128
pipeline = {
105129
"include": ["curator/curator_ci_template.yml"],
106130
}
131+
if session_name:
132+
pipeline["variables"] = {"NEMO_CI_SESSION_NAME": session_name}
107133

108134
entries = config.get("entries", [])
109135
job_count = 0
@@ -122,9 +148,7 @@ def generate_pipeline(curator_dir: str, scope: str) -> dict:
122148

123149

124150
def main() -> None:
125-
parser = argparse.ArgumentParser(
126-
description="Generate GitLab CI jobs for Curator benchmarks"
127-
)
151+
parser = argparse.ArgumentParser(description="Generate GitLab CI jobs for Curator benchmarks")
128152
parser.add_argument(
129153
"--curator-dir",
130154
type=str,
@@ -140,14 +164,17 @@ def main() -> None:
140164

141165
args = parser.parse_args()
142166

143-
pipeline = generate_pipeline(args.curator_dir, args.scope)
167+
session_name = session_name_from_env()
168+
pipeline = generate_pipeline(args.curator_dir, args.scope, session_name=session_name)
144169

145170
output_file = "generated_curator_benchmark_tests.yml"
146171
with open(output_file, "w") as f:
147172
yaml.dump(pipeline, f)
148173

149-
job_count = len([k for k in pipeline if k != "include"])
174+
job_count = len([k for k in pipeline if k not in {"include", "variables"}])
150175
print(f"Generated pipeline with {job_count} jobs -> {output_file}")
176+
if session_name:
177+
print(f"Using benchmark session name: {session_name}")
151178

152179

153180
if __name__ == "__main__":

0 commit comments

Comments
 (0)