Skip to content

Commit 2ff6eb6

Browse files
author
Release Manager
committed
sagemathgh-39007: Fix cpu time on Windows Currently, it uses `resources` which is not available on Windows. For cross-platform purposes, we change it to use `time.process_time()` instead. Also add type hints and minor reformating. <!-- ^ Please provide a concise and informative title. --> <!-- ^ Don't put issue numbers in the title, do this in the PR description below. --> <!-- ^ For example, instead of "Fixes sagemath#12345" use "Introduce new method to calculate 1 + 2". --> <!-- v Describe your changes below in detail. --> <!-- v Why is this change required? What problem does it solve? --> <!-- v If this PR resolves an open issue, please link to it here. For example, "Fixes sagemath#12345". --> ### 📝 Checklist <!-- Put an `x` in all the boxes that apply. --> - [ ] The title is concise and informative. - [ ] The description explains in detail what this PR is about. - [ ] I have linked a relevant issue or discussion. - [ ] I have created tests covering the changes. - [ ] I have updated the documentation and checked the documentation preview. ### ⌛ Dependencies <!-- List all open PRs that this PR logically depends on. For example, --> <!-- - sagemath#12345: short description why this is a dependency --> <!-- - sagemath#34567: ... --> URL: sagemath#39007 Reported by: Tobias Diez Reviewer(s):
2 parents e5546e9 + b11860f commit 2ff6eb6

File tree

2 files changed

+63
-49
lines changed

2 files changed

+63
-49
lines changed

src/sage/interfaces/interface.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ def _pre_interact(self):
203203
def _post_interact(self):
204204
pass
205205

206-
def cputime(self):
206+
def cputime(self) -> float:
207207
"""
208208
CPU time since this process started running.
209209
"""

src/sage/misc/timing.py

Lines changed: 62 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# pyright: strict
12
# sage_setup: distribution = sagemath-objects
23
r"""
34
Timing functions
@@ -17,24 +18,36 @@
1718
# https://www.gnu.org/licenses/
1819
# ****************************************************************************
1920

21+
from __future__ import annotations
2022

21-
import resource
2223
import time
24+
from typing import TYPE_CHECKING, overload
2325

26+
if TYPE_CHECKING:
27+
from weakref import ReferenceType
2428

25-
def cputime(t=0, subprocesses=False):
29+
from sage.interfaces.expect import Expect
30+
31+
32+
@overload
33+
def cputime(t: float = 0, subprocesses: bool = False) -> float: ...
34+
@overload
35+
def cputime(t: GlobalCputime, subprocesses: bool) -> GlobalCputime: ...
36+
37+
38+
def cputime(
39+
t: float | GlobalCputime = 0, subprocesses: bool = False
40+
) -> float | GlobalCputime:
2641
"""
2742
Return the time in CPU seconds since Sage started, or with
2843
optional argument ``t``, return the time since ``t``. This is how
29-
much time Sage has spent using the CPU. If ``subprocesses=False``
44+
much time Sage has spent using the CPU (to be precise, the sum of the system
45+
and user CPU times of the process). If ``subprocesses=False``
3046
this does not count time spent in subprocesses spawned by Sage
3147
(e.g., Gap, Singular, etc.). If ``subprocesses=True`` this
3248
function tries to take all subprocesses with a working
3349
``cputime()`` implementation into account.
3450
35-
The measurement for the main Sage process is done via a call to
36-
:func:`resource.getrusage()`.
37-
3851
INPUT:
3952
4053
- ``t`` -- (optional) time in CPU seconds, if ``t`` is a result
@@ -81,39 +94,39 @@ def cputime(t=0, subprocesses=False):
8194
t = float(t)
8295
except TypeError:
8396
t = 0.0
84-
u, s = resource.getrusage(resource.RUSAGE_SELF)[:2]
85-
return u + s - t
86-
else:
87-
try:
88-
from sage.interfaces.quit import expect_objects
89-
except ImportError:
90-
expect_objects = ()
91-
if t == 0:
92-
ret = GlobalCputime(cputime())
93-
for s in expect_objects:
94-
S = s()
95-
if S and S.is_running():
96-
try:
97-
ct = S.cputime()
98-
ret.total += ct
99-
ret.interfaces[s] = ct
100-
except NotImplementedError:
101-
pass
102-
return ret
103-
else:
104-
if not isinstance(t, GlobalCputime):
105-
t = GlobalCputime(t)
106-
ret = GlobalCputime(cputime() - t.local)
107-
for s in expect_objects:
108-
S = s()
109-
if S and S.is_running():
110-
try:
111-
ct = S.cputime() - t.interfaces.get(s, 0.0)
112-
ret.total += ct
113-
ret.interfaces[s] = ct
114-
except NotImplementedError:
115-
pass
116-
return ret
97+
return time.process_time() - t
98+
99+
try:
100+
from sage.interfaces.quit import expect_objects
101+
except ImportError:
102+
expect_objects = ()
103+
104+
if t == 0:
105+
ret = GlobalCputime(cputime())
106+
for reference in expect_objects:
107+
process = reference()
108+
if process and process.is_running():
109+
try:
110+
ct = process.cputime()
111+
ret.total += ct
112+
ret.interfaces[reference] = ct
113+
except NotImplementedError:
114+
pass
115+
return ret
116+
117+
if not isinstance(t, GlobalCputime):
118+
t = GlobalCputime(t)
119+
ret = GlobalCputime(cputime() - t.local)
120+
for reference in expect_objects:
121+
process = reference()
122+
if process and process.is_running():
123+
try:
124+
ct = process.cputime() - t.interfaces.get(reference, 0.0)
125+
ret.total += ct
126+
ret.interfaces[reference] = ct
127+
except NotImplementedError:
128+
pass
129+
return ret
117130

118131

119132
class GlobalCputime:
@@ -153,7 +166,8 @@ class GlobalCputime:
153166
154167
:func:`cputime`
155168
"""
156-
def __init__(self, t):
169+
170+
def __init__(self, t: float) -> None:
157171
"""
158172
Create a new CPU time object which also keeps track of
159173
subprocesses.
@@ -164,11 +178,11 @@ def __init__(self, t):
164178
sage: ct = GlobalCputime(0.0); ct
165179
0.0...
166180
"""
167-
self.total = t
168-
self.local = t
169-
self.interfaces = {}
181+
self.total: float = t
182+
self.local: float = t
183+
self.interfaces: dict[ReferenceType[Expect], float] = {}
170184

171-
def __repr__(self):
185+
def __repr__(self) -> str:
172186
"""
173187
EXAMPLES::
174188
@@ -177,7 +191,7 @@ def __repr__(self):
177191
"""
178192
return str(self.total)
179193

180-
def __add__(self, other):
194+
def __add__(self, other: GlobalCputime | float) -> GlobalCputime:
181195
"""
182196
EXAMPLES::
183197
@@ -193,7 +207,7 @@ def __add__(self, other):
193207
ret = GlobalCputime(self.total + other.total)
194208
return ret
195209

196-
def __sub__(self, other):
210+
def __sub__(self, other: GlobalCputime | float) -> GlobalCputime:
197211
"""
198212
EXAMPLES::
199213
@@ -209,7 +223,7 @@ def __sub__(self, other):
209223
ret = GlobalCputime(self.total - other.total)
210224
return ret
211225

212-
def __float__(self):
226+
def __float__(self) -> float:
213227
"""
214228
EXAMPLES::
215229
@@ -220,7 +234,7 @@ def __float__(self):
220234
return float(self.total)
221235

222236

223-
def walltime(t=0):
237+
def walltime(t: float = 0) -> float:
224238
"""
225239
Return the wall time in second, or with optional argument ``t``, return
226240
the wall time since time ``t``. "Wall time" means the time on a wall

0 commit comments

Comments
 (0)