diff --git a/tangostationcontrol/tangostationcontrol/devices/beam_device.py b/tangostationcontrol/tangostationcontrol/devices/beam_device.py index c5d27c643050c17201077e206454488009922a08..b45d9b0e7890892c2f463bea4e22e7fce449fa38 100644 --- a/tangostationcontrol/tangostationcontrol/devices/beam_device.py +++ b/tangostationcontrol/tangostationcontrol/devices/beam_device.py @@ -150,7 +150,7 @@ class BeamDevice(LOFARDevice): doc="Time it took to compute weights", unit="s", dtype=numpy.float64, - fget=lambda self: self._compute_weights.statistics["last"] or 0, + fget=lambda self: self._compute_weights.get_statistic(self)["last"] or 0, ) Duration_preparation_period_slack_R = attribute( @@ -158,7 +158,7 @@ class BeamDevice(LOFARDevice): doc="Slack between computing and applying weights", unit="s", dtype=numpy.float64, - fget=lambda self: self._wait_to_apply_weights.statistics["last"] or 0, + fget=lambda self: self._wait_to_apply_weights.get_statistic(self)["last"] or 0, ) Duration_apply_weights_R = attribute( @@ -166,7 +166,7 @@ class BeamDevice(LOFARDevice): doc="Time it took to upload weights", unit="s", dtype=numpy.float64, - fget=lambda self: self._apply_weights.statistics["last"] or 0, + fget=lambda self: self._apply_weights.get_statistic(self)["last"] or 0, ) Nr_update_pointing_exceptions_R = attribute( @@ -275,7 +275,7 @@ class BeamDevice(LOFARDevice): def _wait_to_apply_weights(self, timestamp: datetime.datetime): # expected time required to upload weights to hardware (use last 10 measured durations) expected_application_time = median( - self._apply_weights.statistics["history"][-10:] or [0.1] + self._apply_weights.get_statistic(self)["history"][-10:] or [0.1] ) # wait until provided time occurs, but don't start sleeping long here diff --git a/tangostationcontrol/tangostationcontrol/devices/device_decorators.py b/tangostationcontrol/tangostationcontrol/devices/device_decorators.py index 12a0247a414d98e9c2eb84db079ba35f675e7fe7..f92409d720ab68e100a710962825a17f0d4855d0 100644 --- a/tangostationcontrol/tangostationcontrol/devices/device_decorators.py +++ b/tangostationcontrol/tangostationcontrol/devices/device_decorators.py @@ -78,15 +78,15 @@ def fault_on_error(): return inner -def TimeIt(log_function=None): +def TimeIt(log_function=None, max_history_len=10): """ - Wrapper to time calls. Stores the timing log in a - <function>.statistics property as a dict with the following + Wrapper to time calls, per object ("self"). Stores the timing log in a + <function>.get_statistic(self) function returning a dict with the following information: "count": number of times the function was called "last": duration of the last invocation - "history": last 10 durations + "history": last "max_history_len" durations NOTE: If the function called throws an exception, timing information is not logged or recorded. Those calls are expected to be @@ -94,12 +94,14 @@ def TimeIt(log_function=None): """ def inner(func): - statistics = { + default_statistic = { "count": 0, "last": None, "history": [], } + statistics = {} + @wraps(func) def timer_wrapper(self, *args, **kwargs): # time function call @@ -107,10 +109,16 @@ def TimeIt(log_function=None): result = func(self, *args, **kwargs) after = time.monotonic_ns() + # maintain statistics per object (self) + if self not in statistics: + statistics[self] = default_statistic.copy() + # store measurement - statistics["count"] += 1 - statistics["last"] = (after - before) / 1e9 - statistics["history"] = statistics["history"][-9:] + [statistics["last"]] + statistics[self]["count"] += 1 + statistics[self]["last"] = (after - before) / 1e9 + statistics[self]["history"] = statistics[self]["history"][ + -(max_history_len - 1) : + ] + [statistics[self]["last"]] if log_function: log_function( @@ -120,7 +128,10 @@ def TimeIt(log_function=None): # return function result (if any) return result - timer_wrapper.statistics = statistics + # get the statistics for a specific object + timer_wrapper.get_statistic = lambda self: statistics.get( + self, default_statistic.copy() + ) return timer_wrapper diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/digitalbeam.py b/tangostationcontrol/tangostationcontrol/devices/sdp/digitalbeam.py index cb86fb6ec1f8e382e92b9f2f6cf979ef26cadea3..ebde55278d4f7ce014731b91362e3655c47dc343 100644 --- a/tangostationcontrol/tangostationcontrol/devices/sdp/digitalbeam.py +++ b/tangostationcontrol/tangostationcontrol/devices/sdp/digitalbeam.py @@ -81,7 +81,7 @@ class DigitalBeam(BeamDevice): Duration_delays_R = attribute( access=AttrWriteType.READ, dtype=numpy.float64, - fget=lambda self: self._delays.statistics["last"] or 0, + fget=lambda self: self._delays.get_statistic(self)["last"] or 0, ) input_select_RW = attribute( diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py index 6dc6fd68aba527bc76cfa4802d37108637bcdc75..99302c241245ce96fef0e4cbe7b15e984b211fac 100644 --- a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py +++ b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py @@ -465,7 +465,8 @@ class SDP(OPCUADevice): unit="s", access=AttrWriteType.READ, dtype=numpy.float64, - fget=lambda self: self.read_subband_frequency_R.statistics["last"] or 0, + fget=lambda self: self.read_subband_frequency_R.get_statistic(self)["last"] + or 0, ) def read_antenna_type_RW(self):