diff --git a/changelogs/unreleased/changed-signedness-of-time64-functions.md b/changelogs/unreleased/changed-signedness-of-time64-functions.md new file mode 100644 index 0000000000000000000000000000000000000000..3e500994c007925a34d905fc561dac38c1d70c91 --- /dev/null +++ b/changelogs/unreleased/changed-signedness-of-time64-functions.md @@ -0,0 +1,10 @@ +## bugfix/core + +* **[Breaking change]** Return value signedness of 64-bit time functions in + `clock` and `fiber` was changed from `uint64_t` to `int64_t` both in Lua + and C (gh-5989). + +---- + +Breaking change: lua: return value type for all time64 functions changed from +`uint64_t` to `int64_t`. diff --git a/src/lib/core/clock.c b/src/lib/core/clock.c index ff30584857e98ea12399d41a9b84fc69ee108bbd..ccf35858c8ad1f32137c5550f6c974c837594420 100644 --- a/src/lib/core/clock.c +++ b/src/lib/core/clock.c @@ -70,41 +70,43 @@ clock_thread(void) #endif } -uint64_t +int64_t clock_realtime64(void) { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); - return ((uint64_t)ts.tv_sec) * 1000000000 + ts.tv_nsec; + return ((int64_t)ts.tv_sec) * 1000000000 + ts.tv_nsec; } -uint64_t + +int64_t clock_monotonic64(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); - return ((uint64_t)ts.tv_sec) * 1000000000 + ts.tv_nsec; + return ((int64_t)ts.tv_sec) * 1000000000 + ts.tv_nsec; } -uint64_t + +int64_t clock_process64(void) { #if defined(CLOCK_PROCESS_CPUTIME_ID) struct timespec ts; clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); - return ((uint64_t)ts.tv_sec) * 1000000000 + ts.tv_nsec; + return ((int64_t)ts.tv_sec) * 1000000000 + ts.tv_nsec; #else - return (uint64_t) clock() * 1000000000 / CLOCKS_PER_SEC; + return (int64_t)clock() * 1000000000 / CLOCKS_PER_SEC; #endif } -uint64_t +int64_t clock_thread64(void) { #if defined(CLOCK_THREAD_CPUTIME_ID) struct timespec ts; clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts); - return ((uint64_t)ts.tv_sec) * 1000000000 + ts.tv_nsec; + return ((int64_t)ts.tv_sec) * 1000000000 + ts.tv_nsec; #else - return (uint64_t) clock() * 1000000000 / CLOCKS_PER_SEC; + return (int64_t)clock() * 1000000000 / CLOCKS_PER_SEC; #endif } diff --git a/src/lib/core/clock.h b/src/lib/core/clock.h index e31b8599adfdbb85396fafea47a8e02168667b23..75376b56141f75ba6b3ea604ecfb00664c84d25d 100644 --- a/src/lib/core/clock.h +++ b/src/lib/core/clock.h @@ -40,15 +40,67 @@ extern "C" { /** \cond public */ -double clock_realtime(void); -double clock_monotonic(void); -double clock_process(void); -double clock_thread(void); - -uint64_t clock_realtime64(void); -uint64_t clock_monotonic64(void); -uint64_t clock_process64(void); -uint64_t clock_thread64(void); +/** + * A settable system-wide clock that measures real (i.e., + * wall-clock) time. + * + * See clock_gettime(2), CLOCK_REALTIME. + */ +double +clock_realtime(void); + +/** + * A nonsettable system-wide clock that represents monotonic time. + * + * See clock_gettime(2), CLOCK_MONOTONIC. + */ +double +clock_monotonic(void); + +/** + * A clock that measures CPU time consumed by this process (by all + * threads in the process). + * + * See clock_gettime(2), CLOCK_PROCESS_CPUTIME_ID. + */ +double +clock_process(void); + +/** + * A clock that measures CPU time consumed by this thread. + * + * See clock_gettime(2), CLOCK_THREAD_CPUTIME_ID. + */ +double +clock_thread(void); + +/** + * Same as clock_realtime(), but returns the time as 64 bit + * signed integer. + */ +int64_t +clock_realtime64(void); + +/** + * Same as clock_monotonic(), but returns the time as 64 bit + * signed integer. + */ +int64_t +clock_monotonic64(void); + +/** + * Same as clock_process(), but returns the time as 64 bit + * signed integer. + */ +int64_t +clock_process64(void); + +/** + * Same as clock_thread(), but returns the time as 64 bit + * signed integer. + */ +int64_t +clock_thread64(void); /** \endcond public */ diff --git a/src/lib/core/fiber.c b/src/lib/core/fiber.c index 147ff49b49bf0af3bd639e108baae1c82e62c7cb..19e73d703645e523d23bbf1d780eb86666bcdff3 100644 --- a/src/lib/core/fiber.c +++ b/src/lib/core/fiber.c @@ -592,10 +592,10 @@ fiber_time(void) return ev_now(loop()); } -uint64_t +int64_t fiber_time64(void) { - return (uint64_t) ( ev_now(loop()) * 1000000 + 0.5 ); + return (int64_t)(ev_now(loop()) * 1000000 + 0.5); } double @@ -604,10 +604,10 @@ fiber_clock(void) return ev_monotonic_now(loop()); } -uint64_t +int64_t fiber_clock64(void) { - return (uint64_t) ( ev_monotonic_now(loop()) * 1000000 + 0.5 ); + return (int64_t)(ev_monotonic_now(loop()) * 1000000 + 0.5); } /** diff --git a/src/lib/core/fiber.h b/src/lib/core/fiber.h index 5d9fd6d6dafba6f3fbac826a18a07233adf1dd84..4ed5c1d81ed1c3166e95ef46598d8cc260daabd1 100644 --- a/src/lib/core/fiber.h +++ b/src/lib/core/fiber.h @@ -391,7 +391,7 @@ fiber_time(void); * Report loop begin time as 64-bit int. * Uses real time clock. */ -API_EXPORT uint64_t +API_EXPORT int64_t fiber_time64(void); /** @@ -405,7 +405,7 @@ fiber_clock(void); * Report loop begin time as 64-bit int. * Uses monotonic clock. */ -API_EXPORT uint64_t +API_EXPORT int64_t fiber_clock64(void); /** diff --git a/src/lua/clock.lua b/src/lua/clock.lua index fee43ccde767f8afa3c2a5252cc7bd33da8279d4..738f3844fec49961195cf521f9b34ee0bcf240b7 100644 --- a/src/lua/clock.lua +++ b/src/lua/clock.lua @@ -7,10 +7,10 @@ ffi.cdef[[ double clock_monotonic(void); double clock_process(void); double clock_thread(void); - uint64_t clock_realtime64(void); - uint64_t clock_monotonic64(void); - uint64_t clock_process64(void); - uint64_t clock_thread64(void); + int64_t clock_realtime64(void); + int64_t clock_monotonic64(void); + int64_t clock_process64(void); + int64_t clock_thread64(void); ]] local C = ffi.C diff --git a/src/lua/fiber.lua b/src/lua/fiber.lua index b14117714989bd9fb284f3378f29b6204309fe0b..a788aa37d37240369f99d4985b4e900686271e4a 100644 --- a/src/lua/fiber.lua +++ b/src/lua/fiber.lua @@ -5,11 +5,11 @@ local ffi = require('ffi') ffi.cdef[[ double fiber_time(void); -uint64_t +int64_t fiber_time64(void); double fiber_clock(void); -uint64_t +int64_t fiber_clock64(void); ]] local C = ffi.C diff --git a/test/app-tap/clock.test.lua b/test/app-tap/clock.test.lua index d1ea4f0a8e1dd2fc9f32d4d7bdfe1835e5289a76..5f25d77bbc96e9fa377ada3ef765cb37df66ab65 100755 --- a/test/app-tap/clock.test.lua +++ b/test/app-tap/clock.test.lua @@ -1,16 +1,72 @@ #!/usr/bin/env tarantool local clock = require("clock") -local test = require("tap").test("csv") -test:plan(10) +local fiber = require("fiber") +local test = require("tap").test("clock") + +test:plan(36) + +test:ok(clock.time() > 0, "time") test:ok(clock.realtime() > 0, "realtime") test:ok(clock.thread() > 0, "thread") test:ok(clock.monotonic() > 0, "monotonic") test:ok(clock.proc() > 0, "proc") +test:ok(fiber.time() > 0, "fiber.time") +test:ok(fiber.clock() > 0, "fiber.clock") +test:ok(clock.time64() > 0, "time64") test:ok(clock.realtime64() > 0, "realtime64") test:ok(clock.thread64() > 0, "thread64") test:ok(clock.monotonic64() > 0, "monotonic64") test:ok(clock.proc64() > 0, "proc64") +test:ok(fiber.time64() > 0, "fiber.time64") +test:ok(fiber.clock64() > 0, "fiber.clock64") test:ok(clock.monotonic() <= clock.monotonic(), "time is monotonic") +test:ok(clock.monotonic64() <= clock.monotonic64(), "time is monotonic") test:ok(math.abs(clock.realtime() - os.time()) < 2, "clock.realtime ~ os.time") + +test:ok(fiber.time() == fiber.time(), "fiber.time is cached") +test:ok(fiber.time64() == fiber.time64(), "fiber.time64 is cached") + +test:ok(fiber.clock() == fiber.clock(), "fiber.clock is cached") +test:ok(fiber.clock64() == fiber.clock64(), "fiber.clock64 is cached") +test:ok(fiber.clock() < (fiber.yield() or 0) + fiber.clock(), + "fiber.clock is growing after yield") +test:ok(fiber.clock64() < (fiber.yield() or 0) + fiber.clock64(), + "fiber.clock64 is growing after yield") + +test:ok(math.abs(fiber.time() - tonumber(fiber.time64())/1e6) < 1, + "fiber.time64 is in microseconds") +test:ok(math.abs(fiber.clock() - tonumber(fiber.clock64())/1e6) < 1, + "fiber.clock64 is in microseconds") + +test:ok(math.abs(clock.time() - tonumber(clock.time64())/1e9) < 1, + "clock.time64 is in nanoseconds") +test:ok(math.abs(clock.realtime() - tonumber(clock.realtime64())/1e9) < 1, + "clock.realtime64 is in nanoseconds") +test:ok(math.abs(clock.thread() - tonumber(clock.thread64())/1e9) < 1, + "clock.thread64 is in nanoseconds") +test:ok(math.abs(clock.proc() - tonumber(clock.proc64())/1e9) < 1, + "clock.proc64 is in nanoseconds") + +local function subtract_future(func) + local ts1 = func() + fiber.sleep(0.001) + return ts1 - func() +end +test:ok(subtract_future(clock.time64) < 0, + "clock.time64() can be subtracted") +test:ok(subtract_future(clock.realtime64) < 0, + "clock.realtime64() can be subtracted") +test:ok(subtract_future(clock.thread64) < 0, + "clock.thread64() can be subtracted") +test:ok(subtract_future(clock.monotonic64) < 0, + "clock.monotonic64() can be subtracted") +test:ok(subtract_future(clock.proc64) < 0, + "clock.proc64() can be subtracted") +test:ok(subtract_future(fiber.time64) < 0, + "fiber.time64 can be subtracted") +test:ok(subtract_future(fiber.clock64) < 0, + "fiber.clock64 can be subtracted") + +os.exit(test:check() and 0 or 1)