mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 07:31:38 +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,7 +1064,13 @@ def test_large_time(self):
 | 
			
		|||
        if self.get_file_system(self.dirname) != "NTFS":
 | 
			
		||||
            self.skipTest("requires NTFS")
 | 
			
		||||
 | 
			
		||||
        large = 5000000000   # some day in 2128
 | 
			
		||||
        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)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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());
 | 
			
		||||
#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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int res = -1;
 | 
			
		||||
    if (ns_index >= 0) {
 | 
			
		||||
        /* 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 *float_s = NULL;
 | 
			
		||||
 | 
			
		||||
            PyObject *s = _PyLong_FromTime_t(sec);
 | 
			
		||||
            PyObject *ns_fractional = PyLong_FromUnsignedLong(nsec);
 | 
			
		||||
    if (!(s && ns_fractional)) {
 | 
			
		||||
            if (s == NULL || ns_fractional == NULL) {
 | 
			
		||||
                goto exit;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            s_in_ns = PyNumber_Multiply(s, get_posix_state(module)->billion);
 | 
			
		||||
    if (!s_in_ns) {
 | 
			
		||||
            if (s_in_ns == NULL) {
 | 
			
		||||
                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) {
 | 
			
		||||
            if (ns_total == NULL) {
 | 
			
		||||
                goto exit;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
    if (s_index >= 0) {
 | 
			
		||||
        PyStructSequence_SET_ITEM(v, s_index, s);
 | 
			
		||||
        s = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    if (f_index >= 0) {
 | 
			
		||||
        PyStructSequence_SET_ITEM(v, f_index, float_s);
 | 
			
		||||
        float_s = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    if (ns_index >= 0) {
 | 
			
		||||
            PyStructSequence_SET_ITEM(v, ns_index, ns_total);
 | 
			
		||||
        ns_total = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
            assert(!PyErr_Occurred());
 | 
			
		||||
            res = 0;
 | 
			
		||||
 | 
			
		||||
exit:
 | 
			
		||||
        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