DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Stephen Hemminger <stephen@networkplumber.org>
To: Soumyadeep Hore <soumyadeep.hore@intel.com>
Cc: dev@dpdk.org, bruce.richardson@intel.com,
	rajesh3.kumar@intel.com, aman.deep.singh@intel.com,
	manoj.kumar.subbarao@intel.com
Subject: Re: [PATCH v2] examples/ptpclient: compensate for clock frequency drift
Date: Tue, 13 Oct 2026 15:13:35 -0700	[thread overview]
Message-ID: <20261013151335.40429bc2@phoenix.local> (raw)
In-Reply-To: <20261013220145.880388-1-soumyadeep.hore@intel.com>

On Wed, 14 Oct 2026 03:31:45 +0530
Soumyadeep Hore <soumyadeep.hore@intel.com> wrote:

> The ptpclient example corrected only the instantaneous phase offset by
> calling rte_eth_timesync_adjust_time() once per DELAY_RESP. It never
> compensated for oscillator frequency drift, so the transmitter/receiver
> offset settled at a non-zero steady-state value (proportional to the
> drift rate times the sync interval) instead of converging towards zero.
> 
> Replace the one-shot phase step with a PI clock servo, using the same
> model as linuxptp. The servo output is a frequency correction that is
> applied through the best mechanism the PMD provides:
> 
> - When the driver supports hardware frequency adjustment, the correction
>   is applied with rte_eth_timesync_adjust_freq() (for example the E810
>   INCVAL register).
> - Otherwise the same correction is realized in software as an
>   incremental phase step over the elapsed interval using
>   rte_eth_timesync_adjust_time(), which every timesync-capable PMD
>   provides.
> 
> Hardware support is probed once at runtime, so any PMD that implements
> the adjust_freq operation in the future uses the hardware path without
> further changes. The servo state is kept per port and the selected path
> is logged once per port.
> 
> Bugzilla ID: 1474
> 
> Signed-off-by: Soumyadeep Hore <soumyadeep.hore@intel.com>
> ---
> v2:
>  - Use transmitter/receiver instead of master/slave terminology

More detail AI review.

Review: [PATCH] examples/ptpclient: compensate for clock frequency drift

Builds clean with -Werror. Sign convention checked: delta_eval()
returns master - slave, so feeding it to the servo with a positive
output applied as +ppb is correct (linuxptp negates because its
offset is slave - master).

Warnings
--------

1. Integral term has no limit.

   drift_ppb accumulates KI * offset forever. linuxptp clamps the
   drift and the output to max_frequency (900000 ppb) because the
   hardware range is finite; ice turns an unbounded ppm into an
   incval that can run off the end. Clamp after the update:

	#define PTP_SERVO_MAX_PPB	900000.0
	...
	if (servo->drift_ppb > PTP_SERVO_MAX_PPB)
		servo->drift_ppb = PTP_SERVO_MAX_PPB;
	else if (servo->drift_ppb < -PTP_SERVO_MAX_PPB)
		servo->drift_ppb = -PTP_SERVO_MAX_PPB;

   and the same for ppb before applying it.

2. Gains assume a 1 s sync interval.

   KP = 0.7 and KI = 0.3 are linuxptp's values for sync interval
   1 s; linuxptp scales them as kp * interval^-0.3 and
   ki * interval^0.4 for other rates. Here both the integral update
   and the slope seed run once per DELAY_RESP with no time scaling,
   so at -3 or -4 log sync interval the integral runs 8-16x too
   fast and the loop is under-damped. The SYNC header carries
   logMessageInterval; use it:

	int8_t lmi = ptp_msg->sync.hdr.log_message_interval;
	double interval = ldexp(1.0, lmi);
	servo->kp = PTP_SERVO_KP_SCALE * pow(interval, -0.3);
	servo->ki = PTP_SERVO_KI_SCALE * pow(interval, 0.4);

   Or at minimum document that the constants are only correct for
   1 s sync.

3. Step branch leaves last_local pointing before the step.

   local is read before rte_eth_timesync_adjust_time(), so the next
   interval is measured as elapsed + step. On the first sync the
   NIC clock is usually at 0, so the step is ~56 years and the
   slope seed in case 1 comes out as 0. For a negative step larger
   than the elapsed time, local <= last_local and the software
   correction is silently skipped that sample. Account for the
   step:

	rte_eth_timesync_adjust_time(ptp->portid, offset);
	servo->last_offset = 0;
	servo->last_local = local + offset;

4. Software path does not remove the drift.

   In software mode the correction is a phase step applied at the
   end of each interval, so the clock free-runs for the whole
   interval and is pulled back afterwards. This moves the sawtooth
   so that the offset measured at sample time converges to 0, but
   the peak error is still drift * interval, same as before the
   patch. The commit message claims the frequency correction is
   "realized" in software; say what it actually does, otherwise
   users on PMDs without adjust_freq will expect a flat offset and
   not get one.

5. Documentation not updated.

   doc/guides/sample_app_ug/ptpclient.rst still describes the
   adjustment as a one-shot adj = -[(T2-T1)-(T4-T3)]/2 and "we
   adjust the PTP time receiver clock". Add a short paragraph on
   the PI servo, the step threshold and the hardware/software
   selection.

Info
----

6. The "\n" added to the print_clock_info() header line is an
   unrelated change; either mention it in the commit message or
   drop it.

7. Probing adjust_freq inside the servo and initialising
   freq_adj_supported = -1 over all RTE_MAX_ETHPORTS in lcore_main()
   is roundabout. Probe in port_init() where timesync is enabled,
   which also removes the tri-state int:

	ret = rte_eth_timesync_adjust_freq(port, 0);
	ptp_servo[port].freq_adj_hw = (ret == 0);

8. Double blank line after the ptp_servo[] definition.

      reply	other threads:[~2026-10-13 22:13 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-13 21:46 [PATCH] examples/ptpclient: compensate for clock frequency drift Soumyadeep Hore
2026-10-13 22:01 ` [PATCH v2] " Soumyadeep Hore
2026-10-13 22:13   ` Stephen Hemminger [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261013151335.40429bc2@phoenix.local \
    --to=stephen@networkplumber.org \
    --cc=aman.deep.singh@intel.com \
    --cc=bruce.richardson@intel.com \
    --cc=dev@dpdk.org \
    --cc=manoj.kumar.subbarao@intel.com \
    --cc=rajesh3.kumar@intel.com \
    --cc=soumyadeep.hore@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox