Merge: Revamp Clock to return float values for easier memory management
authorJean Privat <jean@pryen.org>
Tue, 24 May 2016 13:16:47 +0000 (09:16 -0400)
committerJean Privat <jean@pryen.org>
Tue, 24 May 2016 13:16:47 +0000 (09:16 -0400)
This PR updates the main services of `Clock` to return float values instead of malloced extern instances of `Timespec`. There is a precision loss, but it's sufficient for games and the likes, and a program needing higher precision can still use `Timespec` directly. Clients don't even have to worry about memory management anymore.

Pull-Request: #2117
Reviewed-by: Jean Privat <jean@pryen.org>

13 files changed:
contrib/friendz/src/friendz.nit
contrib/tinks/src/game/framework.nit
lib/gamnit/limit_fps.nit
lib/mnit/mnit_fps.nit
lib/performance_analysis.nit
lib/popcorn/README.md
lib/popcorn/examples/middlewares/example_advanced_logger.nit
lib/popcorn/pop_middlewares.nit
lib/realtime.nit
src/interpreter/dynamic_loading_ffi/on_demand_compiler.nit
tests/sav/test_realtime.res [deleted file]
tests/test_kill_process.nit
tests/test_realtime.nit [deleted file]

index c0554fe..762eb1d 100644 (file)
@@ -1609,22 +1609,10 @@ redef class App
                game.save
        end
 
-       # Maximum wanted frame per second
-       var max_fps = 30
-
-       # clock used to track FPS
-       private var clock = new Clock
-
        redef fun frame_core(display)
        do
                game.step
                game.draw(display)
-               var dt = clock.lapse
-               var target_dt = 1000000000 / max_fps
-               if dt.sec == 0 and dt.nanosec < target_dt then
-                       var sleep_t = target_dt - dt.nanosec
-                       sys.nanosleep(0, sleep_t)
-               end
        end
 
        redef fun input(input_event)
index 49c74b0..9472da6 100644 (file)
@@ -41,7 +41,7 @@ class TGame
                var dt = clock.lapse
                tick += 1
 
-               var turn = new TTurn(self, tick, dt.to_f, dt.millisec)
+               var turn = new TTurn(self, tick, dt, ((dt-dt.floor)*1000.0).to_i)
                return turn
        end
 
index f16609f..896f07f 100644 (file)
@@ -47,7 +47,7 @@ redef class App
        private var frame_count = 0
 
        # Deadline used to compute `current_fps`
-       private var frame_count_deadline = 5
+       private var frame_count_deadline = 5.0
 
        # Check and sleep to maintain a frame-rate bellow `maximum_fps`
        #
@@ -55,12 +55,12 @@ redef class App
        # Is automatically called at the end of `full_frame`.
        fun limit_fps
        do
-               var t = clock.total.sec
+               var t = clock.total
                if t >= frame_count_deadline then
                        var cfps = frame_count.to_f / 5.0
                        self.current_fps = cfps
                        frame_count = 0
-                       frame_count_deadline = t + 5
+                       frame_count_deadline = t + 5.0
                end
                frame_count += 1
 
index 3841bc6..f4abd92 100644 (file)
@@ -44,19 +44,19 @@ redef class App
        private var frame_count = 0
 
        # Deadline used to compute `current_fps`
-       private var frame_count_deadline = 0
+       private var frame_count_deadline = 0.0
 
        # Check and sleep to maitain a frame-rate bellow `maximum_fps`
        # Also periodically uptate `current_fps`
        # Is automatically called at the end of `full_frame`.
        fun limit_fps
        do
-               var t = clock.total.sec
+               var t = clock.total
                if t >= frame_count_deadline then
                        var cfps = frame_count.to_f / 5.0
                        self.current_fps = cfps
                        frame_count = 0
-                       frame_count_deadline = t + 5
+                       frame_count_deadline = t + 5.0
                end
                frame_count += 1
 
index 4763061..b9e436a 100644 (file)
@@ -122,11 +122,8 @@ class PerfEntry
        # Total execution time of this event
        var sum = 0.0
 
-       # Register a new event execution time with a `Timespec`
-       fun add(lapse: Timespec) do add_float lapse.to_f
-
-       # Register a new event execution time in seconds using a `Float`
-       fun add_float(time: Float)
+       # Register a new event execution time in seconds
+       fun add(time: Float)
        do
                if time.to_f < min.to_f or count == 0 then min = time
                if time.to_f > max.to_f then max = time
index 08f7c9a..4712faf 100644 (file)
@@ -505,7 +505,7 @@ class LogHandler
        redef fun all(req, res) do
                var timer = req.timer
                if timer != null then
-                       print "{req.method} {req.uri} {res.color_status} ({timer.total})"
+                       print "{req.method} {req.uri} {res.color_status} ({timer.total}s)"
                else
                        print "{req.method} {req.uri} {res.color_status}"
                end
index b97d10c..7f8e3b1 100644 (file)
@@ -34,7 +34,7 @@ class LogHandler
        redef fun all(req, res) do
                var timer = req.timer
                if timer != null then
-                       print "{req.method} {req.uri} {res.color_status} ({timer.total})"
+                       print "{req.method} {req.uri} {res.color_status} ({timer.total}s)"
                else
                        print "{req.method} {req.uri} {res.color_status}"
                end
index 38e4bd9..518d9dc 100644 (file)
@@ -48,7 +48,7 @@ class ConsoleLog
        redef fun all(req, res) do
                var clock = req.clock
                if clock != null then
-                       print "{req.method} {req.uri} {status(res)} ({clock.total})"
+                       print "{req.method} {req.uri} {status(res)} ({clock.total}s)"
                else
                        print "{req.method} {req.uri} {status(res)}"
                end
index 8cfa4da..243b5d8 100644 (file)
@@ -73,13 +73,16 @@ extern class Timespec `{struct timespec*`}
                clock_gettime(CLOCK_MONOTONIC, self);
        `}
 
-       # Substract a Timespec from `self`.
-       fun - ( o : Timespec ) : Timespec
+       # Subtract `other` from `self`
+       fun -(other: Timespec): Timespec
        do
-               var s = sec - o.sec
-               var ns = nanosec - o.nanosec
-               if ns > nanosec then s += 1
-               return new Timespec( s, ns )
+               var s = sec - other.sec
+               var ns = nanosec - other.nanosec
+               if ns < 0 then
+                       s -= 1
+                       ns += 1000000000
+               end
+               return new Timespec(s, ns)
        end
 
        # Number of whole seconds of elapsed time.
@@ -117,15 +120,33 @@ extern class Timespec `{struct timespec*`}
 end
 
 # Keeps track of real time
+#
+# ~~~
+# var clock = new Clock
+#
+# # sleeping at least 1s
+# 1.0.sleep
+# assert clock.total >= 1.0
+# assert clock.lapse >= 1.0
+#
+# # sleeping at least 5ms
+# 0.005.sleep
+# assert clock.total >= 1.005
+# assert clock.lapse >= 0.005
+# ~~~
 class Clock
-       # Time at instanciation
+       super FinalizableOnce
+
+       # TODO use less mallocs
+
+       # Time at creation
        protected var time_at_beginning = new Timespec.monotonic_now
 
        # Time at last time a lapse method was called
        protected var time_at_last_lapse = new Timespec.monotonic_now
 
        # Smallest time frame reported by clock
-       fun resolution : Timespec `{
+       fun resolution: Timespec `{
                struct timespec* tv = malloc( sizeof(struct timespec) );
 #ifdef __MACH__
                clock_serv_t cclock;
@@ -142,18 +163,43 @@ class Clock
                return tv;
        `}
 
-       # Return timelapse since instanciation of this instance
-       fun total : Timespec
+       # Seconds since the creation of this instance
+       fun total: Float
        do
-               return new Timespec.monotonic_now - time_at_beginning
+               var now = new Timespec.monotonic_now
+               var diff = now - time_at_beginning
+               var r = diff.to_f
+               diff.free
+               now.free
+               return r
        end
 
-       # Return timelapse since last call to lapse
-       fun lapse : Timespec
+       # Seconds since the last call to `lapse`
+       fun lapse: Float
        do
                var nt = new Timespec.monotonic_now
                var dt = nt - time_at_last_lapse
+               var r = dt.to_f
+               dt.free
+               time_at_last_lapse.free
                time_at_last_lapse = nt
-               return dt
+               return r
+       end
+
+       # Seconds since the last call to `lapse`, without resetting the lapse counter
+       fun peek_lapse: Float
+       do
+               var nt = new Timespec.monotonic_now
+               var dt = nt - time_at_last_lapse
+               var r = dt.to_f
+               nt.free
+               dt.free
+               return r
+       end
+
+       redef fun finalize_once
+       do
+               time_at_beginning.free
+               time_at_last_lapse.free
        end
 end
index 4207a01..4e4a5b3 100644 (file)
@@ -128,7 +128,12 @@ redef class AModule
                srcs.add_all mmodule.ffi_files
 
                # Compiler options specific to this module
-               var ldflags = mmodule.ldflags[""].join(" ")
+               var ldflags_array = mmodule.ldflags[""]
+               if ldflags_array.has("-lrt") and system("sh -c 'uname -s 2>/dev/null || echo not' | grep Darwin >/dev/null") == 0 then
+                       # Remove -lrt on OS X
+                       ldflags_array.remove "-lrt"
+               end
+               var ldflags = ldflags_array.join(" ")
 
                # Protect pkg-config
                var pkgconfigs = mmodule.pkgconfigs
diff --git a/tests/sav/test_realtime.res b/tests/sav/test_realtime.res
deleted file mode 100644 (file)
index 65b7078..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-sleeping 1s
-true
-true
-sleeping 5000ns
-true
-true
-true
index 21728c1..a9f3e61 100644 (file)
@@ -21,12 +21,11 @@ var clock = new Clock
 var p = new Process("sleep", "10")
 
 # Send some signals
-p.signal(sigalarm)
+p.signal sigalarm
 p.kill
 
 # Wait for it to die
 p.wait
-var lapse = clock.lapse
 
 # Let's be generous here, as long as it does not take 5 secs out of 10 it's OK
-print lapse.sec < 5
+print clock.lapse < 5.0
diff --git a/tests/test_realtime.nit b/tests/test_realtime.nit
deleted file mode 100644 (file)
index 6101a3d..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2012 Alexis Laferrière <alexis.laf@xymus.net>
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import realtime
-
-redef extern class Timespec
-       fun simplify : Int
-       do
-               return sec*1000000 + nanosec/1000
-       end
-end
-
-var c = new Clock
-var t0 = c.total.simplify
-
-print "sleeping 1s"
-nanosleep(1, 0)
-print c.total.sec >= 1
-print c.lapse.sec >= 1
-
-var t1 = c.total.simplify
-
-print "sleeping 5000ns"
-nanosleep(0, 5000)
-print c.lapse.nanosec >= 5000
-
-var t2 = c.total.simplify
-
-print t0 <= t1
-print t1 <= t2