-
-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ST: Use clock_gettime to prevent time jumping backwards. v7.0.17 (#3979)
try to fix #3978 **Background** check #3978 **Research** I referred the Android platform's solution, because I have android background, and there is a loop to handle message inside android. https://github.com/aosp-mirror/platform_frameworks_base/blob/ff007a03c01bf936d1e961a13adff9f266d5189c/core/java/android/os/Handler.java#L701-L706C6 ``` public final boolean sendMessageDelayed(@nonnull Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } ``` https://github.com/aosp-mirror/platform_system_core/blob/59d9dc1f50b1ae8630ec11a431858a3cb66487b7/libutils/SystemClock.cpp#L37-L51 ``` /* * native public static long uptimeMillis(); */ int64_t uptimeMillis() { return nanoseconds_to_milliseconds(uptimeNanos()); } /* * public static native long uptimeNanos(); */ int64_t uptimeNanos() { return systemTime(SYSTEM_TIME_MONOTONIC); } ``` https://github.com/aosp-mirror/platform_system_core/blob/59d9dc1f50b1ae8630ec11a431858a3cb66487b7/libutils/Timers.cpp#L32-L55 ``` #if defined(__linux__) nsecs_t systemTime(int clock) { checkClockId(clock); static constexpr clockid_t clocks[] = {CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID, CLOCK_THREAD_CPUTIME_ID, CLOCK_BOOTTIME}; static_assert(clock_id_max == arraysize(clocks)); timespec t = {}; clock_gettime(clocks[clock], &t); return nsecs_t(t.tv_sec)*1000000000LL + t.tv_nsec; } #else nsecs_t systemTime(int clock) { // TODO: is this ever called with anything but REALTIME on mac/windows? checkClockId(clock); // Clock support varies widely across hosts. Mac OS doesn't support // CLOCK_BOOTTIME (and doesn't even have clock_gettime until 10.12). // Windows is windows. timeval t = {}; gettimeofday(&t, nullptr); return nsecs_t(t.tv_sec)*1000000000LL + nsecs_t(t.tv_usec)*1000LL; } #endif ``` For Linux system, we can use `clock_gettime` api, but it's first appeared in Mac OSX 10.12. `man clock_gettime` The requirement is to find an alternative way to get the timestamp in microsecond unit, but the `clock_gettime` get nanoseconds, the math formula is the nanoseconds / 1000 = microsecond. Then I check the performance of this api + math division. I used those code to check the `clock_gettime` performance. ``` #include <sys/time.h> #include <time.h> #include <stdio.h> #include <unistd.h> int main() { struct timeval tv; struct timespec ts; clock_t start; clock_t end; long t; while (1) { start = clock(); gettimeofday(&tv, NULL); end = clock(); printf("gettimeofday clock is %lu\n", end - start); printf("gettimeofday is %lld\n", (tv.tv_sec * 1000000LL + tv.tv_usec)); start = clock(); clock_gettime(CLOCK_MONOTONIC, &ts); t = ts.tv_sec * 1000000L + ts.tv_nsec / 1000L; end = clock(); printf("clock_monotonic clock is %lu\n", end - start); printf("clock_monotonic: seconds is %ld, nanoseconds is %ld, sum is %ld\n", ts.tv_sec, ts.tv_nsec, t); start = clock(); clock_gettime(CLOCK_MONOTONIC_RAW, &ts); t = ts.tv_sec * 1000000L + ts.tv_nsec / 1000L; end = clock(); printf("clock_monotonic_raw clock is %lu\n", end - start); printf("clock_monotonic_raw: nanoseconds is %ld, sum is %ld\n", ts.tv_nsec, t); sleep(3); } return 0; } ``` Here is output: env: Mac OS M2 chip. ``` gettimeofday clock is 11 gettimeofday is 1709775727153949 clock_monotonic clock is 2 clock_monotonic: seconds is 1525204, nanoseconds is 409453000, sum is 1525204409453 clock_monotonic_raw clock is 2 clock_monotonic_raw: nanoseconds is 770493000, sum is 1525222770493 ``` We can see the `clock_gettime` is faster than `gettimeofday`, so there are no performance risks. **MacOS solution** `clock_gettime` api only available until mac os 10.12, for the mac os older than 10.12, just keep the `gettimeofday`. check osx version in `auto/options.sh`, then add MACRO in `auto/depends.sh`, the MACRO is `MD_OSX_HAS_NO_CLOCK_GETTIME`. **CYGWIN** According to google search, it seems the `clock_gettime(CLOCK_MONOTONIC)` is not support well at least 10 years ago, but I didn't own an windows machine, so can't verify it. so keep win's solution. --------- Co-authored-by: winlin <[email protected]>
- Loading branch information
Showing
9 changed files
with
168 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,6 @@ | |
|
||
#define VERSION_MAJOR 7 | ||
#define VERSION_MINOR 0 | ||
#define VERSION_REVISION 16 | ||
#define VERSION_REVISION 17 | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
// | ||
// Copyright (c) 2013-2024 The SRS Authors | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
#include <srs_utest_st.hpp> | ||
#include <sys/time.h> | ||
#include <time.h> | ||
#include <unistd.h> | ||
|
||
using namespace std; | ||
|
||
VOID TEST(StTest, StUtimeInMicroseconds) | ||
{ | ||
st_utime_t st_time_1 = st_utime(); | ||
// sleep 1 microsecond | ||
#if !defined(SRS_CYGWIN64) | ||
usleep(1); | ||
#endif | ||
st_utime_t st_time_2 = st_utime(); | ||
|
||
EXPECT_GT(st_time_1, 0); | ||
EXPECT_GT(st_time_2, 0); | ||
EXPECT_GE(st_time_2, st_time_1); | ||
// st_time_2 - st_time_1 should be in range of [1, 100] microseconds | ||
EXPECT_GE(st_time_2 - st_time_1, 0); | ||
EXPECT_LE(st_time_2 - st_time_1, 100); | ||
} | ||
|
||
static inline st_utime_t time_gettimeofday() { | ||
struct timeval tv; | ||
gettimeofday(&tv, NULL); | ||
return (tv.tv_sec * 1000000LL + tv.tv_usec); | ||
} | ||
|
||
VOID TEST(StTest, StUtimePerformance) | ||
{ | ||
clock_t start; | ||
int gettimeofday_elapsed_time = 0; | ||
int st_utime_elapsed_time = 0; | ||
|
||
// Both the st_utime(clock_gettime or gettimeofday) and gettimeofday's | ||
// elpased time to execute is dependence on whether it is the first time be called. | ||
// In general, the gettimeofday has better performance, but the gap between | ||
// them is really small, maybe less than 10 clock ~ 10 microseconds. | ||
|
||
// check st_utime first, then gettimeofday | ||
{ | ||
start = clock(); | ||
st_utime_t t2 = st_utime(); | ||
int elapsed_time = clock() - start; | ||
st_utime_elapsed_time += elapsed_time; | ||
EXPECT_GT(t2, 0); | ||
|
||
start = clock(); | ||
st_utime_t t1 = time_gettimeofday(); | ||
elapsed_time = clock() - start; | ||
gettimeofday_elapsed_time += elapsed_time; | ||
EXPECT_GT(t1, 0); | ||
|
||
|
||
EXPECT_GE(gettimeofday_elapsed_time, 0); | ||
EXPECT_GE(st_utime_elapsed_time, 0); | ||
|
||
// pass the test, if | ||
EXPECT_LT(gettimeofday_elapsed_time > st_utime_elapsed_time ? | ||
gettimeofday_elapsed_time - st_utime_elapsed_time : | ||
st_utime_elapsed_time - gettimeofday_elapsed_time, 10); | ||
} | ||
|
||
// check gettimeofday first, then st_utime | ||
{ | ||
start = clock(); | ||
st_utime_t t1 = time_gettimeofday(); | ||
int elapsed_time = clock() - start; | ||
gettimeofday_elapsed_time += elapsed_time; | ||
EXPECT_GT(t1, 0); | ||
|
||
start = clock(); | ||
st_utime_t t2 = st_utime(); | ||
elapsed_time = clock() - start; | ||
st_utime_elapsed_time += elapsed_time; | ||
EXPECT_GT(t2, 0); | ||
|
||
EXPECT_GE(gettimeofday_elapsed_time, 0); | ||
EXPECT_GE(st_utime_elapsed_time, 0); | ||
|
||
EXPECT_LT(gettimeofday_elapsed_time > st_utime_elapsed_time ? | ||
gettimeofday_elapsed_time - st_utime_elapsed_time : | ||
st_utime_elapsed_time - gettimeofday_elapsed_time, 10); | ||
} | ||
|
||
// compare st_utime & gettimeofday in a loop | ||
for (int i = 0; i < 100; i++) { | ||
start = clock(); | ||
st_utime_t t2 = st_utime(); | ||
int elapsed_time = clock() - start; | ||
st_utime_elapsed_time = elapsed_time; | ||
EXPECT_GT(t2, 0); | ||
usleep(1); | ||
|
||
start = clock(); | ||
st_utime_t t1 = time_gettimeofday(); | ||
elapsed_time = clock() - start; | ||
gettimeofday_elapsed_time = elapsed_time; | ||
EXPECT_GT(t1, 0); | ||
usleep(1); | ||
|
||
EXPECT_GE(gettimeofday_elapsed_time, 0); | ||
EXPECT_GE(st_utime_elapsed_time, 0); | ||
|
||
EXPECT_LT(gettimeofday_elapsed_time > st_utime_elapsed_time ? | ||
gettimeofday_elapsed_time - st_utime_elapsed_time : | ||
st_utime_elapsed_time - gettimeofday_elapsed_time, 10); | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// | ||
// Copyright (c) 2013-2024 The SRS Authors | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
|
||
#ifndef SRS_UTEST_ST_HPP | ||
#define SRS_UTEST_ST_HPP | ||
|
||
#include <srs_utest.hpp> | ||
|
||
#include <st.h> | ||
|
||
#endif // SRS_UTEST_ST_HPP | ||
|