Skip to content

Commit b081728

Browse files
committed
#582: Add JSON task lister util script
1 parent 1fb6416 commit b081728

File tree

1 file changed

+126
-0
lines changed

1 file changed

+126
-0
lines changed
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
#
2+
#@HEADER
3+
###############################################################################
4+
#
5+
# lbsJSONTaskLister.py
6+
# DARMA/LB-analysis-framework => LB Analysis Framework
7+
#
8+
# Copyright 2019-2024 National Technology & Engineering Solutions of Sandia, LLC
9+
# (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S.
10+
# Government retains certain rights in this software.
11+
#
12+
# Redistribution and use in source and binary forms, with or without
13+
# modification, are permitted provided that the following conditions are met:
14+
#
15+
# * Redistributions of source code must retain the above copyright notice,
16+
# this list of conditions and the following disclaimer.
17+
#
18+
# * Redistributions in binary form must reproduce the above copyright notice,
19+
# this list of conditions and the following disclaimer in the documentation
20+
# and/or other materials provided with the distribution.
21+
#
22+
# * Neither the name of the copyright holder nor the names of its
23+
# contributors may be used to endorse or promote products derived from this
24+
# software without specific prior written permission.
25+
#
26+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36+
# POSSIBILITY OF SUCH DAMAGE.
37+
#
38+
# Questions? Contact [email protected]
39+
#
40+
###############################################################################
41+
#@HEADER
42+
#
43+
"""
44+
Utility to generate a yaml containing lists of tasks associated to their respective ranks,
45+
from the last phase and last sub-iteration of input JSON files.
46+
47+
"""
48+
49+
import os
50+
import sys
51+
import json
52+
import yaml
53+
import argparse
54+
import re
55+
56+
from lbaf.IO.lbsVTDataReader import LoadReader
57+
from lbaf.Utils.lbsLogging import get_logger, Logger
58+
59+
def process_files(directory, file_stem, file_suffix, logger: Logger):
60+
reader = LoadReader(
61+
file_prefix = directory + file_stem,
62+
logger = logger,
63+
file_suffix = file_suffix
64+
)
65+
66+
tasks = {}
67+
n_ranks = reader.n_ranks
68+
69+
try:
70+
for rank in range(n_ranks):
71+
_, data = reader._load_vt_file(rank)
72+
phases = data.get("phases", [])
73+
if not phases:
74+
logger.warning("No phases found for rank %s", str(rank))
75+
continue
76+
77+
last_phase = phases[-1]
78+
79+
if "lb_iterations" in last_phase:
80+
lb_iterations = last_phase["lb_iterations"]
81+
if lb_iterations:
82+
last_lb_iteration = lb_iterations[-1]
83+
iteration_tasks = [task["entity"].get("seq_id", task["entity"].get("id")) for task in last_lb_iteration.get("tasks", [])]
84+
tasks[rank] = iteration_tasks
85+
else:
86+
logger.warning("No lb_iterations found in the last phase of rank %s", str(rank))
87+
else:
88+
phase_tasks = [task["entity"].get("seq_id", task["entity"].get("id")) for task in last_phase.get("tasks", [])]
89+
tasks[rank] = phase_tasks
90+
except (json.JSONDecodeError, KeyError, ValueError, IndexError) as e:
91+
logger.error("Error processing rank %s: %s", str(rank), e)
92+
sys.exit(1)
93+
94+
return tasks
95+
96+
def main():
97+
parser = argparse.ArgumentParser(description="Extract tasks from JSON files.")
98+
parser.add_argument("directory", type=str, help="Directory containing JSON files.")
99+
parser.add_argument("--file-stem", type=str, default="data", help="File stem for JSON files (default: 'data').")
100+
parser.add_argument("--file-suffix", type=str, default="json", help="File suffix for JSON files (default: 'json').")
101+
parser.add_argument("--output", type=str, default="tasks.yml", help="Output YAML file (default: 'tasks.yml').")
102+
103+
args = parser.parse_args()
104+
105+
directory = args.directory
106+
file_stem = args.file_stem
107+
file_suffix = args.file_suffix
108+
output_file = args.output
109+
110+
logger = get_logger()
111+
112+
if not os.path.isdir(directory):
113+
logger.error("Directory not found: %s", directory)
114+
return
115+
116+
tasks = process_files(directory, file_stem, file_suffix, logger)
117+
118+
try:
119+
with open(output_file, 'w') as file:
120+
yaml.safe_dump(tasks, file)
121+
logger.info("Tasks successfully written to %s", output_file)
122+
except IOError as e:
123+
logger.error("Error writing to %s: %s", output_file, e)
124+
125+
if __name__ == "__main__":
126+
main()

0 commit comments

Comments
 (0)