Tracking time

Updated: April 19, 2023

To keep QNX Neutrino clocks on track, you have the following options:

ClockAdjust()

In order to facilitate applying time corrections to CLOCK_REALTIME without having the system experience abrupt “steps” in time (or even having time jump backwards), the ClockAdjust() call provides the option to specify an interval over which the time correction is to be applied. This has the effect of speeding or retarding time over a specified interval until the system has synchronized to the indicated current time. This service can be used to implement network-coordinated time averaging between multiple nodes on a network.

libmod_timecc.a

The libmod_timecc.a kernel module uses ClockCycles() as a time source by converting its value, since boot, to nanoseconds to update CLOCK_MONOTONIC. See ClockCycles() for more information.

It's highly recommended to use libmod_timecc.a when:
  • Using high-resolution timers
  • Tickless operation is enabled
  • Any entity might delay system tick on CPU0 for nontrivial periods
Note: Depending on the requirements of your system, you decide if the drift is nontrivial. If you need to synchronize your system with external events, you need to characterize the drift in terms of typical and worst-case conditions and load scenarios.
To use libmod_timecc.a you need to modify the target buildfile to include the libmod_timecc.a kernel module, by adding a [module=timecc] prefix to the buildfile line that includes procnto*:
[module=timecc] PATH=/proc/boot ./procnto-smp-instr -vv
See the module attribute in the mkifs page for more information.

Be sure to set the timer_prog_time variable in qtime to zero (0). This can be done through the -f option in startup-*. Keep in mind, you don't need to set the timer_freq option when using the -f option in startup-*. The QTIME_FLAG_TIMECC flag is not set by startup-*, either automatically or via a command-line. The kernel sets the flag and is only visible once procnto is running. When set, this flag indicates that the libmod_timecc.a module is in use. See qtime for more information.

To avoid any interference with the module's timing, do not attach to the interrupt used by libmod_timecc.a from other processes. Only the timer hardware used by libmod_timecc.a can be a source of interrupts on the same interrupt level. This means that the interrupt level cannot be shared. The interrupt source on an x86_64 system is the LAPIC Timer. On an Armv8-A system, it is the Generic Timer.

When using InterruptHookIdle2(), the _NTO_IH_RESP_SYNC_TIME bit is ignored.

Some systems need special considerations. For an x86_64 system, do the following:
  • Ensure that the target has LAPIC (Local Advanced Programmable Interrupt Controller) that supports TSC-Deadline mode.
  • Configure startup-* to use LAPIC timer.
  • Make sure that intrinfo has the LAPIC as the first interrupt controller on the list.
  • You cannot use the -z or -zz options in startup-*.
For an Armv8-A system:
  • Configure your system to use CPU0's Generic Timer as the system tick.
Note:

If you are using QNX OS for Safety, you must use libmod_timecc-safety.a.