yumeow-timer 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 YuMeow
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,114 @@
1
+ Metadata-Version: 2.4
2
+ Name: yumeow-timer
3
+ Version: 0.1.0
4
+ Summary: Lightweight timing utilities for performance diagnostics
5
+ Author-email: YuMeow <yumeow@example.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/yuzhTHU/nd2py
8
+ Project-URL: Repository, https://github.com/yuzhTHU/nd2py
9
+ Keywords: timer,timing,performance,profiling,benchmark
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: numpy>=1.20.0
24
+ Requires-Dist: pandas>=1.3.0
25
+ Dynamic: license-file
26
+
27
+ # yumeow-timer
28
+
29
+ Lightweight timing utilities for optional performance diagnostics.
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ pip install yumeow-timer
35
+ ```
36
+
37
+ ## Usage
38
+
39
+ ### Basic Timer
40
+
41
+ ```python
42
+ from yumeow_timer import Timer
43
+
44
+ timer = Timer()
45
+ for i in range(1000):
46
+ # do something
47
+ timer.add()
48
+
49
+ print(timer) # Timer(time=1.23 s, count=1.00 kiter, pace=1.23 ms/iter, speed=813 iter/s)
50
+ print(timer.to_str('pace')) # 1.23 ms/iter
51
+ ```
52
+
53
+ ### NamedTimer (Multiple Categories)
54
+
55
+ ```python
56
+ from yumeow_timer import NamedTimer
57
+
58
+ timer = NamedTimer()
59
+ for i in range(1000):
60
+ if i % 2 == 0:
61
+ timer.add("even")
62
+ else:
63
+ timer.add("odd")
64
+
65
+ print(timer) # 1.23 ms/iter (even=1.23 ms/iter[50%]; odd=1.23 ms/iter[50%])
66
+ print(timer.to_str('pace', mode_of_detail='pace', mode_of_percent='by_count'))
67
+ ```
68
+
69
+ ### ParallelTimer (Shared Time)
70
+
71
+ ```python
72
+ from yumeow_timer import ParallelTimer
73
+
74
+ timer = ParallelTimer()
75
+ for i in range(1000):
76
+ timer.add("process", n=1)
77
+ timer.add("render", n=1)
78
+
79
+ print(timer) # Shows shared time with separate counts
80
+ ```
81
+
82
+ ### Humanize Functions
83
+
84
+ ```python
85
+ from yumeow_timer import humanize_time, humanize_count, humanize_pace, humanize_speed
86
+
87
+ print(humanize_time(3661)) # 1.02 h
88
+ print(humanize_count(1500)) # 1.50 kiter
89
+ print(humanize_pace(0.00123)) # 1.23 ms/iter
90
+ print(humanize_speed(813)) # 813 iter/s
91
+ ```
92
+
93
+ ## API Reference
94
+
95
+ ### Timer
96
+
97
+ Basic timer that tracks time and count.
98
+
99
+ - `add(n=1, by="increment")` - Add count and elapsed time
100
+ - `clear(reset_last_add_time=False)` - Reset timer
101
+ - `to_str(mode="pace")` - Get human-readable string
102
+ - Properties: `time`, `count`, `pace`, `speed`
103
+
104
+ ### NamedTimer
105
+
106
+ Extends Timer to track multiple named categories with separate time tracking.
107
+
108
+ ### ParallelTimer
109
+
110
+ Extends Timer to track multiple named categories with shared time.
111
+
112
+ ## License
113
+
114
+ MIT License - See LICENSE file for details.
@@ -0,0 +1,88 @@
1
+ # yumeow-timer
2
+
3
+ Lightweight timing utilities for optional performance diagnostics.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install yumeow-timer
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Basic Timer
14
+
15
+ ```python
16
+ from yumeow_timer import Timer
17
+
18
+ timer = Timer()
19
+ for i in range(1000):
20
+ # do something
21
+ timer.add()
22
+
23
+ print(timer) # Timer(time=1.23 s, count=1.00 kiter, pace=1.23 ms/iter, speed=813 iter/s)
24
+ print(timer.to_str('pace')) # 1.23 ms/iter
25
+ ```
26
+
27
+ ### NamedTimer (Multiple Categories)
28
+
29
+ ```python
30
+ from yumeow_timer import NamedTimer
31
+
32
+ timer = NamedTimer()
33
+ for i in range(1000):
34
+ if i % 2 == 0:
35
+ timer.add("even")
36
+ else:
37
+ timer.add("odd")
38
+
39
+ print(timer) # 1.23 ms/iter (even=1.23 ms/iter[50%]; odd=1.23 ms/iter[50%])
40
+ print(timer.to_str('pace', mode_of_detail='pace', mode_of_percent='by_count'))
41
+ ```
42
+
43
+ ### ParallelTimer (Shared Time)
44
+
45
+ ```python
46
+ from yumeow_timer import ParallelTimer
47
+
48
+ timer = ParallelTimer()
49
+ for i in range(1000):
50
+ timer.add("process", n=1)
51
+ timer.add("render", n=1)
52
+
53
+ print(timer) # Shows shared time with separate counts
54
+ ```
55
+
56
+ ### Humanize Functions
57
+
58
+ ```python
59
+ from yumeow_timer import humanize_time, humanize_count, humanize_pace, humanize_speed
60
+
61
+ print(humanize_time(3661)) # 1.02 h
62
+ print(humanize_count(1500)) # 1.50 kiter
63
+ print(humanize_pace(0.00123)) # 1.23 ms/iter
64
+ print(humanize_speed(813)) # 813 iter/s
65
+ ```
66
+
67
+ ## API Reference
68
+
69
+ ### Timer
70
+
71
+ Basic timer that tracks time and count.
72
+
73
+ - `add(n=1, by="increment")` - Add count and elapsed time
74
+ - `clear(reset_last_add_time=False)` - Reset timer
75
+ - `to_str(mode="pace")` - Get human-readable string
76
+ - Properties: `time`, `count`, `pace`, `speed`
77
+
78
+ ### NamedTimer
79
+
80
+ Extends Timer to track multiple named categories with separate time tracking.
81
+
82
+ ### ParallelTimer
83
+
84
+ Extends Timer to track multiple named categories with shared time.
85
+
86
+ ## License
87
+
88
+ MIT License - See LICENSE file for details.
@@ -0,0 +1,41 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "yumeow-timer"
7
+ version = "0.1.0"
8
+ description = "Lightweight timing utilities for performance diagnostics"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ authors = [
12
+ {name = "YuMeow", email = "yumeow@example.com"}
13
+ ]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Intended Audience :: Developers",
17
+ "Intended Audience :: Science/Research",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Operating System :: OS Independent",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Topic :: Software Development :: Libraries :: Python Modules",
25
+ ]
26
+ keywords = ["timer", "timing", "performance", "profiling", "benchmark"]
27
+ requires-python = ">=3.10"
28
+ dependencies = [
29
+ "numpy>=1.20.0",
30
+ "pandas>=1.3.0",
31
+ ]
32
+
33
+ [project.urls]
34
+ Homepage = "https://github.com/yuzhTHU/nd2py"
35
+ Repository = "https://github.com/yuzhTHU/nd2py"
36
+
37
+ [tool.setuptools.packages.find]
38
+ where = ["src"]
39
+
40
+ [tool.setuptools.package-dir]
41
+ "" = "src"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,11 @@
1
+ """
2
+ yumeow-timer: Lightweight timing utilities for optional performance diagnostics.
3
+
4
+ Provides Timer, NamedTimer, and ParallelTimer classes for tracking
5
+ execution time and iteration counts with human-readable output.
6
+ """
7
+
8
+ from .timing import Timer, NamedTimer, ParallelTimer
9
+
10
+ __version__ = "0.1.0"
11
+ __all__ = ["Timer", "NamedTimer", "ParallelTimer", "__version__"]
@@ -0,0 +1,281 @@
1
+ """
2
+ Lightweight timing utilities for optional performance diagnostics.
3
+ """
4
+
5
+ import enum
6
+ import time
7
+ import numpy as np
8
+ import pandas as pd
9
+ from typing import Literal
10
+
11
+ __all__ = ["Timer", "NamedTimer", "ParallelTimer"]
12
+
13
+
14
+ Mode = Literal["time", "count", "pace", "speed"]
15
+
16
+
17
+ def humanize_time(time):
18
+ """Convert time in seconds to a human-readable string."""
19
+ if time == 0: return "0 s"
20
+ unit_scale = pd.Series({ # 需要保证从小到大排列
21
+ 'μs': 1e-6, 'ms': 1e-3, 's': 1e0, 'min': 60, 'h': 3600, 'day': 86400
22
+ })
23
+ idx = max(0, unit_scale.searchsorted(time, side='right')-1)
24
+ time_unit, scale = unit_scale.index[idx], unit_scale.iloc[idx]
25
+ return f"{time / scale:.3g} {time_unit}"
26
+
27
+
28
+ def humanize_count(count, unit="iter"):
29
+ """Convert count to a human-readable string."""
30
+ if count == 0: return f"0 {unit}"
31
+ unit_scale = pd.Series({ # 需要保证从小到大排列
32
+ f'n{unit}': 1e-9, f'μ{unit}': 1e-6, f'm{unit}': 1e-3,
33
+ f'{unit}': 1, f'k{unit}': 1e3, f'M{unit}': 1e6, f'G{unit}': 1e9
34
+ })
35
+ idx = max(0, unit_scale.searchsorted(count, side='right')-1)
36
+ count_unit, scale = unit_scale.index[idx], unit_scale.iloc[idx]
37
+ return f"{count / scale:.3g} {count_unit}"
38
+
39
+
40
+ def humanize_pace(pace, unit="iter"):
41
+ """Convert pace (second/iter) to a human-readable string."""
42
+ if pace == 0: return f"0 s/{unit}"
43
+ unit_scale = pd.Series({ # 需要保证从小到大排列
44
+ f'μs/{unit}': 1e-6, f'ms/{unit}': 1e-3, f's/{unit}': 1e0,
45
+ f'min/{unit}': 60, f'h/{unit}': 3600, f'day/{unit}': 86400
46
+ })
47
+ idx = max(0, unit_scale.searchsorted(pace, side='right')-1)
48
+ pace_unit, scale = unit_scale.index[idx], unit_scale.iloc[idx]
49
+ return f"{pace / scale:.3g} {pace_unit}"
50
+
51
+
52
+ def humanize_speed(speed, unit="iter"):
53
+ """Convert speed (iter/second) to a human-readable string."""
54
+ if speed == 0: return f"0 {unit}/s"
55
+ unit_scale = pd.Series({ # 需要保证从小到大排列
56
+ f'{unit}/day': 1/86400, f'{unit}/h': 1/3600, f'{unit}/min': 1/60, f'{unit}/s': 1,
57
+ f'k{unit}/s': 1e3, f'M{unit}/s': 1e6, f'G{unit}/s': 1e9
58
+ })
59
+ idx = max(0, unit_scale.searchsorted(speed, side='right')-1)
60
+ speed_unit, scale = unit_scale.index[idx], unit_scale.iloc[idx]
61
+ return f"{speed / scale:.3g} {speed_unit}"
62
+
63
+
64
+ class Timer:
65
+ def __init__(self, unit="iter"):
66
+ """ 计时器 """
67
+ self._count = 0
68
+ self._time = 0
69
+ self.unit = unit
70
+ self.last_add_time = time.time()
71
+
72
+ def add(self, n=1, by: Literal["increment", "absolute"]="increment"):
73
+ if by == "increment": self._count += n
74
+ elif by == "absolute": self._count = n
75
+ self._time += (now := time.time()) - self.last_add_time
76
+ self.last_add_time = now
77
+
78
+ def clear(self, reset_last_add_time=False):
79
+ self._count = 0
80
+ self._time = 0
81
+ if reset_last_add_time:
82
+ self.last_add_time = time.time()
83
+
84
+ def to_str(self, mode: Mode = 'pace'):
85
+ if mode == 'pace': return humanize_pace(self.pace, unit=self.unit)
86
+ elif mode == "speed": return humanize_speed(self.speed, unit=self.unit)
87
+ elif mode == "count": return humanize_count(self.count, unit=self.unit)
88
+ elif mode == "time": return humanize_time(self.time)
89
+ else: raise ValueError(f"Unknown mode: {mode}. Supported modes are 'pace', 'speed', 'count', and 'time'.")
90
+
91
+ def __str__(self):
92
+ time = self.time_str()
93
+ count = self.count_str()
94
+ pace = self.pace_str()
95
+ speed = self.speed_str()
96
+ return f"{type(self).__name__}(time={time}, count={count}, pace={pace}, speed={speed})"
97
+
98
+ def __repr__(self):
99
+ return self.__str__()
100
+
101
+ @property
102
+ def time(self): return self._time
103
+ @property
104
+ def count(self): return self._count
105
+ @property
106
+ def pace(self): return self.time / self.count if self.count != 0 else 0
107
+ @property
108
+ def speed(self): return self.count / self.time if self.time != 0 else 0
109
+ def time_str(self): return humanize_time(self.time)
110
+ def count_str(self): return humanize_count(self.count, unit=self.unit)
111
+ def pace_str(self): return humanize_pace(self.pace, unit=self.unit)
112
+ def speed_str(self): return humanize_speed(self.speed, unit=self.unit)
113
+
114
+ def to_dict(self):
115
+ return {
116
+ '_count': self._count,
117
+ '_time': self._time,
118
+ 'unit': self.unit,
119
+ }
120
+
121
+ @classmethod
122
+ def from_dict(cls, dict):
123
+ timer = cls(unit=dict['unit'])
124
+ timer._count = dict['_count']
125
+ timer._time = dict['_time']
126
+ return timer
127
+
128
+
129
+ class NamedTimer(Timer):
130
+ def __init__(self, unit="iter"):
131
+ """ 对 Timer 的扩展,支持将 count 和 time 统计到不同的名称下 """
132
+ super().__init__(unit=unit)
133
+ self._count = {}
134
+ self._time = {}
135
+
136
+ def add(self, name, n=1, by: Literal["increment", "absolute"]="increment"):
137
+ if name and name not in self.names:
138
+ self._time[name] = self._count[name] = 0
139
+ if name is None: pass
140
+ elif by == "increment": self._count[name] += n
141
+ elif by == "absolute": self._count[name] = n
142
+ self._time[name] += (now := time.time()) - self.last_add_time
143
+ self.last_add_time = now
144
+
145
+ def clear(self, reset_last_add_time=False):
146
+ self._count = {}
147
+ self._time = {}
148
+ if reset_last_add_time:
149
+ self.last_add_time = time.time()
150
+
151
+ def to_str(
152
+ self,
153
+ mode: Mode='pace',
154
+ mode_of_detail: Mode|None='pace',
155
+ mode_of_percent: Literal['by_time', 'by_count']|None='by_time',
156
+ ):
157
+ if mode == "time": total = humanize_time(self.time)
158
+ elif mode == "count": total = humanize_count(self.count, unit=self.unit)
159
+ elif mode == "pace": total = humanize_pace(self.pace, unit=self.unit)
160
+ elif mode == "speed": total = humanize_speed(self.speed, unit=self.unit)
161
+ else: raise ValueError(f"Unknown mode: {mode}. Supported modes are 'pace', 'speed', 'count', and 'time'.")
162
+
163
+ if mode_of_detail is None: detail = {k: "" for k in self.names}
164
+ elif mode_of_detail == "time": detail = {k: humanize_time(self.get_named_time(k)) for k in self.names}
165
+ elif mode_of_detail == "count": detail = {k: humanize_count(self.get_named_count(k), unit=self.unit) for k in self.names}
166
+ elif mode_of_detail == "pace": detail = {k: humanize_pace(self.get_named_pace(k), unit=self.unit) for k in self.names}
167
+ elif mode_of_detail == "speed": detail = {k: humanize_speed(self.get_named_speed(k), unit=self.unit) for k in self.names}
168
+ else: raise ValueError(f"Unknown mode_of_detail: {mode_of_detail}. Supported modes are 'pace', 'speed', 'count', and 'time'.")
169
+
170
+ if mode_of_percent is None: percent = {k: None for k in self.names}
171
+ elif mode_of_percent == 'by_time': percent = {k: self.get_named_time(k) / self.time if self.time > 0 else None for k in self.names}
172
+ elif mode_of_percent == 'by_count': percent = {k: self.get_named_count(k) / self.count if self.count > 0 else None for k in self.names}
173
+ else: raise ValueError(f"Unknown mode: {mode_of_percent}. Supported modes are 'by_time' and 'by_count'.")
174
+
175
+ detail_str = []
176
+ for k in sorted(self.names, key=percent.get, reverse=True):
177
+ if detail[k] and percent[k]:
178
+ detail_str.append(f"{k}={detail[k]}[{percent[k]:.0%}]")
179
+ elif detail[k]:
180
+ detail_str.append(f"{k}={detail[k]}")
181
+ elif percent[k]:
182
+ detail_str.append(f"{k}[{percent[k]:.0%}]")
183
+ else:
184
+ pass
185
+ detail_str = f" ({'; '.join(detail_str)})" if detail_str else ""
186
+ return f'{total}{detail_str}'
187
+
188
+ @property
189
+ def names(self): return list(self._time.keys())
190
+ @property
191
+ def time(self): return sum(self._time.values())
192
+ @property
193
+ def count(self): return sum(self._count.values())
194
+ def get_named_time(self, name): return self._time[name]
195
+ def get_named_count(self, name): return self._count[name]
196
+ def get_named_pace(self, name): return self._time[name] / self._count[name] if self._count[name] != 0 else 0
197
+ def get_named_speed(self, name): return self._count[name] / self._time[name] if self._time[name] != 0 else 0
198
+ @property
199
+ def named_time(self): return {k: self.get_named_time(k) for k in self.names}
200
+ @property
201
+ def named_count(self): return {k: self.get_named_count(k) for k in self.names}
202
+ @property
203
+ def named_pace(self): return {k: self.get_named_pace(k) for k in self.names}
204
+ @property
205
+ def named_speed(self): return {k: self.get_named_speed(k) for k in self.names}
206
+
207
+
208
+ class ParallelTimer(Timer):
209
+ def __init__(self, unit="iter"):
210
+ """ 对 Timer 的扩展,支持将 count 统计到不同的名称下,但 time 在各名称间共享 """
211
+ super().__init__(unit=unit)
212
+ self._count = {}
213
+
214
+ def add(self, name, n=1, by: Literal["increment", "absolute"]="increment"):
215
+ if name and name not in self.names:
216
+ self._count[name] = 0
217
+ if name is None: pass
218
+ elif by == "increment": self._count[name] += n
219
+ elif by == "absolute": self._count[name] = n
220
+ self._time += (now := time.time()) - self.last_add_time
221
+ self.last_add_time = now
222
+
223
+ def clear(self, reset_last_add_time=False):
224
+ self._count = {}
225
+ self._time = 0
226
+ if reset_last_add_time:
227
+ self.last_add_time = time.time()
228
+
229
+ def to_str(
230
+ self,
231
+ mode: Mode='pace',
232
+ mode_of_detail: Mode|None='pace',
233
+ mode_of_percent: Literal['by_time', 'by_count']|None='by_time'
234
+ ):
235
+ if mode == "time": total = humanize_time(self.time)
236
+ elif mode == "count": total = humanize_count(self.count, unit=self.unit)
237
+ elif mode == "pace": total = humanize_pace(self.pace, unit=self.unit)
238
+ elif mode == "speed": total = humanize_speed(self.speed, unit=self.unit)
239
+ else: raise ValueError(f"Unknown mode: {mode}. Supported modes are 'pace', 'speed', 'count', and 'time'.")
240
+
241
+ if mode_of_detail is None: detail = {k: "" for k in self.names}
242
+ elif mode_of_detail == "time": detail = {k: humanize_time(self.get_named_time(k)) for k in self.names} # 不建议,因为 time 是共享的
243
+ elif mode_of_detail == "count": detail = {k: humanize_count(self.get_named_count(k), unit=self.unit) for k in self.names}
244
+ elif mode_of_detail == "pace": detail = {k: humanize_pace(self.get_named_pace(k), unit=self.unit) for k in self.names}
245
+ elif mode_of_detail == "speed": detail = {k: humanize_speed(self.get_named_speed(k), unit=self.unit) for k in self.names}
246
+ else: raise ValueError(f"Unknown mode_of_detail: {mode_of_detail}. Supported modes are 'pace', 'speed', 'count', and 'time'.")
247
+
248
+ if mode_of_percent is None: percent = {k: None for k in self.names}
249
+ elif mode_of_percent == 'by_time': percent = {k: self.get_named_time(k) / self.time if self.time > 0 else None for k in self.names} # 不建议,因为 time 是共享的
250
+ elif mode_of_percent == 'by_count': percent = {k: self.get_named_count(k) / self.count if self.count > 0 else None for k in self.names}
251
+ else: raise ValueError(f"Unknown mode: {mode_of_percent}. Supported modes are 'by_time' and 'by_count'.")
252
+
253
+ detail_str = []
254
+ for k in sorted(self.names, key=lambda x: percent.get(x) or -float('inf'), reverse=True):
255
+ if detail[k] and percent[k]:
256
+ detail_str.append(f"{k}={detail[k]}[{percent[k]:.0%}]")
257
+ elif detail[k]:
258
+ detail_str.append(f"{k}={detail[k]}")
259
+ elif percent[k]:
260
+ detail_str.append(f"{k}[{percent[k]:.0%}]")
261
+ else:
262
+ pass
263
+ detail_str = f" ({'; '.join(detail_str)})" if detail_str else ""
264
+ return f'{total}{detail_str}'
265
+
266
+ @property
267
+ def names(self): return list(self._count.keys())
268
+ @property
269
+ def count(self): return sum(self._count.values())
270
+ def get_named_time(self, name): return self._time
271
+ def get_named_count(self, name): return self._count[name]
272
+ def get_named_pace(self, name): return self._time / self._count[name] if self._count[name] != 0 else 0
273
+ def get_named_speed(self, name): return self._count[name] / self._time if self._time != 0 else 0
274
+ @property
275
+ def named_time(self): return {k: self.get_named_time(k) for k in self.names}
276
+ @property
277
+ def named_count(self): return {k: self.get_named_count(k) for k in self.names}
278
+ @property
279
+ def named_pace(self): return {k: self.get_named_pace(k) for k in self.names}
280
+ @property
281
+ def named_speed(self): return {k: self.get_named_speed(k) for k in self.names}
@@ -0,0 +1,114 @@
1
+ Metadata-Version: 2.4
2
+ Name: yumeow-timer
3
+ Version: 0.1.0
4
+ Summary: Lightweight timing utilities for performance diagnostics
5
+ Author-email: YuMeow <yumeow@example.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/yuzhTHU/nd2py
8
+ Project-URL: Repository, https://github.com/yuzhTHU/nd2py
9
+ Keywords: timer,timing,performance,profiling,benchmark
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: numpy>=1.20.0
24
+ Requires-Dist: pandas>=1.3.0
25
+ Dynamic: license-file
26
+
27
+ # yumeow-timer
28
+
29
+ Lightweight timing utilities for optional performance diagnostics.
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ pip install yumeow-timer
35
+ ```
36
+
37
+ ## Usage
38
+
39
+ ### Basic Timer
40
+
41
+ ```python
42
+ from yumeow_timer import Timer
43
+
44
+ timer = Timer()
45
+ for i in range(1000):
46
+ # do something
47
+ timer.add()
48
+
49
+ print(timer) # Timer(time=1.23 s, count=1.00 kiter, pace=1.23 ms/iter, speed=813 iter/s)
50
+ print(timer.to_str('pace')) # 1.23 ms/iter
51
+ ```
52
+
53
+ ### NamedTimer (Multiple Categories)
54
+
55
+ ```python
56
+ from yumeow_timer import NamedTimer
57
+
58
+ timer = NamedTimer()
59
+ for i in range(1000):
60
+ if i % 2 == 0:
61
+ timer.add("even")
62
+ else:
63
+ timer.add("odd")
64
+
65
+ print(timer) # 1.23 ms/iter (even=1.23 ms/iter[50%]; odd=1.23 ms/iter[50%])
66
+ print(timer.to_str('pace', mode_of_detail='pace', mode_of_percent='by_count'))
67
+ ```
68
+
69
+ ### ParallelTimer (Shared Time)
70
+
71
+ ```python
72
+ from yumeow_timer import ParallelTimer
73
+
74
+ timer = ParallelTimer()
75
+ for i in range(1000):
76
+ timer.add("process", n=1)
77
+ timer.add("render", n=1)
78
+
79
+ print(timer) # Shows shared time with separate counts
80
+ ```
81
+
82
+ ### Humanize Functions
83
+
84
+ ```python
85
+ from yumeow_timer import humanize_time, humanize_count, humanize_pace, humanize_speed
86
+
87
+ print(humanize_time(3661)) # 1.02 h
88
+ print(humanize_count(1500)) # 1.50 kiter
89
+ print(humanize_pace(0.00123)) # 1.23 ms/iter
90
+ print(humanize_speed(813)) # 813 iter/s
91
+ ```
92
+
93
+ ## API Reference
94
+
95
+ ### Timer
96
+
97
+ Basic timer that tracks time and count.
98
+
99
+ - `add(n=1, by="increment")` - Add count and elapsed time
100
+ - `clear(reset_last_add_time=False)` - Reset timer
101
+ - `to_str(mode="pace")` - Get human-readable string
102
+ - Properties: `time`, `count`, `pace`, `speed`
103
+
104
+ ### NamedTimer
105
+
106
+ Extends Timer to track multiple named categories with separate time tracking.
107
+
108
+ ### ParallelTimer
109
+
110
+ Extends Timer to track multiple named categories with shared time.
111
+
112
+ ## License
113
+
114
+ MIT License - See LICENSE file for details.
@@ -0,0 +1,10 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/yumeow_timer/__init__.py
5
+ src/yumeow_timer/timing.py
6
+ src/yumeow_timer.egg-info/PKG-INFO
7
+ src/yumeow_timer.egg-info/SOURCES.txt
8
+ src/yumeow_timer.egg-info/dependency_links.txt
9
+ src/yumeow_timer.egg-info/requires.txt
10
+ src/yumeow_timer.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ numpy>=1.20.0
2
+ pandas>=1.3.0
@@ -0,0 +1 @@
1
+ yumeow_timer