ruby-changes:30587
From: akr <ko1@a...>
Date: Fri, 23 Aug 2013 19:44:40 +0900 (JST)
Subject: [ruby-changes:30587] akr:r42666 (trunk): * process.c (gcd_ul): New function.
akr 2013-08-23 19:44:33 +0900 (Fri, 23 Aug 2013) New Revision: 42666 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=42666 Log: * process.c (gcd_ul): New function. (reduce_fraction): Ditto. (reduce_fraction): Ditto. (timetick2dblnum): Ditto. (timetick2integer): Ditto. (make_clock_result): Use timetick2dblnum and timetick2integer. (rb_clock_gettime): Follow the make_clock_result change. Modified files: trunk/ChangeLog trunk/process.c Index: ChangeLog =================================================================== --- ChangeLog (revision 42665) +++ ChangeLog (revision 42666) @@ -1,3 +1,13 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Fri Aug 23 19:40:50 2013 Tanaka Akira <akr@f...> + + * process.c (gcd_ul): New function. + (reduce_fraction): Ditto. + (reduce_fraction): Ditto. + (timetick2dblnum): Ditto. + (timetick2integer): Ditto. + (make_clock_result): Use timetick2dblnum and timetick2integer. + (rb_clock_gettime): Follow the make_clock_result change. + Fri Aug 23 18:39:04 2013 Koichi Sasada <ko1@a...> * array.c (ary_make_shared): shared ary as shady. Need more effort to Index: process.c =================================================================== --- process.c (revision 42665) +++ process.c (revision 42666) @@ -6667,51 +6667,119 @@ rb_proc_times(VALUE obj) https://github.com/ruby/ruby/blob/trunk/process.c#L6667 #define rb_proc_times rb_f_notimplement #endif -static VALUE -make_clock_result(struct timespec *tsp, VALUE unit) +static unsigned long +gcd_ul(unsigned long a, unsigned long b) { - long factor; + unsigned long t; - if (unit == ID2SYM(rb_intern("nanosecond"))) { - factor = 1000000000; - goto return_integer; - } - else if (unit == ID2SYM(rb_intern("microsecond"))) { - factor = 1000000; - goto return_integer; - } - else if (unit == ID2SYM(rb_intern("millisecond"))) { - factor = 1000; - goto return_integer; - } - else if (unit == ID2SYM(rb_intern("float_microsecond"))) { - factor = 1000000; - goto return_float; - } - else if (unit == ID2SYM(rb_intern("float_millisecond"))) { - factor = 1000; - goto return_float; + if (a < b) { + t = a; + a = b; + b = t; } - else if (NIL_P(unit) || unit == ID2SYM(rb_intern("float_second"))) { - factor = 1; - goto return_float; + + while (1) { + t = a % b; + if (t == 0) + return b; + a = b; + b = t; } - else { - rb_raise(rb_eArgError, "unexpected unit: %"PRIsVALUE, unit); +} + +static void +reduce_fraction(unsigned long *np, unsigned long *dp) +{ + unsigned long gcd = gcd_ul(*np, *dp); + if (gcd != 1) { + *np /= gcd; + *dp /= gcd; } +} + +#ifdef HAVE_LONG_LONG +typedef LONG_LONG timetick_giga_count_t; +#define TIMETICK_GIGA_COUNT_MIN LLONG_MIN +#define TIMETICK_GIGA_COUNT_MAX LLONG_MAX +#define TIMETICK_GIGA_COUNT2NUM(v) LL2NUM(v) +#else +typedef long timetick_giga_count_t; +#define TIMETICK_GIGA_COUNT_MIN LONG_MIN +#define TIMETICK_GIGA_COUNT_MAX LONG_MAX +#define TIMETICK_GIGA_COUNT2NUM(v) LONG2NUM(v) +#endif + +struct timetick { + timetick_giga_count_t giga_count; + long count; /* 0 .. 999999999 */ +}; + +static double +timetick2dblnum(struct timetick *ttp, unsigned long numerator, unsigned long denominator, unsigned long factor) +{ + if (factor != 1 && denominator != 1) + reduce_fraction(&factor, &denominator); + if (numerator != 1 && denominator != 1) + reduce_fraction(&numerator, &denominator); + return DBL2NUM(((ttp->giga_count * 1e9 + ttp->count) * numerator * factor) / denominator); +} - return_float: - return DBL2NUM((tsp->tv_sec + 1e-9 * (double)tsp->tv_nsec) / factor); +#define NDIV(x,y) (-(-((x)+1)/(y))-1) +#define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d)) - return_integer: -#if defined(HAVE_LONG_LONG) - if (!MUL_OVERFLOW_SIGNED_INTEGER_P(factor, (LONG_LONG)tsp->tv_sec, - LLONG_MIN, LLONG_MAX-(factor-1))) { - return LL2NUM(tsp->tv_nsec/(1000000000/factor) + factor * (LONG_LONG)tsp->tv_sec); +static VALUE +timetick2integer(struct timetick *ttp, unsigned long numerator, unsigned long denominator, unsigned long factor) +{ + VALUE v; + + if (denominator != 1 && factor != 1) + reduce_fraction(&factor, &denominator); + if (denominator != 1 && numerator != 1) + reduce_fraction(&numerator, &denominator); + + if (numerator <= LONG_MAX && factor <= LONG_MAX) { + if (!MUL_OVERFLOW_SIGNED_INTEGER_P(1000000000, ttp->giga_count, + TIMETICK_GIGA_COUNT_MIN, TIMETICK_GIGA_COUNT_MAX-ttp->count)) { + timetick_giga_count_t t = ttp->giga_count * 1000000000 + ttp->count; + if (!MUL_OVERFLOW_SIGNED_INTEGER_P((long)numerator, t, + TIMETICK_GIGA_COUNT_MIN, TIMETICK_GIGA_COUNT_MAX)) { + t *= numerator; + if (!MUL_OVERFLOW_SIGNED_INTEGER_P((long)factor, t, + TIMETICK_GIGA_COUNT_MIN, TIMETICK_GIGA_COUNT_MAX)) { + t *= factor; + t = DIV(t, denominator); + return TIMETICK_GIGA_COUNT2NUM(t); + } + } + } } -#endif - return rb_funcall(LONG2FIX(tsp->tv_nsec/(1000000000/factor)), '+', 1, - rb_funcall(LONG2FIX(factor), '*', 1, TIMET2NUM(tsp->tv_sec))); + + v = TIMETICK_GIGA_COUNT2NUM(ttp->giga_count); + v = rb_funcall(v, '*', 1, LONG2FIX(1000000000)); + v = rb_funcall(v, '+', 1, LONG2FIX(ttp->count)); + v = rb_funcall(v, '*', 1, ULONG2NUM(numerator)); + v = rb_funcall(v, '*', 1, ULONG2NUM(factor)); + v = rb_funcall(v, '/', 1, ULONG2NUM(denominator)); /* Ruby's '/' is div. */ + return v; +} + +static VALUE +make_clock_result(struct timetick *ttp, unsigned long numerator, unsigned long denominator, VALUE unit) +{ + if (unit == ID2SYM(rb_intern("nanosecond"))) + return timetick2integer(ttp, numerator, denominator, 1000000000); + else if (unit == ID2SYM(rb_intern("microsecond"))) + return timetick2integer(ttp, numerator, denominator, 1000000); + else if (unit == ID2SYM(rb_intern("millisecond"))) + return timetick2integer(ttp, numerator, denominator, 1000); + else if (unit == ID2SYM(rb_intern("float_microsecond"))) + return timetick2dblnum(ttp, numerator, denominator, 1000000); + else if (unit == ID2SYM(rb_intern("float_millisecond"))) + return timetick2dblnum(ttp, numerator, denominator, 1000); + else if (NIL_P(unit) || unit == ID2SYM(rb_intern("float_second"))) + return timetick2dblnum(ttp, numerator, denominator, 1); + else + rb_raise(rb_eArgError, "unexpected unit: %"PRIsVALUE, unit); } /* @@ -6824,6 +6892,10 @@ rb_clock_gettime(int argc, VALUE *argv) https://github.com/ruby/ruby/blob/trunk/process.c#L6892 VALUE clk_id, unit; int ret; + struct timetick tt; + unsigned long numerator; + unsigned long denominator; + rb_scan_args(argc, argv, "11", &clk_id, &unit); if (SYMBOL_P(clk_id)) { @@ -6840,8 +6912,10 @@ rb_clock_gettime(int argc, VALUE *argv) https://github.com/ruby/ruby/blob/trunk/process.c#L6912 ret = gettimeofday(&tv, 0); if (ret != 0) rb_sys_fail("gettimeofday"); - ts.tv_sec = tv.tv_sec; - ts.tv_nsec = tv.tv_usec * 1000; + tt.giga_count = tv.tv_sec; + tt.count = tv.tv_usec * 1000; + numerator = 1; + denominator = 1000000000; goto success; } @@ -6851,8 +6925,10 @@ rb_clock_gettime(int argc, VALUE *argv) https://github.com/ruby/ruby/blob/trunk/process.c#L6925 t = time(NULL); if (t == (time_t)-1) rb_sys_fail("time"); - ts.tv_sec = t; - ts.tv_nsec = 0; + tt.giga_count = t; + tt.count = 0; + numerator = 1; + denominator = 1000000000; goto success; } @@ -6865,13 +6941,15 @@ rb_clock_gettime(int argc, VALUE *argv) https://github.com/ruby/ruby/blob/trunk/process.c#L6941 ret = getrusage(RUSAGE_SELF, &usage); if (ret != 0) rb_sys_fail("getrusage"); - ts.tv_sec = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec; + tt.giga_count = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec; usec = usage.ru_utime.tv_usec + usage.ru_stime.tv_usec; if (1000000 <= usec) { - ts.tv_sec++; + tt.giga_count++; usec -= 1000000; } - ts.tv_nsec = usec * 1000; + tt.count = usec * 1000; + numerator = 1; + denominator = 1000000000; goto success; } #endif @@ -6880,13 +6958,20 @@ rb_clock_gettime(int argc, VALUE *argv) https://github.com/ruby/ruby/blob/trunk/process.c#L6958 #define RUBY_POSIX_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID \ ID2SYM(rb_intern("POSIX_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID")) if (clk_id == RUBY_POSIX_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) { - double ns; struct tms buf; + unsigned_clock_t utime, stime; if (times(&buf) == (clock_t)-1) rb_sys_fail("times"); - ns = ((double)buf.tms_utime + buf.tms_stime) * (1e9 / get_clk_tck()); - ts.tv_sec = (time_t)(ns*1e-9); - ts.tv_nsec = (long)(ns - ts.tv_sec*1e9); + utime = (unsigned_clock_t)buf.tms_utime; + stime = (unsigned_clock_t)buf.tms_stime; + tt.count = (utime % 1000000000) + (stime % 1000000000); + tt.giga_count = (utime / 1000000000) + (stime / 1000000000); + if (1000000000 <= tt.count) { + tt.count -= 1000000000; + tt.giga_count++; + } + numerator = 1; + denominator = get_clk_tck(); goto success; } #endif @@ -6894,18 +6979,17 @@ rb_clock_gettime(int argc, VALUE *argv) https://github.com/ruby/ruby/blob/trunk/process.c#L6979 #define RUBY_ISO_C_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID \ ID2SYM(rb_intern("ISO_C_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID")) if (clk_id == RUBY_ISO_C_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) { - double s, ns; clock_t c; unsigned_clock_t uc; - c = clock(); errno = 0; + c = clock(); if (c == (clock_t)-1) rb_sys_fail("clock"); uc = (unsigned_clock_t)c; - ns = (uc*1e9) / CLOCKS_PER_SEC; /* uc*1e9 doesn't lose data if clock_t is 32bit. */ - s = floor(ns*1e-9); - ts.tv_sec = (time_t)s; - ts.tv_nsec = (long)(ns - s*1e9); + tt.count = uc % 1000000000; + tt.giga_count = uc / 1000000000; + numerator = 1; + denominator = CLOCKS_PER_SEC; goto success; } @@ -6919,10 +7003,10 @@ rb_clock_gettime(int argc, VALUE *argv) https://github.com/ruby/ruby/blob/trunk/process.c#L7003 (void) mach_timebase_info(&sTimebaseInfo); } - t = t * sTimebaseInfo.numer / sTimebaseInfo.denom; - /* TODO: time_t overflow */ - ts.tv_sec = (time_t)(t / 1000000000); - ts.tv_nsec = t % 1000000000; + tt.count = t % 1000000000; + tt.giga_count = t / 1000000000; + numerator = sTimebaseInfo.numer; + denominator = sTimebaseInfo.denom; goto success; } #endif @@ -6934,6 +7018,10 @@ rb_clock_gettime(int argc, VALUE *argv) https://github.com/ruby/ruby/blob/trunk/process.c#L7018 ret = clock_gettime(c, &ts); if (ret == -1) rb_sys_fail("clock_gettime"); + tt.count = ts.tv_nsec; + tt.giga_count = ts.tv_sec; + numerator = 1; + denominator = 1000000000; goto success; #endif } @@ -6942,7 +7030,7 @@ rb_clock_gettime(int argc, VALUE *argv) https://github.com/ruby/ruby/blob/trunk/process.c#L7030 rb_sys_fail(0); success: - return make_clock_result(&ts, unit); + return make_clock_result(&tt, numerator, denominator, unit); } VALUE rb_mProcess; -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/