|
1 | 1 | #!/usr/bin/env python3
|
2 | 2 | """
|
3 |
| -ESMF Profiling tool |
| 3 | +ESMF Profiling tool - OM3 |
4 | 4 | The ESMF Profiling tool is a Python-based tool designed to read and process
|
5 | 5 | performance profile data from ESMF profiling log files. It provides a
|
6 | 6 | structured way to extract hierachical timing and computational stats for
|
@@ -52,6 +52,7 @@ def collect_runtime_tot(
|
52 | 52 | esmf_summary=True,
|
53 | 53 | index=2,
|
54 | 54 | ):
|
| 55 | + |
55 | 56 | runtime_tot = []
|
56 | 57 | for i in range(len(ESMF_path)):
|
57 | 58 | subfiles_path = _list_esmf_files(
|
@@ -95,63 +96,77 @@ def _list_esmf_files(dir_path, profile_prefix, esmf_summary, summary_profile):
|
95 | 96 | except FileNotFoundError:
|
96 | 97 | warnings.warn(f"Directory {dir_path} does not exist! Skipping!")
|
97 | 98 | matching_files_path = []
|
98 |
| - |
99 | 99 | return matching_files_path
|
100 | 100 |
|
101 | 101 |
|
102 | 102 | def _region_time_consumption(regionNames, esmf_region_all, index, esmf_summary):
|
103 |
| - """Calculates time consumption for specific regions.""" |
| 103 | + """Calculates time consumption for specific regions""" |
104 | 104 | runtime = {}
|
105 |
| - for varname in regionNames: |
106 |
| - runtime[varname] = [ |
107 |
| - _find_region_value(sub_ESMF_region, varname, esmf_summary)[0][index] |
| 105 | + |
| 106 | + for regionName in regionNames: |
| 107 | + region_values = [ |
| 108 | + _find_region_values(sub_ESMF_region, regionName, esmf_summary) |
108 | 109 | for sub_ESMF_region in esmf_region_all
|
109 | 110 | ]
|
| 111 | + |
| 112 | + # Process each region value |
| 113 | + for region_value in region_values: |
| 114 | + for key, val in region_value.items(): |
| 115 | + if val and val[0] is not None: |
| 116 | + if key not in runtime: |
| 117 | + runtime[key] = [] |
| 118 | + runtime[key].append(val[index]) |
110 | 119 | return runtime
|
111 | 120 |
|
112 | 121 |
|
113 |
| -def _find_region_value(region, target_region, esmf_summary): |
114 |
| - """Recursively searches for a region value based on its hierarchical path.""" |
| 122 | +def _find_region_values(region, target_region, esmf_summary): |
| 123 | + """ |
| 124 | + Searches for all region values based on a hierarchical path prefix. |
| 125 | + """ |
115 | 126 | target_parts = target_region.split("/")
|
| 127 | + matches = {} |
116 | 128 | default_nans = (None,) * 6
|
117 | 129 |
|
118 |
| - if not target_parts: |
119 |
| - return default_nans, False |
120 |
| - |
121 |
| - if region.name == target_parts[0]: |
122 |
| - if len(target_parts) == 1: |
123 |
| - if not esmf_summary: |
124 |
| - return ( |
125 |
| - region.count, |
126 |
| - region.total, |
127 |
| - region.self_time, |
128 |
| - region.mean, |
129 |
| - region.min_time, |
130 |
| - region.max_time, |
131 |
| - ), True |
132 |
| - else: |
133 |
| - return ( |
134 |
| - region.count, |
135 |
| - region.PETs, |
136 |
| - region.mean, |
137 |
| - region.min_time, |
138 |
| - region.max_time, |
139 |
| - region.min_PET, |
140 |
| - region.max_PET, |
141 |
| - ), True |
142 |
| - |
143 |
| - for child in region.children: |
144 |
| - result, found = _find_region_value( |
145 |
| - child, "/".join(target_parts[1:]), esmf_summary |
| 130 | + def search_region(region, path, current_path): |
| 131 | + """Recursive helper function to search regions.""" |
| 132 | + if region.name.startswith(path[0]): |
| 133 | + if len(path) == 1: |
| 134 | + matches[current_path] = _get_region_data(region, esmf_summary) |
| 135 | + return |
| 136 | + |
| 137 | + # Continue searching in children if more path components remain |
| 138 | + for child in region.children: |
| 139 | + search_region(child, path[1:], f"{current_path}/{child.name}") |
| 140 | + |
| 141 | + def _get_region_data(region, esmf_summary): |
| 142 | + """Returns the region data tuple based on esmf_summary setting.""" |
| 143 | + return ( |
| 144 | + ( |
| 145 | + region.count, |
| 146 | + region.total, |
| 147 | + region.self_time, |
| 148 | + region.mean, |
| 149 | + region.min_time, |
| 150 | + region.max_time, |
| 151 | + ) |
| 152 | + if not esmf_summary |
| 153 | + else ( |
| 154 | + region.count, |
| 155 | + region.PETs, |
| 156 | + region.mean, |
| 157 | + region.min_time, |
| 158 | + region.max_time, |
| 159 | + region.min_PET, |
| 160 | + region.max_PET, |
146 | 161 | )
|
147 |
| - if found: |
148 |
| - return result, found |
| 162 | + ) |
| 163 | + |
| 164 | + # recursive search |
| 165 | + search_region(region, target_parts, region.name) |
149 | 166 |
|
150 |
| - for child in region.children: |
151 |
| - result, found = _find_region_value(child, target_region, esmf_summary) |
152 |
| - if found: |
153 |
| - return result, found |
154 |
| - return default_nans, False |
| 167 | + if not matches: |
| 168 | + print(f"No matches found for target prefix: {target_region}") |
| 169 | + return matches if matches else {f"{target_region}": default_nans} |
155 | 170 |
|
156 | 171 |
|
157 | 172 | class ESMFProfileTrees(object):
|
@@ -231,7 +246,11 @@ def _parse_line(self, line):
|
231 | 246 | ]
|
232 | 247 | runtime_tot = collect_runtime_tot(
|
233 | 248 | ESMF_path,
|
234 |
| - regionNames=["[ESMF]"], |
| 249 | + regionNames=[ |
| 250 | + "[ESMF]", |
| 251 | + "[ESMF]/[ensemble] RunPhase1/[ESM0001] RunPhase1/[OCN] RunPhase1", |
| 252 | + "[ESMF]/[ensemble] RunPhase1/[ESM0001] RunPhase1/[MED]", |
| 253 | + ], |
235 | 254 | profile_prefix="ESMF_Profile.",
|
236 | 255 | esmf_summary=True,
|
237 | 256 | index=2,
|
|
0 commit comments