Source code for fridom.framework.timing_module
"""timing_module.py - Keep track of the time spent in different model components."""
from contextlib import contextmanager
from typing import Generator
import fridom.framework as fr
[docs]
class TimingComponent:
"""Keep track of the time spent in a particular component of the model."""
def __init__(self, name:str) -> None:
"""
Initialize the TimingComponent.
Arguments:
name (str): name of the component
"""
self.name = name
self.time = 0.0
self.is_active = False
self.start_time = 0.0
[docs]
def start(self) -> None:
"""Start the timer."""
# check if the timer is already active
if self.is_active:
fr.log.debug(
f"Start of TimingComponent {self.name} is called, "
"but the component is already active.")
return
# start the timer
self.is_active = True
from time import time
self.start_time = time()
return
[docs]
def stop(self) -> None:
"""Stop the timer."""
# check if the timer is active
if not self.is_active:
fr.log.debug(
f"Stop of TimingComponent {self.name} is called, "
"but the component is not active.")
return
# stop the timer
from time import time
self.time += time() - self.start_time
self.is_active = False
return
[docs]
def reset(self) -> None:
"""Reset the timer."""
self.time = 0.0
self.is_active = False
self.start_time = 0.0
def __str__(self) -> str:
"""
Return string representation of the time spent in the component.
Format: "name: {hh:mm:ss}s"
"""
# Convert time to hours, minutes, seconds
t = self.time
h = int(t // 3600)
t -= h * 3600
m = int(t // 60)
t -= m * 60
s = int(t)
# print time in hours, minutes, seconds
return f"{self.name:<30s}: {h:02d}:{m:02d}:{s:02d}s"
[docs]
class TimingModule:
"""Container class for TimingComponent objects."""
def __init__(self) -> None:
"""Construct the TimingModule with default components."""
# initialize default components
self.total = TimingComponent("Total Integration")
# add components to list
self.components = [
self.total,
]
[docs]
def add_component(self, name:str) -> None:
"""
Add a new TimingComponent to the TimingModule.
Arguments:
name (str): name of the new component
"""
self.components.append(TimingComponent(name))
[docs]
def get(self, name:str) -> TimingComponent:
"""
Get the TimingComponent with the given name.
If the component is not found, add a new component with the given name.
Arguments:
name (str): name of the component to get
"""
# search for component with given name
for component in self.components:
if component.name == name:
return component
# if not found => add the component
self.add_component(name)
return self.get(name) # recursive call (should find the component now)
[docs]
def reset(self) -> None:
"""Reset all TimingComponents."""
for component in self.components:
component.reset()
@contextmanager
def __getitem__(self, name:str) -> Generator[TimingComponent, None, None]:
"""
Context manager to start and stop the timer for a component.
Arguments:
name (str): name of the component
"""
component = self.get(name)
component.start()
yield component
component.stop()
def __str__(self) -> str:
"""Return string representation of the model settings."""
res = "=====================================================\n"
res += " Timing Summary: \n"
res += "=====================================================\n"
for component in self.components:
res += str(component)
res += f" ({100 * component.time / self.total.time:.1f}%)\n"
res += "=====================================================\n"
return res
def __repr__(self) -> str:
"""Return string representation of the model settings (for IPython)."""
return self.__str__()