How to calculate delta between monotonic system clock and frameCaptureTSC

Software Version
DRIVE OS Linux 6.0.8.1 and DriveWorks 5.14

Hardware Platform
DRIVE AGX Orin

Hi,

In this thread we were told how to convert frameCaptureTSC to time, but we would need to figure out the delta between the time deduced from the frameCaptureTSC and the monotonic system clock.

Is there a way to get the current tick count to calculate the delta between the current monotonic system clock time and the current TSC time?

Kind regards,
Adam

Dear @AdamBalazsVay ,
TSC gets reset on every boot. May I know the objective of this?

Dear @SivaRamaKrishnaNV

Thanks for your reply. Of course, that’s fine. We would calculate the delta every time our application is started. In out GStreamer pipeline we would like to send the frame capture time that can be compared to the monotonic system clock to be able to calculate end to end latency.

Hi @SivaRamaKrishnaNV,

Do you have any update on this?

Kind regards,
Adam

Dear @SivaRamaKrishnaNV,

So far I’ve found 3 methods to get a monotonic clock:

  1. Use clock_gettime(CLOCK_MONOTONIC) (aka. std::chrono::steady_clock::now)
  2. NvPlayfair library’s NvpGetTimeMark + NvpConvertTimeMarkToNsec
  3. Getting the raw TSC tick value

Unfortunately all 3 clocks are divergent :( I created a small test application to print the delta between them in every second. This is the output I got:

Fair - steady:     8791 ms | tsc - steady:    -5339 ms | fair - tsc:    14131 ms | fair:   250066 sec | tsc:   250052 sec | steady:   250057 sec
Fair - steady:     8799 ms | tsc - steady:    -5360 ms | fair - tsc:    14159 ms | fair:   250574 sec | tsc:   250560 sec | steady:   250565 sec

In 8.5 minutes nv “fairplay” timestamp drifted 8 millisecs from the system monotonic clock, TSC timestamp drifted 21 millisecs.

Please let us know which of the three mentioned clocks is used when filling ImageMetaData::frameCaptureTSC?

There is a short application to reproduce the output I got. In every minute it prints the current clocks and the deltas between them. If they were in sync the deltas would not change:

#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#include <chrono>
#include <nvplayfair.h>
#include <thread>

static constexpr uint64_t TSCFreq{31250000};

void printDiff()
{
    static constexpr off_t tscMemOffset{0x0c6a0010};

    static off_t const pageSize{sysconf(_SC_PAGE_SIZE)};
    static off_t const pageBase{(tscMemOffset / pageSize) * pageSize};
    static off_t const pageOffset{tscMemOffset - pageBase};

    int const memFileDesc{open("/dev/mem", O_RDONLY)};
    if(memFileDesc < 0)
    {
        printf("Can't open memory");
        return;
    }

    uint8_t const* mem{static_cast<uint8_t*>(mmap(nullptr, pageOffset + sizeof(uint64_t), PROT_READ, MAP_PRIVATE, memFileDesc, pageBase))};
    if(mem != MAP_FAILED)
    {
        // Get raw TSs
        uint64_t const regLow{*reinterpret_cast<uint32_t const*>(mem + pageOffset)};
        uint64_t const regHigh{*reinterpret_cast<uint32_t const*>(mem + pageOffset + sizeof(uint32_t))};

        auto const fairRaw{NvpGetTimeMark()};

        auto const steadyNow{std::chrono::steady_clock::now()};

        // Nano calc
        auto const umapResult{munmap((void*)mem,  pageOffset + sizeof(uint64_t))};
        if(umapResult != 0)
        {
            printf("Can't unmap memory");
        }

        uint64_t const tscTime{regLow + (regHigh << 32)};
        timespec tscTimeSpec{};
        tscTimeSpec.tv_sec = tscTime / TSCFreq;
        tscTimeSpec.tv_nsec = ((tscTime % TSCFreq) * 1000000000L) / TSCFreq;

        int64_t const tscTimeInNano{tscTimeSpec.tv_sec * 1000000000L + tscTimeSpec.tv_nsec};
        int64_t const steadyNowInNano{std::chrono::duration_cast<std::chrono::nanoseconds>(steadyNow.time_since_epoch()).count()};
        int64_t const fairTS{NvpConvertTimeMarkToNsec(fairRaw)};

        printf("Fair - steady: %8.0ld ms | tsc - steady: %8.0ld ms | fair - tsc: %8.0ld ms | fair: %8.0ld sec | tsc: %8.0ld sec | steady: %8.0ld sec\n",
                (fairTS - steadyNowInNano) / 1000000, (tscTimeInNano - steadyNowInNano) / 1000000, (fairTS - tscTimeInNano) / 1000000, fairTS / 1000000000, tscTimeInNano / 1000000000, steadyNowInNano / 1000000000);
    }
    else
    {
        printf("Can't map memory");
    }

    close(memFileDesc);

    return;
}

int main() 
{
    for(;;) {
        printDiff();
        std::this_thread::sleep_for(std::chrono::minutes(1));
    }
}

@SivaRamaKrishnaNV did you have the chance checking this?