[前][次][番号順一覧][スレッド一覧]

ruby-changes:30665

From: akr <ko1@a...>
Date: Sat, 31 Aug 2013 22:21:57 +0900 (JST)
Subject: [ruby-changes:30665] akr:r42744 (trunk): * process.c (rb_clock_getres): New method.

akr	2013-08-31 22:21:48 +0900 (Sat, 31 Aug 2013)

  New Revision: 42744

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=42744

  Log:
    * process.c (rb_clock_getres): New method.
      (timetick2dblnum_reciprocal): New function.
    
    * configure.in: Check clock_getres.
    
    [ruby-core:56780] [Feature #8809] accepted at
    DevelopersMeeting20130831Japan
    https://bugs.ruby-lang.org/projects/ruby/wiki/DevelopersMeeting20130831Japan

  Modified files:
    trunk/ChangeLog
    trunk/configure.in
    trunk/process.c
    trunk/test/ruby/test_process.rb
Index: configure.in
===================================================================
--- configure.in	(revision 42743)
+++ configure.in	(revision 42744)
@@ -1877,6 +1877,7 @@ if test x"$ac_cv_func_clock_gettime" != https://github.com/ruby/ruby/blob/trunk/configure.in#L1877
 	AC_DEFINE(HAVE_CLOCK_GETTIME, 1)
     fi
 fi
+AC_CHECK_FUNCS(clock_getres) # clock_getres should be tested after clock_gettime test including librt test.
 
 AC_CACHE_CHECK(for unsetenv returns a value, rb_cv_unsetenv_return_value,
   [AC_TRY_COMPILE([
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 42743)
+++ ChangeLog	(revision 42744)
@@ -1,3 +1,14 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Sat Aug 31 22:18:29 2013  Tanaka Akira  <akr@f...>
+
+	* process.c (rb_clock_getres): New method.
+	  (timetick2dblnum_reciprocal): New function.
+
+	* configure.in: Check clock_getres.
+
+	[ruby-core:56780] [Feature #8809] accepted at
+	DevelopersMeeting20130831Japan
+	https://bugs.ruby-lang.org/projects/ruby/wiki/DevelopersMeeting20130831Japan
+
 Sat Aug 31 21:02:07 2013  Tanaka Akira  <akr@f...>
 
 	* bignum.c: Use GMP to accelerate big Bignum multiplication.
Index: process.c
===================================================================
--- process.c	(revision 42743)
+++ process.c	(revision 42744)
@@ -6751,6 +6751,27 @@ timetick2dblnum(struct timetick *ttp, https://github.com/ruby/ruby/blob/trunk/process.c#L6751
     return DBL2NUM(d);
 }
 
+static VALUE
+timetick2dblnum_reciprocal(struct timetick *ttp,
+    timetick_int_t *numerators, int num_numerators,
+    timetick_int_t *denominators, int num_denominators)
+{
+    double d;
+    int i;
+
+    reduce_factors(numerators, num_numerators,
+                   denominators, num_denominators);
+
+    d = 1.0;
+    for (i = 0; i < num_denominators; i++)
+        d *= denominators[i];
+    for (i = 0; i < num_numerators; i++)
+        d /= numerators[i];
+    d /= ttp->giga_count * 1e9 + ttp->count;
+
+    return DBL2NUM(d);
+}
+
 #define NDIV(x,y) (-(-((x)+1)/(y))-1)
 #define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
 
@@ -7086,6 +7107,135 @@ rb_clock_gettime(int argc, VALUE *argv) https://github.com/ruby/ruby/blob/trunk/process.c#L7107
     return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
 }
 
+/*
+ *  call-seq:
+ *     Process.clock_getres(clock_id [, unit])   -> number
+ *
+ *  Returns the time resolution returned by POSIX clock_getres() function.
+ *
+ *  +clock_id+ specifies a kind of clock.
+ *  See the document of +Process.clock_gettime+ for details.
+ *
+ *  +clock_id+ can be a symbol as +Process.clock_gettime+.
+ *  However the result may not be accurate.
+ *  For example, +Process.clock_getres(:GETTIMEOFDAY_BASED_CLOCK_REALTIME)+
+ *  returns 1.0e-06 which means 1 micro second, but actual resolution can be more coarse.
+ *
+ *  If the given +clock_id+ is not supported, Errno::EINVAL is raised.
+ *
+ *  +unit+ specifies a type of the return value.
+ *  +Process.clock_getres+ accepts +unit+ as +Process.clock_gettime+.
+ *  The default value, +:float_second+, is also same as
+ *  +Process.clock_gettime+.
+ *
+ *  +Process.clock_getres+ also accepts +:hertz+ as +unit+.
+ *  +:hertz+ means a the reciprocal of +:float_second+.
+ *
+ *  +:hertz+ can be used to obtain the exact value of
+ *  the clock ticks per second for times() function and
+ *  CLOCKS_PER_SEC for clock() function.
+ *
+ *  +Process.clock_getres(:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)+
+ *  returns the clock ticks per second.
+ *
+ *  +Process.clock_getres(:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)+
+ *  returns CLOCKS_PER_SEC.
+ *
+ *    p Process.clock_getres(Process::CLOCK_MONOTONIC)
+ *    #=> 1.0e-09
+ *
+ */
+VALUE
+rb_clock_getres(int argc, VALUE *argv)
+{
+    VALUE clk_id, unit;
+    int ret;
+
+    struct timetick tt;
+    timetick_int_t numerators[2];
+    timetick_int_t denominators[2];
+    int num_numerators = 0;
+    int num_denominators = 0;
+
+    rb_scan_args(argc, argv, "11", &clk_id, &unit);
+
+    if (SYMBOL_P(clk_id)) {
+#ifdef RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
+        if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
+            tt.giga_count = 0;
+            tt.count = 1000;
+            denominators[num_denominators++] = 1000000000;
+            goto success;
+        }
+#endif
+
+#ifdef RUBY_TIME_BASED_CLOCK_REALTIME
+        if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
+            tt.giga_count = 1;
+            tt.count = 0;
+            denominators[num_denominators++] = 1000000000;
+            goto success;
+        }
+#endif
+
+#ifdef RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
+        if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
+            tt.giga_count = 0;
+            tt.count = 1000;
+            denominators[num_denominators++] = 1000000000;
+            goto success;
+        }
+#endif
+
+#ifdef RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
+        if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
+            tt.count = 1;
+            tt.giga_count = 0;
+            denominators[num_denominators++] = get_clk_tck();
+            goto success;
+        }
+#endif
+
+#ifdef RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
+        if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
+            tt.count = 1;
+            tt.giga_count = 0;
+            denominators[num_denominators++] = CLOCKS_PER_SEC;
+            goto success;
+        }
+#endif
+
+#ifdef RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
+        /* not yet */
+#endif
+    }
+    else {
+#if defined(HAVE_CLOCK_GETRES)
+        struct timespec ts;
+        clockid_t c;
+        c = NUM2CLOCKID(clk_id);
+        ret = clock_getres(c, &ts);
+        if (ret == -1)
+            rb_sys_fail("clock_getres");
+        tt.count = (int32_t)ts.tv_nsec;
+        tt.giga_count = ts.tv_sec;
+        denominators[num_denominators++] = 1000000000;
+        goto success;
+#endif
+    }
+    /* EINVAL emulates clock_getres behavior when clock_id is invalid. */
+    errno = EINVAL;
+    rb_sys_fail(0);
+
+  success:
+    if (unit == ID2SYM(rb_intern("hertz"))) {
+        return timetick2dblnum_reciprocal(&tt, numerators, num_numerators, denominators, num_denominators);
+    }
+    else {
+        return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
+    }
+}
+
 VALUE rb_mProcess;
 VALUE rb_mProcUID;
 VALUE rb_mProcGID;
@@ -7413,6 +7563,7 @@ Init_process(void) https://github.com/ruby/ruby/blob/trunk/process.c#L7563
     rb_define_const(rb_mProcess, "CLOCK_SECOND", CLOCKID2NUM(CLOCK_SECOND));
 #endif
     rb_define_module_function(rb_mProcess, "clock_gettime", rb_clock_gettime, -1);
+    rb_define_module_function(rb_mProcess, "clock_getres", rb_clock_getres, -1);
 
 #if defined(HAVE_TIMES) || defined(_WIN32)
     rb_cProcessTms = rb_struct_define("Tms", "utime", "stime", "cutime", "cstime", NULL);
Index: test/ruby/test_process.rb
===================================================================
--- test/ruby/test_process.rb	(revision 42743)
+++ test/ruby/test_process.rb	(revision 42744)
@@ -1729,4 +1729,70 @@ EOS https://github.com/ruby/ruby/blob/trunk/test/ruby/test_process.rb#L1729
     assert_kind_of(Float, t, "Process.clock_gettime(:#{n})")
   end
 
+  def test_clock_getres
+    r = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
+    assert_kind_of(Integer, r)
+    assert_raise(Errno::EINVAL) { Process.clock_getres(:foo) }
+  end
+
+  def test_clock_getres_constants
+    Process.constants.grep(/\ACLOCK_/).each {|n|
+      c = Process.const_get(n)
+      begin
+        t = Process.clock_getres(c)
+      rescue Errno::EINVAL
+        next
+      end
+      assert_kind_of(Float, t, "Process.clock_getres(Process::#{n})")
+    }
+  end
+
+  def test_clock_getres_GETTIMEOFDAY_BASED_CLOCK_REALTIME
+    n = :GETTIMEOFDAY_BASED_CLOCK_REALTIME
+    t = Process.clock_getres(n)
+    assert_kind_of(Float, t, "Process.clock_getres(:#{n})")
+  end
+
+  def test_clock_getres_TIME_BASED_CLOCK_REALTIME
+    n = :TIME_BASED_CLOCK_REALTIME
+    t = Process.clock_getres(n)
+    assert_kind_of(Float, t, "Process.clock_getres(:#{n})")
+  end
+
+  def test_clock_getres_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
+    n = :GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
+    begin
+      t = Process.clock_getres(n)
+    rescue Errno::EINVAL
+      return
+    end
+    assert_kind_of(Float, t, "Process.clock_getres(:#{n})")
+  end
+
+  def test_clock_getres_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
+    n = :TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
+    begin
+      t = Process.clock_getres(n)
+    rescue Errno::EINVAL
+      return
+    end
+    assert_kind_of(Float, t, "Process.clock_getres(:#{n})")
+  end
+
+  def test_clock_getres_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
+    n = :CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
+    t = Process.clock_getres(n)
+    assert_kind_of(Float, t, "Process.clock_getres(:#{n})")
+  end
+
+  def test_clock_getres_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
+    n = :MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
+    begin
+      t = Process.clock_getres(n)
+    rescue Errno::EINVAL
+      return
+    end
+    assert_kind_of(Float, t, "Process.clock_getres(:#{n})")
+  end
+
 end

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]