Re: [PATCH v7] posix-timers: add clock_compare system call

From: Sagi Maimon
Date: Thu Mar 28 2024 - 11:43:16 EST


Hi Thomas

On Sat, Mar 23, 2024 at 2:38 AM Thomas Gleixner <tglx@xxxxxxxxxxxxx> wrote:
>
> Sagi!
>
> On Wed, Mar 20 2024 at 16:42, Sagi Maimon wrote:
> > On Thu, Mar 14, 2024 at 8:08 PM Thomas Gleixner <tglx@xxxxxxxxxxxxx> wrote:
> >> Which is maximaly precise under the assumption that in the time between
> >> the sample points a1 and a2 neither the system clock nor the PCH clocks
> >> are changing their frequency significantly. That is a valid assumption
> >> when you put a reasonable upper bound on d2.
> >>
> >
> > You are right.
> > In fact, we are running this calculation on a user space application.
> > We use the new system call to get pairs of mono and PHC and then run
> > that calculation in user space.
> > That is why the system call returns pairs of clock samples and not the
> > diff between them.
>
> Please stop claiming things which are fundamentally wrong:
>
> The proposed system call returns the PHC sample and the midpoint of
> two CLOCK_WHATEVER samples which have been sampled before and after
> the PHC sample.
>
> That is fundamentally different from a pair of samples as I explained
> to you in great length more than once by now.
>
> I understand that you can't rely on the PTP_SYS_OFFSET_PRECISE IOCTL
> alone because there is not much hardware support, but what you are
> proposing is way worse than the other two PTP_SYS_OFFSET variants.
>
> PTP_SYS_OFFSET at least gives the caller a choice of analysis of the
> interleaving system timestamps.
>
> PTP_SYS_OFFSET_EXTENDED moves the outer sample points as close as
> possible to the actual PCH read and provides both outer samples to user
> space for analysis. It was introduced for a reason, no?
>
> Your proposed system call is just declaring arbitrarily that the
> CLOCK_WHATEVER sample is exactly the midpoint of the two outer samples
> and is therefore superior and correct.
>
> It is neither superior nor correct because the midpoint is an
> ill-defined assumption as I explained to you multiple times now.
>
> Aside of that the approach loses the extended information of
> PTP_SYS_OFFSET and PTP_SYS_OFFSET_EXTENDED including the more precise
> sampling behaviour of the latter. IOW, it is ignoring and throwing away
> the effort of people who cared about making the best out of the
> limitations of hardware including the already existing algorithms to
> make sense out of it.
>
> The P at the beginning of PTP does not mean 'Potentially precise' and
> the lack of C in PTP does not mean that Correctness is overrated.
>
> The problem is that these non hardware assisted IOCTL variants sample
> only CLOCK_REALTIME and not CLOCK_MONOTONIC_RAW, which is all you need
> to solve your problem at hand, no?
>
> That's absolutely not rocket science to solve. The below sketch does
> exactly that without creating an ill-defined syscall monstrosity, at the
> same time it is fully preserving the benefits of the existing IOCTL
> variants and therefore allows to apply already existing algorithms to
> analyse that data. That's too simple and too obviously correct, right?
>
> The thing is a sketch and it's neither compiled nor tested. It's just
> for illustration and you can keep all bugs you might find in it.
>
> On top this needs an analyis whether any of the gettimex64()
> implementations does something special instead of invoking the
> ptp_read_system_prets() and ptp_read_system_postts() helpers as close as
> possible to the PCH readout, but that's not rocket science either. It's
> just 21 callbacks to look at.
>
I like your suggestion, thanks!
it is what our user space needs from the kernel and with minimum kernel changes.
I will write it, test it and upload it with your permission (it is you
idea after all).
> It might also require a new set of variant '3' IOTCLS to make that flag
> field work, but that's not going to make the change more complex and
> it's an exercise left to the experts of that IOCTL interface.
>
I think that I understand your meaning.
There is a backward compatibility problem here.
Existing user space application using PTP_SYS_OFFSET_EXTENDED ioctl
won't have any problems
because of the "extoff->rsv[0] || extoff->rsv[1] || extoff->rsv[2]"
test, but what about all
old user space applications using: PTP_SYS_OFFSET ?
How can it be solved?
Can you explain what you meant above regarding the IOCTL?

Thanks,
Sagi



> Thanks,
>
> tglx
> ---
> drivers/ptp/ptp_chardev.c | 36 ++++++++++++++++++++++--------------
> include/linux/ptp_clock_kernel.h | 28 +++++++++++++++++++---------
> include/uapi/linux/ptp_clock.h | 10 ++++++++--
> 3 files changed, 49 insertions(+), 25 deletions(-)
>
> --- a/drivers/ptp/ptp_chardev.c
> +++ b/drivers/ptp/ptp_chardev.c
> @@ -164,9 +164,9 @@ long ptp_ioctl(struct posix_clock_contex
> struct ptp_sys_offset_precise precise_offset;
> struct system_device_crosststamp xtstamp;
> struct ptp_clock_info *ops = ptp->info;
> + struct ptp_system_timestamp sts = { };
> struct ptp_sys_offset *sysoff = NULL;
> struct timestamp_event_queue *tsevq;
> - struct ptp_system_timestamp sts;
> struct ptp_clock_request req;
> struct ptp_clock_caps caps;
> struct ptp_clock_time *pct;
> @@ -358,11 +358,13 @@ long ptp_ioctl(struct posix_clock_contex
> extoff = NULL;
> break;
> }
> - if (extoff->n_samples > PTP_MAX_SAMPLES
> - || extoff->rsv[0] || extoff->rsv[1] || extoff->rsv[2]) {
> + if (!extoff->n_samples || extoff->n_samples > PTP_MAX_SAMPLES ||
> + (extoff->flags & ~PTP_SYS_OFFSET_VALID_FLAGS) ||
> + extoff->rsv[0] || extoff->rsv[1]) {
> err = -EINVAL;
> break;
> }
> + sts.flags = extoff->flags;
> for (i = 0; i < extoff->n_samples; i++) {
> err = ptp->info->gettimex64(ptp->info, &ts, &sts);
> if (err)
> @@ -386,29 +388,35 @@ long ptp_ioctl(struct posix_clock_contex
> sysoff = NULL;
> break;
> }
> - if (sysoff->n_samples > PTP_MAX_SAMPLES) {
> + if (!sysoff->n_samples || sysoff->n_samples > PTP_MAX_SAMPLES ||
> + (sysoff->flags & ~PTP_SYS_OFFSET_VALID_FLAGS) ||
> + sysoff->rsv[0] || sysoff->rsv[1]) {
> err = -EINVAL;
> break;
> }
> + sts.flags = sysoff->flags;
> pct = &sysoff->ts[0];
> for (i = 0; i < sysoff->n_samples; i++) {
> - ktime_get_real_ts64(&ts);
> - pct->sec = ts.tv_sec;
> - pct->nsec = ts.tv_nsec;
> - pct++;
> - if (ops->gettimex64)
> - err = ops->gettimex64(ops, &ts, NULL);
> - else
> + if (ops->gettimex64) {
> + err = ops->gettimex64(ops, &ts, &sts);
> + } else {
> + ptp_read_system_prets(&sts);
> err = ops->gettime64(ops, &ts);
> + }
> if (err)
> goto out;
> +
> + pct->sec = sts.pre_ts.tv_sec;
> + pct->nsec = sts.pre_ts.tv_nsec;
> + pct++;
> pct->sec = ts.tv_sec;
> pct->nsec = ts.tv_nsec;
> pct++;
> }
> - ktime_get_real_ts64(&ts);
> - pct->sec = ts.tv_sec;
> - pct->nsec = ts.tv_nsec;
> + if (!ops->gettimex64)
> + ptp_read_system_postts(&sts);
> + pct->sec = sts.post_ts.tv_sec;
> + pct->nsec = sts.post_ts.tv_nsec;
> if (copy_to_user((void __user *)arg, sysoff, sizeof(*sysoff)))
> err = -EFAULT;
> break;
> --- a/include/linux/ptp_clock_kernel.h
> +++ b/include/linux/ptp_clock_kernel.h
> @@ -44,13 +44,15 @@ struct ptp_clock_request {
> struct system_device_crosststamp;
>
> /**
> - * struct ptp_system_timestamp - system time corresponding to a PHC timestamp
> - * @pre_ts: system timestamp before capturing PHC
> - * @post_ts: system timestamp after capturing PHC
> + * struct ptp_system_timestamp - System time corresponding to a PHC timestamp
> + * @flags: Flags to select the system clock to sample
> + * @pre_ts: System timestamp before capturing PHC
> + * @post_ts: System timestamp after capturing PHC
> */
> struct ptp_system_timestamp {
> - struct timespec64 pre_ts;
> - struct timespec64 post_ts;
> + unsigned int flags;
> + struct timespec64 pre_ts;
> + struct timespec64 post_ts;
> };
>
> /**
> @@ -457,14 +459,22 @@ static inline ktime_t ptp_convert_timest
>
> static inline void ptp_read_system_prets(struct ptp_system_timestamp *sts)
> {
> - if (sts)
> - ktime_get_real_ts64(&sts->pre_ts);
> + if (sts) {
> + if (sts->flags & PTP_SYS_OFFSET_MONO_RAW)
> + ktime_get_raw_ts64(&sts->pre_ts);
> + else
> + ktime_get_real_ts64(&sts->pre_ts);
> + }
> }
>
> static inline void ptp_read_system_postts(struct ptp_system_timestamp *sts)
> {
> - if (sts)
> - ktime_get_real_ts64(&sts->post_ts);
> + if (sts) {
> + if (sts->flags & PTP_SYS_OFFSET_MONO_RAW)
> + ktime_get_raw_ts64(&sts->post_ts);
> + else
> + ktime_get_real_ts64(&sts->post_ts);
> + }
> }
>
> #endif
> --- a/include/uapi/linux/ptp_clock.h
> +++ b/include/uapi/linux/ptp_clock.h
> @@ -76,6 +76,10 @@
> */
> #define PTP_PEROUT_V1_VALID_FLAGS (0)
>
> +/* Bits for PTP_SYS_OFFSET and PTP_SYS_OFFSET_EXTENDED */
> +#define PTP_SYS_OFFSET_MONO_RAW (1U << 0)
> +#define PTP_SYS_OFFSET_VALID_FLAGS (PTP_SYS_OFFSET_MONO_RAW)
> +
> /*
> * struct ptp_clock_time - represents a time value
> *
> @@ -146,7 +150,8 @@ struct ptp_perout_request {
>
> struct ptp_sys_offset {
> unsigned int n_samples; /* Desired number of measurements. */
> - unsigned int rsv[3]; /* Reserved for future use. */
> + unsigned int flags;
> + unsigned int rsv[2]; /* Reserved for future use. */
> /*
> * Array of interleaved system/phc time stamps. The kernel
> * will provide 2*n_samples + 1 time stamps, with the last
> @@ -157,7 +162,8 @@ struct ptp_sys_offset {
>
> struct ptp_sys_offset_extended {
> unsigned int n_samples; /* Desired number of measurements. */
> - unsigned int rsv[3]; /* Reserved for future use. */
> + unsigned int flags;
> + unsigned int rsv[2]; /* Reserved for future use. */
> /*
> * Array of [system, phc, system] time stamps. The kernel will provide
> * 3*n_samples time stamps.