Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add profiling utilities #3

Merged
merged 6 commits into from
May 14, 2024
Merged
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
68 changes: 68 additions & 0 deletions om3utils/esmf_profiling.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"""ESMF profiling data parser."""

from pathlib import Path

Check warning on line 3 in om3utils/esmf_profiling.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_profiling.py#L3

Added line #L3 was not covered by tests

from om3utils.profiling import ProfilingParser
from om3utils.esmf_trace import ESMFTrace, MultiPETTimingNode

Check warning on line 6 in om3utils/esmf_profiling.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_profiling.py#L5-L6

Added lines #L5 - L6 were not covered by tests


class ESMFProfilingParser(ProfilingParser):

Check warning on line 9 in om3utils/esmf_profiling.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_profiling.py#L9

Added line #L9 was not covered by tests
"""Defines a ProfilingParser for ESMF profiling data.

ESMF generates traces in the Common Trace Format (CTF), one trace per parallel element (core, thread, etc). This
parser reads those traces and converts them into a tree of timing nodes, each node corresponding to a profiling
region.
"""

def __init__(self, dirname):
super().__init__()

Check warning on line 18 in om3utils/esmf_profiling.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_profiling.py#L17-L18

Added lines #L17 - L18 were not covered by tests

# ESMF provides the following metrics:
self._metrics = ["hits", "tmin", "tmax", "tavg", "ttot"]
self._dirname = dirname

Check warning on line 22 in om3utils/esmf_profiling.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_profiling.py#L21-L22

Added lines #L21 - L22 were not covered by tests

@property
def metrics(self) -> list:
return self._metrics

Check warning on line 26 in om3utils/esmf_profiling.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_profiling.py#L24-L26

Added lines #L24 - L26 were not covered by tests

def read(self, path: Path) -> dict:

Check warning on line 28 in om3utils/esmf_profiling.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_profiling.py#L28

Added line #L28 was not covered by tests
"""Given a file path, returns a dictionary holding the parsed data.

Args:
path (Path): File to parse.

Returns:
dict: Profiling data.
"""
profiling_dir = path / self._dirname
if not profiling_dir.is_dir():
raise FileNotFoundError(f"Directory not found: {profiling_dir.as_posix()}")

Check warning on line 39 in om3utils/esmf_profiling.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_profiling.py#L37-L39

Added lines #L37 - L39 were not covered by tests

trace = ESMFTrace(profiling_dir)

Check warning on line 41 in om3utils/esmf_profiling.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_profiling.py#L41

Added line #L41 was not covered by tests

stats = {"region": trace.regions}
stats.update({key: [0] * len(trace.regions) for key in self.metrics})

Check warning on line 44 in om3utils/esmf_profiling.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_profiling.py#L43-L44

Added lines #L43 - L44 were not covered by tests

for name, child in trace.multiPETTree.children.items():
self._add_node_stats(child, name, stats)

Check warning on line 47 in om3utils/esmf_profiling.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_profiling.py#L46-L47

Added lines #L46 - L47 were not covered by tests

return stats

Check warning on line 49 in om3utils/esmf_profiling.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_profiling.py#L49

Added line #L49 was not covered by tests

def _add_node_stats(self, node: MultiPETTimingNode, name: str, stats: dict):

Check warning on line 51 in om3utils/esmf_profiling.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_profiling.py#L51

Added line #L51 was not covered by tests
"""For a given timing node, compute and collect the relevant statistics (e.g. the total time spent in a region).
Once done, do the same for each node child, such that we traverse the whole timing tree.

Args:
node (MultiPETTimingNode): Timing node.
name (str): Name of the region.
stats(dict): Profiling statistics.
"""
index = stats["region"].index(name)
stats["hits"][index] += node.count_each
stats["tmin"][index] += node.total_min_s
stats["tmax"][index] += node.total_max_s
stats["tavg"][index] += node.total_mean_s
stats["ttot"][index] += node.total_sum_s

Check warning on line 65 in om3utils/esmf_profiling.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_profiling.py#L60-L65

Added lines #L60 - L65 were not covered by tests

for name, child in node.children.items():
self._add_node_stats(child, name, stats)

Check warning on line 68 in om3utils/esmf_profiling.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_profiling.py#L67-L68

Added lines #L67 - L68 were not covered by tests
322 changes: 322 additions & 0 deletions om3utils/esmf_trace.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,322 @@
"""Classes to represent timing trees as produced by ESMF when running in profiling mode.

ESMF can output an execution trace using the Common Trace Format (CTF). Full CTF documentation can be found online at
https://diamon.org/ctf/, but in a nutshell, CFT is a very flexible binary trace format. A reference parser
implementation of CTF is provided by the Babeltrace 2 library (https://babeltrace.org/), which also includes Python 3
bindings.

Note that most of the contents of this file are based on the code from esmf-profiler (https://github.com/esmf-org/esmf-profiler).
"""

import sys
from pathlib import Path

Check warning on line 12 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L11-L12

Added lines #L11 - L12 were not covered by tests

import bt2

Check warning on line 14 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L14

Added line #L14 was not covered by tests

from om3utils.utils import nano_to_sec

Check warning on line 16 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L16

Added line #L16 was not covered by tests


class SinglePETTimingNode:

Check warning on line 19 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L19

Added line #L19 was not covered by tests
"""Representation of a single PET timing node in a tree of profiling events.

One node corresponds to one profiling region and one PET (Persistent Execution Thread) and it can have
child regions, which are store in a list. This allows to create a tree of regions.

Furthermore, the root node of a tree (id = 0) also stores a dictionary of all the regions that exist in that tree.
This allows to efficiently append a new node to the tree.
"""

def __init__(self, _id: int, pet: int, name: str):

Check warning on line 29 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L29

Added line #L29 was not covered by tests
"""

Args:
_id (int): Region ID.
pet (int): PET number.
name (str): Region name.
"""
self._id = _id
self._pet = pet
self._name = name
self._total = 0
self._min = sys.maxsize
self._max = 0
self._mean = 0
self._count = 0
self._children = [] # Children that have this node as direct parent

Check warning on line 45 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L37-L45

Added lines #L37 - L45 were not covered by tests

# Cache containing all of this node's children, direct or indirect, that is, all the nodes that belong to the
# tree that have this node as root. Note that only the root node of the tree maintains a cache (self._id = 0)
self._child_cache = {} # id -> SinglePetTimingTreeNode
if self._id == 0:
self._child_cache[self._id] = self

Check warning on line 51 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L49-L51

Added lines #L49 - L51 were not covered by tests

@property
def name(self):

Check warning on line 54 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L53-L54

Added lines #L53 - L54 were not covered by tests
"""str: Name of profiling region."""
return self._name

Check warning on line 56 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L56

Added line #L56 was not covered by tests

@property
def pet(self):

Check warning on line 59 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L58-L59

Added lines #L58 - L59 were not covered by tests
"""int: PET number."""
return self._pet

Check warning on line 61 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L61

Added line #L61 was not covered by tests

@property
def total(self):

Check warning on line 64 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L63-L64

Added lines #L63 - L64 were not covered by tests
"""float: Total time spent in the region, in nanoseconds."""
return self._total

Check warning on line 66 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L66

Added line #L66 was not covered by tests

@total.setter
def total(self, value):
self._total = value

Check warning on line 70 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L68-L70

Added lines #L68 - L70 were not covered by tests

@property
def count(self):

Check warning on line 73 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L72-L73

Added lines #L72 - L73 were not covered by tests
"""int: Number of times this region was executed."""
return self._count

Check warning on line 75 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L75

Added line #L75 was not covered by tests

@count.setter
def count(self, value):
self._count = value

Check warning on line 79 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L77-L79

Added lines #L77 - L79 were not covered by tests

@property
def min(self):

Check warning on line 82 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L81-L82

Added lines #L81 - L82 were not covered by tests
"""float: Minimum time spent in the region, in nanoseconds."""
return self._min

Check warning on line 84 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L84

Added line #L84 was not covered by tests

@min.setter
def min(self, value):
self._min = value

Check warning on line 88 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L86-L88

Added lines #L86 - L88 were not covered by tests

@property
def max(self):

Check warning on line 91 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L90-L91

Added lines #L90 - L91 were not covered by tests
"""float: Maximum time spent in the region, in nanoseconds."""
return self._max

Check warning on line 93 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L93

Added line #L93 was not covered by tests

@max.setter
def max(self, value):
self._max = value

Check warning on line 97 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L95-L97

Added lines #L95 - L97 were not covered by tests

@property
def mean(self):

Check warning on line 100 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L99-L100

Added lines #L99 - L100 were not covered by tests
"""float: Mean time spent in the region, in nanoseconds."""
return self._mean

Check warning on line 102 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L102

Added line #L102 was not covered by tests

@mean.setter
def mean(self, value):
self._mean = value

Check warning on line 106 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L104-L106

Added lines #L104 - L106 were not covered by tests

@property
def children(self):

Check warning on line 109 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L108-L109

Added lines #L108 - L109 were not covered by tests
"""list: Children that have this node as direct parent"""
return self._children

Check warning on line 111 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L111

Added line #L111 was not covered by tests

#
def add_child(self, parentid, child: "SinglePETTimingNode"):

Check warning on line 114 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L114

Added line #L114 was not covered by tests
"""Add child node to the node with given parentid.

Note that it must be called only from the root of the tree (self._id == 0).

Args:
parentid (int): Parent region ID.
child (SinglePETTimingNode): Child to add.

Returns:
bool: Execution status.
"""
self._child_cache[parentid]._children.append(child)
self._child_cache[child._id] = child
return True

Check warning on line 128 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L126-L128

Added lines #L126 - L128 were not covered by tests


class MultiPETTimingNode:

Check warning on line 131 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L131

Added line #L131 was not covered by tests
"""Representation of a multi-PET timing node in a tree of profiling events.

One node corresponds to one profiling region executed by one or more PETs. The tree is constructed by merging
single-PET timing trees. The multi-PET statistics are computed and updated every time a new single-PET timing tree
is merged into the multi-PET tree.
"""

def __init__(self):
self._children: dict[str, MultiPETTimingNode] = (

Check warning on line 140 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L139-L140

Added lines #L139 - L140 were not covered by tests
{}
) # sub-regions in the timing tree { name -> MultiPETTimingNode }
self._pet_count = 0 # the number of PETs reporting timing information for this node
self._count_each = -1 # how many times each PET called into this region
self._counts_match = True # if counts_each is not the same for all reporting PETs, then this is False
self._total_sum = 0 # sum of all totals
self._total_min = sys.maxsize # min of all totals
self._total_min_pet = -1 # PET with min total
self._total_max = 0 # max of all totals
self._total_max_pet = -1 # PET with max total
self._contributing_nodes = {} # map of contributing SinglePETTimingNodes (key = PET)

Check warning on line 151 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L143-L151

Added lines #L143 - L151 were not covered by tests

@property
def pet_count(self):

Check warning on line 154 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L153-L154

Added lines #L153 - L154 were not covered by tests
"""int: Number of PETs reporting timing information for this node."""
return self._pet_count

Check warning on line 156 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L156

Added line #L156 was not covered by tests

@property
def count_each(self):

Check warning on line 159 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L158-L159

Added lines #L158 - L159 were not covered by tests
"""int: How many times each PET is called into this region.

Note that this value is only meaningful if self.counts_match is true.
"""
return self._count_each

Check warning on line 164 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L164

Added line #L164 was not covered by tests

@property
def counts_match(self):

Check warning on line 167 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L166-L167

Added lines #L166 - L167 were not covered by tests
"""bool: Is the value of counts_each the same for all reporting PETs?"""
return self._counts_match

Check warning on line 169 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L169

Added line #L169 was not covered by tests

@property
def total_sum(self):

Check warning on line 172 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L171-L172

Added lines #L171 - L172 were not covered by tests
"""float: Sum of all totals from all PETs, in nanoseconds."""
return self._total_sum

Check warning on line 174 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L174

Added line #L174 was not covered by tests

@property
def total_sum_s(self):

Check warning on line 177 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L176-L177

Added lines #L176 - L177 were not covered by tests
"""float: Sum of all totals from all PETs, in seconds."""
return nano_to_sec(self._total_sum)

Check warning on line 179 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L179

Added line #L179 was not covered by tests

@property
def total_mean(self):

Check warning on line 182 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L181-L182

Added lines #L181 - L182 were not covered by tests
"""float: The mean total time, averaged over all PETs, in nanoseconds."""
return self._total_sum / self._pet_count

Check warning on line 184 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L184

Added line #L184 was not covered by tests

@property
def total_mean_s(self):

Check warning on line 187 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L186-L187

Added lines #L186 - L187 were not covered by tests
"""float: The mean total time, averaged over all PETs, in seconds."""
return nano_to_sec(self.total_mean)

Check warning on line 189 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L189

Added line #L189 was not covered by tests

@property
def total_min(self):

Check warning on line 192 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L191-L192

Added lines #L191 - L192 were not covered by tests
"""float: Minimum total time spend in this region among all PETs, in nanoseconds."""
return self._total_min

Check warning on line 194 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L194

Added line #L194 was not covered by tests

@property
def total_min_s(self):

Check warning on line 197 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L196-L197

Added lines #L196 - L197 were not covered by tests
"""float: Minimum total time spend in this region among all PETs, in seconds."""
return nano_to_sec(self._total_min)

Check warning on line 199 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L199

Added line #L199 was not covered by tests

@property
def total_min_pet(self):

Check warning on line 202 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L201-L202

Added lines #L201 - L202 were not covered by tests
"""int: ID of PET who spent the minimum total time in this region."""
return self._total_min_pet

Check warning on line 204 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L204

Added line #L204 was not covered by tests

@property
def total_max(self):

Check warning on line 207 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L206-L207

Added lines #L206 - L207 were not covered by tests
"""float: Maximum total time spend in this region among all PETs, in nanoseconds."""
return self._total_max

Check warning on line 209 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L209

Added line #L209 was not covered by tests

@property
def total_max_s(self):

Check warning on line 212 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L211-L212

Added lines #L211 - L212 were not covered by tests
"""float: Maximum total time spend in this region among all PETs, in seconds."""
return nano_to_sec(self._total_max)

Check warning on line 214 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L214

Added line #L214 was not covered by tests

@property
def total_max_pet(self):

Check warning on line 217 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L216-L217

Added lines #L216 - L217 were not covered by tests
"""int: ID of PET who spent the maximum total time in this region."""
return self._total_max_pet

Check warning on line 219 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L219

Added line #L219 was not covered by tests

@property
def children(self):

Check warning on line 222 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L221-L222

Added lines #L221 - L222 were not covered by tests
"""dict[str, MultiPETTimingNode]: Direct children of this node."""
return self._children

Check warning on line 224 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L224

Added line #L224 was not covered by tests

def _merge_children(self, other: SinglePETTimingNode):
for c in other.children:
rs = self._children.setdefault(c.name, MultiPETTimingNode())
rs.merge(c)

Check warning on line 229 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L226-L229

Added lines #L226 - L229 were not covered by tests

def merge(self, other: SinglePETTimingNode):

Check warning on line 231 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L231

Added line #L231 was not covered by tests
"""Merge a single-PET tree into this multi-PET timing tree.

Update the statistics of this MultiPETTimingNode by including the information from a new SinglePETTiming node.
This function then proceeds to traverse the entire single-PET tree and merge all of its nodes. This is achieved
by calling the self._merge_children method.

Args:
other (SinglePETTimingNode): Single-PET tree to merge.
"""
self._pet_count += 1
if self._pet_count == 1:
self._count_each = other.count
elif self._count_each != other.count:
self._counts_match = False

Check warning on line 245 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L241-L245

Added lines #L241 - L245 were not covered by tests

self._total_sum += other.total
if self._total_min > other.min:
self._total_min = other.min
self._total_min_pet = other.pet
if self._total_max < other.max:
self._total_max = other.max
self._total_max_pet = other.pet

Check warning on line 253 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L247-L253

Added lines #L247 - L253 were not covered by tests

self._contributing_nodes[other.pet] = other

Check warning on line 255 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L255

Added line #L255 was not covered by tests

self._merge_children(other)

Check warning on line 257 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L257

Added line #L257 was not covered by tests


class ESMFTrace:

Check warning on line 260 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L260

Added line #L260 was not covered by tests
"""Tree of MultiPetTimingNodes constructed by parsing the traces generated by ESMF.

Args:
path (str): Directory containing the traces to parse.
"""

def __init__(self, path: Path):
self._region_id_to_name_map = {} # { pet -> { region_id -> region name } }
self._timing_trees = {} # { pet -> root of timing tree }
self._regions = {"TOP"} # Set containing all known regions. Using a set ensures region's names are unique.

Check warning on line 270 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L267-L270

Added lines #L267 - L270 were not covered by tests

# Iterate over the trace messages.
for msg in bt2.TraceCollectionMessageIterator(path.as_posix()):
if type(msg) is bt2._EventMessageConst:
self._handle_event(msg)

Check warning on line 275 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L273-L275

Added lines #L273 - L275 were not covered by tests

self.multiPETTree = MultiPETTimingNode()
for _, t in self._timing_trees.items():
self.multiPETTree.merge(t)

Check warning on line 279 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L277-L279

Added lines #L277 - L279 were not covered by tests

@property
def regions(self) -> list[str]:

Check warning on line 282 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L281-L282

Added lines #L281 - L282 were not covered by tests
"""list[str]: Name of all the known regions."""
return list(self._regions)

Check warning on line 284 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L284

Added line #L284 was not covered by tests

def _handle_event(self, msg: bt2._EventMessageConst):

Check warning on line 286 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L286

Added line #L286 was not covered by tests
"""Process a trace event message, extracting and storing any relevant information.

Args:
msg (bt2._EventMessageConst: Trace message describing the event to handle.
"""
if msg.event.name == "define_region":
pet = int(msg.event.packet.context_field["pet"])
regionid = int(msg.event.payload_field["id"])
name = str(msg.event.payload_field["name"])
self._region_id_to_name_map.setdefault(pet, {})[regionid] = name
self._regions.add(name)

Check warning on line 297 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L292-L297

Added lines #L292 - L297 were not covered by tests

elif msg.event.name == "region_profile":
pet = int(msg.event.packet.context_field["pet"])
region_id = int(msg.event.payload_field["id"])
parent_id = int(msg.event.payload_field["parentid"])

Check warning on line 302 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L299-L302

Added lines #L299 - L302 were not covered by tests

if region_id == 1:

Check warning on line 304 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L304

Added line #L304 was not covered by tests
# special case for outermost timed region
name = "TOP"

Check warning on line 306 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L306

Added line #L306 was not covered by tests
else:
_map = self._region_id_to_name_map[pet]
name = _map[region_id] # should already be there

Check warning on line 309 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L308-L309

Added lines #L308 - L309 were not covered by tests

node = SinglePETTimingNode(region_id, pet, name)
node.total = int(msg.event.payload_field["total"])
node.count = int(msg.event.payload_field["count"])
node.min = int(msg.event.payload_field["min"])
node.max = int(msg.event.payload_field["max"])

Check warning on line 315 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L311-L315

Added lines #L311 - L315 were not covered by tests

# add child to the timing tree for the given pet
root = self._timing_trees.setdefault(pet, SinglePETTimingNode(0, pet, "TOP_LEVEL"))
if not root.add_child(parent_id, node):
raise RuntimeError(

Check warning on line 320 in om3utils/esmf_trace.py

View check run for this annotation

Codecov / codecov/patch

om3utils/esmf_trace.py#L318-L320

Added lines #L318 - L320 were not covered by tests
f"{self.__class__.__name__} child not added to tree pet = {pet}, regionid = {region_id}, parentid = {parent_id}, name = {name}"
)
Loading
Loading