Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit28d2357

Browse files
committed
gh-88494: Use QueryPerformanceCounter() for time.monotonic()
On Windows, time.monotonic() now uses the QueryPerformanceCounter()clock to have a resolution better than 1 us, instead of thegGetTickCount64() clock which has a resolution of 15.6 ms.
1 parent3a25d9c commit28d2357

File tree

4 files changed

+110
-138
lines changed

4 files changed

+110
-138
lines changed

‎Doc/library/time.rst

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,15 @@ Functions
287287
The reference point of the returned value is undefined, so that only the
288288
difference between the results of two calls is valid.
289289

290+
Clock:
291+
292+
* On Windows, call ``QueryPerformanceCounter()`` and
293+
``QueryPerformanceFrequency()``.
294+
* On macOS, call ``mach_absolute_time()`` and ``mach_timebase_info()``.
295+
* On HP-UX, call ``gethrtime()``.
296+
* Call ``clock_gettime(CLOCK_HIGHRES)`` if available.
297+
* Otherwise, call ``clock_gettime(CLOCK_MONOTONIC)``.
298+
290299
Use:func:`monotonic_ns` to avoid the precision loss caused by the
291300
:class:`float` type.
292301

@@ -316,6 +325,11 @@ Functions
316325
point of the returned value is undefined, so that only the difference between
317326
the results of two calls is valid.
318327

328+
..impl-detail::
329+
330+
On CPython, use the same clock than:func:`time.monotonic()` and is a
331+
monotonic clock, i.e. a clock that cannot go backwards.
332+
319333
Use:func:`perf_counter_ns` to avoid the precision loss caused by the
320334
:class:`float` type.
321335

@@ -324,6 +338,10 @@ Functions
324338
..versionchanged::3.10
325339
On Windows, the function is now system-wide.
326340

341+
..versionchanged::3.13
342+
Use the same clock than:func:`time.monotonic()`.
343+
344+
327345
..function::perf_counter_ns() -> int
328346

329347
Similar to:func:`perf_counter`, but return time as nanoseconds.
@@ -666,6 +684,12 @@ Functions
666684
:class:`struct_time` object is returned, from which the components
667685
of the calendar date may be accessed as attributes.
668686

687+
Clock:
688+
689+
* On Windows, call ``GetSystemTimeAsFileTime()``.
690+
* Call ``clock_gettime(CLOCK_REALTIME)`` if available.
691+
* Otherwise, call ``gettimeofday()``.
692+
669693
Use:func:`time_ns` to avoid the precision loss caused by the:class:`float`
670694
type.
671695

‎Doc/whatsnew/3.13.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,15 @@ sys
552552
This function is not guaranteed to exist in all implementations of Python.
553553
(Contributed by Serhiy Storchaka in:gh:`78573`.)
554554

555+
time
556+
----
557+
558+
* On Windows,:func:`time.monotonic()` now uses the
559+
``QueryPerformanceCounter()`` clock to have a resolution better than 1 us,
560+
instead of the ``GetTickCount64()`` clock which has a resolution of 15.6 ms.
561+
(Contributed by Victor Stinner in:gh:`88494`.)
562+
563+
555564
tkinter
556565
-------
557566

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
On Windows,:func:`time.monotonic()` now uses the ``QueryPerformanceCounter()``
2+
clock to have a resolution better than 1 us, instead of the
3+
``GetTickCount64()`` clock which has a resolution of 15.6 ms. Patch by Victor
4+
Stinner.

‎Python/pytime.c

Lines changed: 73 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,9 +1027,76 @@ _PyTime_TimeWithInfo(PyTime_t *t, _Py_clock_info_t *info)
10271027
}
10281028

10291029

1030+
#ifdefMS_WINDOWS
1031+
staticint
1032+
py_win_perf_counter_frequency(_PyTimeFraction*base,intraise_exc)
1033+
{
1034+
LARGE_INTEGERfreq;
1035+
// Since Windows XP, the function cannot fail.
1036+
(void)QueryPerformanceFrequency(&freq);
1037+
LONGLONGfrequency=freq.QuadPart;
1038+
1039+
// Since Windows XP, frequency cannot be zero.
1040+
assert(frequency >=1);
1041+
1042+
Py_BUILD_ASSERT(sizeof(PyTime_t)==sizeof(frequency));
1043+
PyTime_tdenom= (PyTime_t)frequency;
1044+
1045+
// Known QueryPerformanceFrequency() values:
1046+
//
1047+
// * 10,000,000 (10 MHz): 100 ns resolution
1048+
// * 3,579,545 Hz (3.6 MHz): 279 ns resolution
1049+
if (_PyTimeFraction_Set(base,SEC_TO_NS,denom)<0) {
1050+
if (raise_exc) {
1051+
PyErr_SetString(PyExc_RuntimeError,
1052+
"invalid QueryPerformanceFrequency");
1053+
}
1054+
return-1;
1055+
}
1056+
return0;
1057+
}
1058+
1059+
1060+
// N.B. If raise_exc=0, this may be called without the GIL.
1061+
staticint
1062+
py_get_win_perf_counter(PyTime_t*tp,_Py_clock_info_t*info,intraise_exc)
1063+
{
1064+
assert(info==NULL||raise_exc);
1065+
1066+
static_PyTimeFractionbase= {0,0};
1067+
if (base.denom==0) {
1068+
if (py_win_perf_counter_frequency(&base,raise_exc)<0) {
1069+
return-1;
1070+
}
1071+
}
1072+
1073+
if (info) {
1074+
info->implementation="QueryPerformanceCounter()";
1075+
info->resolution=_PyTimeFraction_Resolution(&base);
1076+
info->monotonic=1;
1077+
info->adjustable=0;
1078+
}
1079+
1080+
LARGE_INTEGERnow;
1081+
QueryPerformanceCounter(&now);
1082+
LONGLONGticksll=now.QuadPart;
1083+
1084+
/* Make sure that casting LONGLONG to PyTime_t cannot overflow,
1085+
both types are signed */
1086+
PyTime_tticks;
1087+
static_assert(sizeof(ticksll) <=sizeof(ticks),
1088+
"LONGLONG is larger than PyTime_t");
1089+
ticks= (PyTime_t)ticksll;
1090+
1091+
*tp=_PyTimeFraction_Mul(ticks,&base);
1092+
return0;
1093+
}
1094+
#endif// MS_WINDOWS
1095+
1096+
10301097
#ifdef__APPLE__
10311098
staticint
1032-
py_mach_timebase_info(_PyTimeFraction*base,intraise)
1099+
py_mach_timebase_info(_PyTimeFraction*base,intraise_exc)
10331100
{
10341101
mach_timebase_info_data_ttimebase;
10351102
// According to the Technical Q&A QA1398, mach_timebase_info() cannot
@@ -1051,7 +1118,7 @@ py_mach_timebase_info(_PyTimeFraction *base, int raise)
10511118
// * (1000000000, 33333335) on PowerPC: ~30 ns
10521119
// * (1000000000, 25000000) on PowerPC: 40 ns
10531120
if (_PyTimeFraction_Set(base,numer,denom)<0) {
1054-
if (raise) {
1121+
if (raise_exc) {
10551122
PyErr_SetString(PyExc_RuntimeError,
10561123
"invalid mach_timebase_info");
10571124
}
@@ -1069,42 +1136,9 @@ py_get_monotonic_clock(PyTime_t *tp, _Py_clock_info_t *info, int raise_exc)
10691136
assert(info==NULL||raise_exc);
10701137

10711138
#if defined(MS_WINDOWS)
1072-
ULONGLONGticks=GetTickCount64();
1073-
static_assert(sizeof(ticks) <=sizeof(PyTime_t),
1074-
"ULONGLONG is larger than PyTime_t");
1075-
PyTime_tt;
1076-
if (ticks <= (ULONGLONG)PyTime_MAX) {
1077-
t= (PyTime_t)ticks;
1078-
}
1079-
else {
1080-
// GetTickCount64() maximum is larger than PyTime_t maximum:
1081-
// ULONGLONG is unsigned, whereas PyTime_t is signed.
1082-
t=PyTime_MAX;
1083-
}
1084-
1085-
intres=pytime_mul(&t,MS_TO_NS);
1086-
*tp=t;
1087-
1088-
if (raise_exc&&res<0) {
1089-
pytime_overflow();
1139+
if (py_get_win_perf_counter(tp,info,raise_exc)<0) {
10901140
return-1;
10911141
}
1092-
1093-
if (info) {
1094-
DWORDtimeAdjustment,timeIncrement;
1095-
BOOLisTimeAdjustmentDisabled,ok;
1096-
info->implementation="GetTickCount64()";
1097-
info->monotonic=1;
1098-
ok=GetSystemTimeAdjustment(&timeAdjustment,&timeIncrement,
1099-
&isTimeAdjustmentDisabled);
1100-
if (!ok) {
1101-
PyErr_SetFromWindowsErr(0);
1102-
return-1;
1103-
}
1104-
info->resolution=timeIncrement*1e-7;
1105-
info->adjustable=0;
1106-
}
1107-
11081142
#elif defined(__APPLE__)
11091143
static_PyTimeFractionbase= {0,0};
11101144
if (base.denom==0) {
@@ -1190,8 +1224,7 @@ _PyTime_MonotonicUnchecked(void)
11901224
{
11911225
PyTime_tt;
11921226
if (py_get_monotonic_clock(&t,NULL,0)<0) {
1193-
// If mach_timebase_info(), clock_gettime() or gethrtime() fails:
1194-
// silently ignore the failure and return 0.
1227+
// Ignore silently the error and return 0.
11951228
t=0;
11961229
}
11971230
returnt;
@@ -1216,122 +1249,24 @@ _PyTime_MonotonicWithInfo(PyTime_t *tp, _Py_clock_info_t *info)
12161249
}
12171250

12181251

1219-
#ifdefMS_WINDOWS
1220-
staticint
1221-
py_win_perf_counter_frequency(_PyTimeFraction*base,intraise)
1222-
{
1223-
LONGLONGfrequency;
1224-
1225-
LARGE_INTEGERfreq;
1226-
// Since Windows XP, the function cannot fail.
1227-
(void)QueryPerformanceFrequency(&freq);
1228-
frequency=freq.QuadPart;
1229-
1230-
// Since Windows XP, frequency cannot be zero.
1231-
assert(frequency >=1);
1232-
1233-
Py_BUILD_ASSERT(sizeof(PyTime_t)==sizeof(frequency));
1234-
PyTime_tdenom= (PyTime_t)frequency;
1235-
1236-
// Known QueryPerformanceFrequency() values:
1237-
//
1238-
// * 10,000,000 (10 MHz): 100 ns resolution
1239-
// * 3,579,545 Hz (3.6 MHz): 279 ns resolution
1240-
if (_PyTimeFraction_Set(base,SEC_TO_NS,denom)<0) {
1241-
if (raise) {
1242-
PyErr_SetString(PyExc_RuntimeError,
1243-
"invalid QueryPerformanceFrequency");
1244-
}
1245-
return-1;
1246-
}
1247-
return0;
1248-
}
1249-
1250-
1251-
// N.B. If raise_exc=0, this may be called without the GIL.
1252-
staticint
1253-
py_get_win_perf_counter(PyTime_t*tp,_Py_clock_info_t*info,intraise_exc)
1254-
{
1255-
assert(info==NULL||raise_exc);
1256-
1257-
static_PyTimeFractionbase= {0,0};
1258-
if (base.denom==0) {
1259-
if (py_win_perf_counter_frequency(&base,raise_exc)<0) {
1260-
return-1;
1261-
}
1262-
}
1263-
1264-
if (info) {
1265-
info->implementation="QueryPerformanceCounter()";
1266-
info->resolution=_PyTimeFraction_Resolution(&base);
1267-
info->monotonic=1;
1268-
info->adjustable=0;
1269-
}
1270-
1271-
LARGE_INTEGERnow;
1272-
QueryPerformanceCounter(&now);
1273-
LONGLONGticksll=now.QuadPart;
1274-
1275-
/* Make sure that casting LONGLONG to PyTime_t cannot overflow,
1276-
both types are signed */
1277-
PyTime_tticks;
1278-
static_assert(sizeof(ticksll) <=sizeof(ticks),
1279-
"LONGLONG is larger than PyTime_t");
1280-
ticks= (PyTime_t)ticksll;
1281-
1282-
PyTime_tns=_PyTimeFraction_Mul(ticks,&base);
1283-
*tp=ns;
1284-
return0;
1285-
}
1286-
#endif// MS_WINDOWS
1287-
1288-
12891252
int
12901253
_PyTime_PerfCounterWithInfo(PyTime_t*t,_Py_clock_info_t*info)
12911254
{
1292-
#ifdefMS_WINDOWS
1293-
returnpy_get_win_perf_counter(t,info,1);
1294-
#else
12951255
return_PyTime_MonotonicWithInfo(t,info);
1296-
#endif
12971256
}
12981257

12991258

13001259
PyTime_t
13011260
_PyTime_PerfCounterUnchecked(void)
13021261
{
1303-
PyTime_tt;
1304-
intres;
1305-
#ifdefMS_WINDOWS
1306-
res=py_get_win_perf_counter(&t,NULL,0);
1307-
#else
1308-
res=py_get_monotonic_clock(&t,NULL,0);
1309-
#endif
1310-
if (res<0) {
1311-
// If py_win_perf_counter_frequency() or py_get_monotonic_clock()
1312-
// fails: silently ignore the failure and return 0.
1313-
t=0;
1314-
}
1315-
returnt;
1262+
return_PyTime_MonotonicUnchecked();
13161263
}
13171264

13181265

13191266
int
13201267
PyTime_PerfCounter(PyTime_t*result)
13211268
{
1322-
intres;
1323-
#ifdefMS_WINDOWS
1324-
res=py_get_win_perf_counter(result,NULL,1);
1325-
#else
1326-
res=py_get_monotonic_clock(result,NULL,1);
1327-
#endif
1328-
if (res<0) {
1329-
// If py_win_perf_counter_frequency() or py_get_monotonic_clock()
1330-
// fails: silently ignore the failure and return 0.
1331-
*result=0;
1332-
return-1;
1333-
}
1334-
return0;
1269+
returnPyTime_Monotonic(result);
13351270
}
13361271

13371272

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp