pendulum-project / statime

Implementation of the Precision Time Protocol (PTP) in Rust
https://trifectatech.org
Other
162 stars 20 forks source link

Independent clock for arbitrary timescale #389

Open teodly opened 6 months ago

teodly commented 6 months ago

Sometimes we don't want to synchronize the system clock to PTP time source.

It's the case in local audiovisual networks - a device with low jitter clock becomes the master but often it isn't connected to the Internet or GPS so it can't be used as a source of time of day. If I understand correctly, in PTP it's called arbitrary timescale.

Statime used as a library could maintain internal clock, phase-locked to the system TAI clock, with timestamp offset and frequency factor changing according to PTP measurements. System TAI clock would be only read.

Network interface clock (/dev/ptp0) could also be used since it's independent from system clock, but we also need a fallback for NICs without hardware timestamping.

I will start working on it soon since I need it in my unofficial Dante implementation - Inferno.

davidv1992 commented 6 months ago

Linux doesn't really support virtual clocks in the way you suggest here, so I am not sure whether this would be useful in the linux binary. As for when using statime as a library, since you are already required to provide the clock type this should be perfectly possible within the current feature set, so not sure what would be needed in addition there, perhaps you could elaborate on what exactly it is you would like to see added?

dsseng commented 6 months ago

AFAIK virtual clocks (ptp_vclock) can indeed be implemented for network interfaces in their driver, but not really accessible as an available module and UAPI.

teodly commented 6 months ago

Yes, custom implementation of statime::Clock should suffice. I was just thinking of making it available in statime crate out-of-the-box. But it can be implemented in its own crate as well.

davidv1992 commented 6 months ago

Hmmm, not really sure how that would work in a platform independent way (it still needs some sort of clock as basis) but let me know once you have something to review.

teodly commented 6 months ago

Here's the implementation. It's so simple since I'm relying on filters already implemented in Statime.

Other changes are necessary for:

davidv1992 commented 6 months ago

That does look really interesting, particularly the library changes seem quite close to mergeable. We would need to discuss the extra dependency but that is not too hard to work around. If you would like to open a PR I would be interested.

The changes to statime-linux require some more discussion I think, primarily because we would then want that to be configurable, and we should probably have more options than just the current behaviour and what you provided, but I think we should have time soon to look into that.

cmeissl commented 6 months ago

I have a similar use-case for supporting ptp with ARB timescale. In my case the only available ptp hardware clock on the hardware is already in use for synchronizing the system clock. I really like the idea of the overlay clock, but I would like to keep the ARB time monotonic and avoid jumps caused by sync of the underlying clock. While this might not be possible with software timestamps it might work with virtual ptp clocks. Device not supporting this could still use the overlay clock, but should not be selected as a master clock. Detecting time jumps in the overlay clock and re-syncing should be doable.

teodly commented 5 months ago

After experimenting with it, I'm not sure whether CLOCK_TAI is a good base for overlay clocks. CLOCK_MONOTONIC seems to be better since it won't be updated by NTP. But it's not supported by clock_steering crate (and adding it doesn't make sense, because it can't be set).

As @cmeissl pointed out, the kernel already supports virtual clocks for PHC.

So to cover the use case of keeping system time independent from PTP time, my implementation of OverlayClock would need to be changed to use CLOCK_MONOTONIC. Does supporting other clocks as underlying clocks make sense?

davidv1992 commented 5 months ago

I would have no problems with adding something like CLOCK_MONOTONIC to the clock_steering crate if it is necessary or useful. That crate is primarily intended for internal consumption anyway and I could live with the slight rough edges this introduces.

davidv1992 commented 5 months ago

BTW, note that CLOCK_MONOTONIC is still steered by ntp in terms of frequency. For this particular usecase, perhaps CLOCK_MONOTONIC_RAW is even better, as that doesn't even include frequency steering.

teodly commented 1 month ago

Currently and in upcoming weeks and months I have some time to work on it. I've started looking at improving my patch, making it possible to use CLOCK_MONOTONIC or CLOCK_MONOTONIC_RAW as the underlying clock. Let me know if I'm thinking correctly about these considerations:

To sum up, we need a way of converting timestamps from CLOCK_REALTIME timescale to our virtual clock's timescale, but it isn't as easy as shifting and scaling I've already implemented because the underlying clock is different (in practice it is also shifting and scaling but the parameters are hidden in the kernel).

Do we need to measure the MONOTONIC_RAW-REALTIME offset and frequency drift? Have separate clock_task for that? That looks unnecessarily complex and prone to jitter. Do you see better ways of doing it?

davidv1992 commented 1 month ago

Most of it seems sensible, however in situations lacking support for comparing directly with CLOCK_MONOTONIC_RAW, I think the best solution is just to build a virtual clock on CLOCK_REALTIME, imperfect though it may be. You are probably right that doing separate tracking of the difference between monotonic_raw and realtime is jitterprone, probably to the point that it won't actually provide performance benefits over using realtime directly.