ossrs / srs

SRS is a simple, high-efficiency, real-time video server supporting RTMP, WebRTC, HLS, HTTP-FLV, SRT, MPEG-DASH, and GB28181.
https://ossrs.io
MIT License
24.72k stars 5.28k forks source link

issue #3978: improve st_utime's default impl. #3979

Open suzp1984 opened 3 months ago

suzp1984 commented 3 months ago

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.

winlinvip commented 3 months ago

Thank you for your excellent work. Please add new tests to validate your updates in the pull request. The utest is crucial and a necessary condition for merging the pull request. Without it and automated testing, we risk introducing bugs sooner or later due to many changes over time.

suzp1984 commented 3 months ago

Add a UT in srs root project.

winlinvip commented 3 months ago

Failed in cygwin?