Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Independent clock for arbitrary timescale #389

Open
teodly opened this issue Jan 31, 2024 · 12 comments
Open

Independent clock for arbitrary timescale #389

teodly opened this issue Jan 31, 2024 · 12 comments

Comments

@teodly
Copy link
Contributor

teodly commented Jan 31, 2024

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
Copy link
Member

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
Copy link
Contributor

dsseng commented Feb 2, 2024

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
Copy link
Contributor Author

teodly commented Feb 5, 2024

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
Copy link
Member

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
Copy link
Contributor Author

teodly commented Feb 9, 2024

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

Other changes are necessary for:

  • shared_clock.rs - making OverlayClock share state when cloned, as LinuxClock does. So Arc<Mutex<_>> was needed.
  • main.rs - allowing use of different implementations of Clock in port-related functions.
  • main.rs & statime-linux/src/clock/mod.rs - a small refactor to expose unified interface for converting timescales - we need it to convert CLOCK_REALTIME timestamps to TAI, as well as underlying clock's timestamps to overlay clock

@davidv1992
Copy link
Member

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
Copy link

cmeissl commented Feb 23, 2024

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
Copy link
Contributor Author

teodly commented Feb 29, 2024

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
Copy link
Member

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
Copy link
Member

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
Copy link
Contributor Author

teodly commented Jul 8, 2024

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:

  • PHCs are independent from other clocks so they can use any timescale. Currently they always have TAI timescale because PTP is assumed to be a trustworthy source of TAI (that's not true for AV networks).
  • PHC_SYS_OFFSET ioctl used in clock_steering::unix::UnixClock::system_offset always returns system timestamps from CLOCK_REALTIME. We're accounting for it by adding TAI-REALTIME offset.
    • We need another method that allows specifying the reference "system" clock.
      • If PHC_SYS_OFFSET returns successfully, returned REALTIME timescale needs to be converted to our virtual clock's timescale.
      • The specified clock can be directly used in the fallback software timestamp sandwiching.
      • A kernel patch to return CLOCK_MONOTONIC_RAW has been proposed. When it is upstreamed, it would make our measurements more precise - computing virtual clock's timestamp from underlying clock's timestamp is trivial and nearly lossless.
  • When software timestamping is used, clock_task is not run at all because there is only one clock - system clock. Instead, timestamps in REALTIME timescale are converted to TAI for measurement purposes. If we're running as a slave, CLOCK_REALTIME is adjusted (implicitly adjusting CLOCK_TAI).
    • We need to use virtual clock instead of CLOCK_TAI. Similarly as in considerations about PHC_SYS_OFFSET, we need a way of converting REALTIME timescale to our virtual clock.

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
Copy link
Member

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants