Coverage for python / lsst / daf / butler / _butler_metrics.py: 62%
55 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-01 08:18 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-01 08:18 +0000
1# This file is part of daf_butler.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (http://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This software is dual licensed under the GNU General Public License and also
10# under a 3-clause BSD license. Recipients may choose which of these licenses
11# to use; please see the files gpl-3.0.txt and/or bsd_license.txt,
12# respectively. If you choose the GPL option then the following text applies
13# (but note that there is still no warranty even if you opt for BSD instead):
14#
15# This program is free software: you can redistribute it and/or modify
16# it under the terms of the GNU General Public License as published by
17# the Free Software Foundation, either version 3 of the License, or
18# (at your option) any later version.
19#
20# This program is distributed in the hope that it will be useful,
21# but WITHOUT ANY WARRANTY; without even the implied warranty of
22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23# GNU General Public License for more details.
24#
25# You should have received a copy of the GNU General Public License
26# along with this program. If not, see <http://www.gnu.org/licenses/>.
28from __future__ import annotations
30__all__ = ["ButlerMetrics"]
32from collections.abc import Callable, Iterator
33from contextlib import contextmanager
34from typing import Concatenate, ParamSpec
36from pydantic import BaseModel
38from lsst.utils.logging import LsstLoggers
39from lsst.utils.timer import time_this
41P = ParamSpec("P")
44class ButlerMetrics(BaseModel):
45 """Metrics collected during Butler operations."""
47 time_in_put: float = 0.0
48 """Wall-clock time, in seconds, spent in put()."""
50 time_in_get: float = 0.0
51 """Wall-clock time, in seconds, spent in get()."""
53 time_in_ingest: float = 0.0
54 """Wall-clock time, in seconds, spent in ingest()."""
56 n_get: int = 0
57 """Number of datasets retrieved with get()."""
59 n_put: int = 0
60 """Number of datasets stored with put()."""
62 n_ingest: int = 0
63 """Number of datasets ingested."""
65 def reset(self) -> None:
66 """Reset all metrics."""
67 self.time_in_put = 0.0
68 self.time_in_get = 0.0
69 self.time_in_ingest = 0.0
70 self.n_get = 0
71 self.n_put = 0
72 self.n_ingest = 0
74 def increment_get(self, duration: float) -> None:
75 """Increment time for get().
77 Parameters
78 ----------
79 duration : `float`
80 Duration to add to the get() statistics.
81 """
82 self.time_in_get += duration
83 self.n_get += 1
85 def increment_put(self, duration: float) -> None:
86 """Increment time for put().
88 Parameters
89 ----------
90 duration : `float`
91 Duration to add to the put() statistics.
92 """
93 self.time_in_put += duration
94 self.n_put += 1
96 def increment_ingest(self, duration: float, n_datasets: int) -> None:
97 """Increment time and datasets for ingest().
99 Parameters
100 ----------
101 duration : `float`
102 Duration to add to the ingest() statistics.
103 n_datasets : `int`
104 Number of datasets to be ingested for this call.
105 """
106 self.time_in_ingest += duration
107 self.n_ingest += n_datasets
109 @contextmanager
110 def _timer(
111 self,
112 handler: Callable[Concatenate[float, P], None],
113 log: LsstLoggers | None = None,
114 msg: str | None = None,
115 *args: P.args,
116 **kwargs: P.kwargs,
117 ) -> Iterator[None]:
118 with time_this(log=log, msg=msg) as timer:
119 yield
120 handler(timer.duration, *args, **kwargs)
122 @contextmanager
123 def instrument_get(self, log: LsstLoggers | None = None, msg: str | None = None) -> Iterator[None]:
124 """Run code and increment get statistics.
126 Parameters
127 ----------
128 log : `logging.Logger` or `None`
129 Logger to use for any timing information.
130 msg : `str` or `None`
131 Any message to be included in log output.
132 """
133 with self._timer(self.increment_get, log=log, msg=msg):
134 yield
136 @contextmanager
137 def instrument_put(self, log: LsstLoggers | None = None, msg: str | None = None) -> Iterator[None]:
138 """Run code and increment put statistics.
140 Parameters
141 ----------
142 log : `logging.Logger` or `None`
143 Logger to use for any timing information.
144 msg : `str` or `None`
145 Any message to be included in log output.
146 """
147 with self._timer(self.increment_put, log=log, msg=msg):
148 yield
150 @contextmanager
151 def instrument_ingest(
152 self, n_datasets: int, log: LsstLoggers | None = None, msg: str | None = None
153 ) -> Iterator[None]:
154 """Run code and increment ingest statistics.
156 Parameters
157 ----------
158 n_datasets : `int`
159 Number of datasets being ingested.
160 log : `logging.Logger` or `None`
161 Logger to use for any timing information.
162 msg : `str` or `None`
163 Any message to be included in log output.
164 """
165 with self._timer(self.increment_ingest, n_datasets=n_datasets, log=log, msg=msg):
166 yield