Coverage for python / lsst / daf / butler / _butler_metrics.py: 62%
55 statements
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-23 08:07 +0000
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-23 08:07 +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, Iterable, Iterator
33from contextlib import contextmanager
34from typing import Any, 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 log_args: Iterable[Any] = (),
116 *args: P.args,
117 **kwargs: P.kwargs,
118 ) -> Iterator[None]:
119 with time_this(log=log, msg=msg, args=log_args) as timer:
120 yield
121 handler(timer.duration, *args, **kwargs)
123 @contextmanager
124 def instrument_get(
125 self,
126 log: LsstLoggers | None = None,
127 msg: str | None = None,
128 args: Iterable[Any] = (),
129 ) -> Iterator[None]:
130 """Run code and increment get statistics.
132 Parameters
133 ----------
134 log : `logging.Logger` or `None`
135 Logger to use for any timing information.
136 msg : `str` or `None`
137 Any message to be included in log output.
138 args : `~collections.abc.Iterable` [`Any`]
139 Additional parameters passed to the log command that should be
140 written to ``msg``.
141 """
142 with self._timer(self.increment_get, log=log, msg=msg):
143 yield
145 @contextmanager
146 def instrument_put(
147 self,
148 log: LsstLoggers | None = None,
149 msg: str | None = None,
150 args: Iterable[Any] = (),
151 ) -> Iterator[None]:
152 """Run code and increment put statistics.
154 Parameters
155 ----------
156 log : `logging.Logger` or `None`
157 Logger to use for any timing information.
158 msg : `str` or `None`
159 Any message to be included in log output.
160 args : `~collections.abc.Iterable` [`Any`]
161 Additional parameters passed to the log command that should be
162 written to ``msg``.
163 """
164 with self._timer(self.increment_put, log=log, msg=msg):
165 yield
167 @contextmanager
168 def instrument_ingest(
169 self,
170 n_datasets: int,
171 log: LsstLoggers | None = None,
172 msg: str | None = None,
173 args: Iterable[Any] = (),
174 ) -> Iterator[None]:
175 """Run code and increment ingest statistics.
177 Parameters
178 ----------
179 n_datasets : `int`
180 Number of datasets being ingested.
181 log : `logging.Logger` or `None`
182 Logger to use for any timing information.
183 msg : `str` or `None`
184 Any message to be included in log output.
185 args : `~collections.abc.Iterable` [`Any`]
186 Additional parameters passed to the log command that should be
187 written to ``msg``.
188 """
189 with self._timer(self.increment_ingest, n_datasets=n_datasets, log=log, msg=msg, log_args=args):
190 yield