os.times() のバグ
Python 2.5 の os.times() はバグっていて、user time や system time の正しい値が採れない。
bench.py
def f(n):
if n <= 0:
return 1
else:
return f(n-1) + f(n-2)
import os, time
t1 = os.times()
f(34)
t2 = os.times()
utime = t2[0] - t1[0]
stime = t2[1] - t1[1]
total = utime + stime
print "utime %.4f, stime %.4f, total %.4f" % (utime, stime, total)
実行結果:
$ time python bench.py utime 38.6333, stime 0.1000, total 38.7333 real 0m23.787s user 0m23.211s sys 0m0.138s
これをみると分かるけど、real time は 23.8 秒しかかかってないってないのに、user time が 38.6 秒と報告されている。これが os.times() のバグ。
以下のパッチを Modules/posixmodules.c に当てて再度コンパイルすると直る。
--- Modules/posixmodule.c 2008-02-03 16:20:39.000000000 +0900
+++ Modules/posixmodule.c 2008-02-29 10:38:33.000000000 +0900
@@ -5782,25 +5782,25 @@
static PyObject *
posix_times(PyObject *self, PyObject *noargs)
{
struct tms t;
clock_t c;
errno = 0;
c = times(&t);
if (c == (clock_t) -1)
return posix_error();
return Py_BuildValue("ddddd",
- (double)t.tms_utime / HZ,
- (double)t.tms_stime / HZ,
- (double)t.tms_cutime / HZ,
- (double)t.tms_cstime / HZ,
- (double)c / HZ);
+ (double)t.tms_utime / CLK_TCK,
+ (double)t.tms_stime / CLK_TCK,
+ (double)t.tms_cutime / CLK_TCK,
+ (double)t.tms_cstime / CLK_TCK,
+ (double)c / CLK_TCK);
}
#endif /* not OS2 */
#endif /* HAVE_TIMES */
#ifdef MS_WINDOWS
#define HAVE_TIMES /* so the method table will pick it up */
static PyObject *
posix_times(PyObject *self, PyObject *noargs)
{
実行結果:
$ time python bench.py utime 23.1800, stime 0.0500, total 23.2300 real 0m23.487s user 0m23.211s sys 0m0.128s
Ya, 直ってる。
追記: 書き忘れてたけど環境は MacOS X 10.4, GCC 4.0.1。それからこのパッチよりコメントのパッチのほうがきれい。
追記2: ocean 氏のをパッチにしてみた。
--- Modules/posixmodule.c 2008-02-03 16:20:39.000000000 +0900 +++ Modules/posixmodule.c 2008-02-29 22:41:00.000000000 +0900 @@ -5749,11 +5749,17 @@ #endif /* HAVE_SYMLINK */ #ifdef HAVE_TIMES #ifndef HZ +#if defined(CLK_TCK) +#define HZ CLK_TCK +#elif defined(CLOCKS_PER_SEC) +#define HZ CLOCKS_PER_SEC +#else #define HZ 60 /* Universal constant :-) */ +#endif #endif /* HZ */ #if defined(PYCC_VACPP) && defined(PYOS_OS2) static long system_uptime(void)