mirror of
https://github.com/python/cpython.git
synced 2025-11-01 22:21:35 +00:00
gh-138535: Optimize fill_time for typical timestamps (#138537)
While file timestamps can be anything the file system can store, most lie between the recent past and the near future. Optimize fill_time() for typical timestamps in three ways: - When possible, convert to nanoseconds with C arithmetic. - When using C arithmetic and the seconds member is not required (for st_birthtime), avoid creating a long object. - When using C arithmetic, reorder the code to avoid the null checks implied in Py_XDECREF(). Co-authored-by: Victor Stinner <vstinner@python.org>
This commit is contained in:
parent
5edfe55acf
commit
d4825ac27c
3 changed files with 62 additions and 41 deletions
|
|
@ -1064,9 +1064,15 @@ def test_large_time(self):
|
|||
if self.get_file_system(self.dirname) != "NTFS":
|
||||
self.skipTest("requires NTFS")
|
||||
|
||||
large = 5000000000 # some day in 2128
|
||||
os.utime(self.fname, (large, large))
|
||||
self.assertEqual(os.stat(self.fname).st_mtime, large)
|
||||
times = (
|
||||
5000000000, # some day in 2128
|
||||
# boundaries of the fast path cutoff in posixmodule.c:fill_time
|
||||
-9223372037, -9223372036, 9223372035, 9223372036,
|
||||
)
|
||||
for large in times:
|
||||
with self.subTest(large=large):
|
||||
os.utime(self.fname, (large, large))
|
||||
self.assertEqual(os.stat(self.fname).st_mtime, large)
|
||||
|
||||
def test_utime_invalid_arguments(self):
|
||||
# seconds and nanoseconds parameters are mutually exclusive
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
Speed up :func:`os.stat` for files with reasonable timestamps. Contributed
|
||||
by Jeffrey Bosboom.
|
||||
|
|
@ -2588,55 +2588,68 @@ static int
|
|||
fill_time(PyObject *module, PyObject *v, int s_index, int f_index, int ns_index, time_t sec, unsigned long nsec)
|
||||
{
|
||||
assert(!PyErr_Occurred());
|
||||
|
||||
int res = -1;
|
||||
PyObject *s_in_ns = NULL;
|
||||
PyObject *ns_total = NULL;
|
||||
PyObject *float_s = NULL;
|
||||
|
||||
PyObject *s = _PyLong_FromTime_t(sec);
|
||||
PyObject *ns_fractional = PyLong_FromUnsignedLong(nsec);
|
||||
if (!(s && ns_fractional)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
s_in_ns = PyNumber_Multiply(s, get_posix_state(module)->billion);
|
||||
if (!s_in_ns) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ns_total = PyNumber_Add(s_in_ns, ns_fractional);
|
||||
if (!ns_total)
|
||||
goto exit;
|
||||
|
||||
float_s = PyFloat_FromDouble(sec + 1e-9*nsec);
|
||||
if (!float_s) {
|
||||
goto exit;
|
||||
}
|
||||
#define SEC_TO_NS (1000000000LL)
|
||||
assert(nsec < SEC_TO_NS);
|
||||
|
||||
if (s_index >= 0) {
|
||||
PyObject *s = _PyLong_FromTime_t(sec);
|
||||
if (s == NULL) {
|
||||
return -1;
|
||||
}
|
||||
PyStructSequence_SET_ITEM(v, s_index, s);
|
||||
s = NULL;
|
||||
}
|
||||
|
||||
if (f_index >= 0) {
|
||||
PyObject *float_s = PyFloat_FromDouble((double)sec + 1e-9 * nsec);
|
||||
if (float_s == NULL) {
|
||||
return -1;
|
||||
}
|
||||
PyStructSequence_SET_ITEM(v, f_index, float_s);
|
||||
float_s = NULL;
|
||||
}
|
||||
|
||||
int res = -1;
|
||||
if (ns_index >= 0) {
|
||||
PyStructSequence_SET_ITEM(v, ns_index, ns_total);
|
||||
ns_total = NULL;
|
||||
/* 1677-09-21 00:12:44 to 2262-04-11 23:47:15 UTC inclusive */
|
||||
if ((LLONG_MIN/SEC_TO_NS) <= sec && sec <= (LLONG_MAX/SEC_TO_NS - 1)) {
|
||||
PyObject *ns_total = PyLong_FromLongLong(sec * SEC_TO_NS + nsec);
|
||||
if (ns_total == NULL) {
|
||||
return -1;
|
||||
}
|
||||
PyStructSequence_SET_ITEM(v, ns_index, ns_total);
|
||||
assert(!PyErr_Occurred());
|
||||
res = 0;
|
||||
}
|
||||
else {
|
||||
PyObject *s_in_ns = NULL;
|
||||
PyObject *ns_total = NULL;
|
||||
PyObject *s = _PyLong_FromTime_t(sec);
|
||||
PyObject *ns_fractional = PyLong_FromUnsignedLong(nsec);
|
||||
if (s == NULL || ns_fractional == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
s_in_ns = PyNumber_Multiply(s, get_posix_state(module)->billion);
|
||||
if (s_in_ns == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ns_total = PyNumber_Add(s_in_ns, ns_fractional);
|
||||
if (ns_total == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
PyStructSequence_SET_ITEM(v, ns_index, ns_total);
|
||||
assert(!PyErr_Occurred());
|
||||
res = 0;
|
||||
|
||||
exit:
|
||||
Py_XDECREF(s);
|
||||
Py_XDECREF(ns_fractional);
|
||||
Py_XDECREF(s_in_ns);
|
||||
}
|
||||
}
|
||||
|
||||
assert(!PyErr_Occurred());
|
||||
res = 0;
|
||||
|
||||
exit:
|
||||
Py_XDECREF(s);
|
||||
Py_XDECREF(ns_fractional);
|
||||
Py_XDECREF(s_in_ns);
|
||||
Py_XDECREF(ns_total);
|
||||
Py_XDECREF(float_s);
|
||||
return res;
|
||||
#undef SEC_TO_NS
|
||||
}
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue