Skip to content
log.py 36.5 KiB
Newer Older
class EventCounter(PostLogQuantity):
Andreas Klöckner's avatar
Andreas Klöckner committed
    """Counts events signaled by :meth:`add`."""
    def __init__(self, name="interval", description=None):
        PostLogQuantity.__init__(self, name, "1", description)
        self.events = 0

    def add(self, n=1):
        self.events += n

    def transfer(self, counter):
        self.events += counter.pop()

    def prepare_for_tick(self):
        self.events = 0

    def __call__(self):
        result = self.events
        return result


def time_and_count_function(f, timer, counter=None, increment=1):
    def inner_f(*args, **kwargs):
        if counter is not None:
            counter.add(increment)
        sub_timer = timer.start_sub_timer()
        try:
            return f(*args, **kwargs)
        finally:
            sub_timer.stop().submit()
class TimestepCounter(LogQuantity):
Andreas Klöckner's avatar
Andreas Klöckner committed
    """Counts the number of times :meth:`LogManager.tick` is called."""
    def __init__(self, name="step"):
        LogQuantity.__init__(self, name, "1", "Timesteps")
        self.steps = 0

    def __call__(self):
        result = self.steps
        self.steps += 1
        return result


class StepToStepDuration(PostLogQuantity):
    """Records the CPU time between invocations of
    :meth:`LogManager.tick_before` and
    :meth:`LogManager.tick_after`.
    """
    def __init__(self, name="t_2step"):
        PostLogQuantity.__init__(self, name, "s", "Step-to-step duration")
        self.last_start_time = None
        self.last2_start_time = None

    def prepare_for_tick(self):
        self.last2_start_time = self.last_start_time
        self.last_start_time = time()

    def __call__(self):
        if self.last2_start_time is None:
            return None
        else:
            return self.last_start_time - self.last2_start_time


class TimestepDuration(PostLogQuantity):
    """Records the CPU time between the starts of time steps.
    :meth:`LogManager.tick_before` and
    :meth:`LogManager.tick_after`.
    """

    # We would like to run last, so that if log gathering takes any
    # significant time, we catch that, too. (CUDA sync-on-time-taking,
    # I'm looking at you.)
    sort_weight = 1000

    def __init__(self, name="t_step"):
        PostLogQuantity.__init__(self, name, "s", "Time step duration")
    def prepare_for_tick(self):
        self.last_start = time()

    def __call__(self):
        now = time()
        result = now - self.last_start
class CPUTime(LogQuantity):
    """Records (monotonically increasing) CPU time."""
    def __init__(self, name="t_cpu"):
        LogQuantity.__init__(self, name, "s", "Wall time")

        self.start = time()

    def __call__(self):
        return time()-self.start


Andreas Klöckner's avatar
Andreas Klöckner committed
class ETA(LogQuantity):
    """Records an estimate of how long the computation will still take."""
    def __init__(self, total_steps, name="t_eta"):
        LogQuantity.__init__(self, name, "s", "Estimated remaining duration")

        self.steps = 0
        self.total_steps = total_steps
        self.start = time()

    def __call__(self):
        fraction_done = self.steps/self.total_steps
        self.steps += 1
        time_spent = time()-self.start
        if fraction_done > 1e-9:
            return time_spent/fraction_done-time_spent
        else:
            return 0


def add_general_quantities(mgr):
Andreas Klöckner's avatar
Andreas Klöckner committed
    """Add generally applicable :class:`LogQuantity` objects to C{mgr}."""

    mgr.add_quantity(TimestepDuration())
    mgr.add_quantity(StepToStepDuration())
    mgr.add_quantity(CPUTime())
    mgr.add_quantity(LogUpdateDuration(mgr))
    mgr.add_quantity(TimestepCounter())


class SimulationTime(TimeTracker, LogQuantity):
    """Record (monotonically increasing) simulation time."""

    def __init__(self, dt, name="t_sim", start=0):
        LogQuantity.__init__(self, name, "s", "Simulation Time")
        TimeTracker.__init__(self, dt)

    def __call__(self):
class Timestep(SimulationLogQuantity):
    """Record the magnitude of the simulated time step."""

    def __init__(self, dt, name="dt", unit="s"):
        SimulationLogQuantity.__init__(self, dt, name, unit, "Simulation Timestep")
Andreas Klöckner's avatar
Andreas Klöckner committed
    """Set the simulation timestep on :class:`LogManager` C{mgr} to C{dt}."""
    for gd_lst in [mgr.before_gather_descriptors,
            mgr.after_gather_descriptors]:
        for gd in gd_lst:
            if isinstance(gd.quantity, DtConsumer):
                gd.quantity.set_dt(dt)
def add_simulation_quantities(mgr, dt=None):
Andreas Klöckner's avatar
Andreas Klöckner committed
    """Add :class:`LogQuantity` objects relating to simulation time."""
    if dt is not None:
        from warnings import warn
        warn("Specifying dt ahead of time is a deprecated practice. "
    mgr.add_quantity(SimulationTime(dt))
    """Add generic run metadata, such as command line, host, and time."""

    mgr.set_constant("cmdline", " ".join(sys.argv))
    mgr.set_constant("machine", gethostname())
    from time import localtime, strftime, time
    mgr.set_constant("date", strftime("%a, %d %b %Y %H:%M:%S %Z", localtime()))
    mgr.set_constant("unixtime", time())
Andreas Klöckner's avatar
Andreas Klöckner committed

# }}}

# vim: foldmethod=marker