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)