run script when chrony steps clock - linux

I need to start a certain service after system clock was correctly stepped by crony.
System time is maintained by chrony (chronyd (chrony) version 3.5 (+CMDMON +NTP +REFCLOCK +RTC -PRIVDROP -SCFILTER -SIGND +ASYNCDNS -SECHASH +IPV6 -DEBUG)).
Chrony setup, if relevant, is:
server 192.168.100.1 trust minpoll 2 maxpoll 4 polltarget 30
refclock PPS /dev/pps0 refid KPPS trust lock GNSS maxdispersion 3 poll 2
refclock SOCK /var/run/chrony.sock refid GNSS maxdispersion 0.2 noselect
makestep 0.1 -1
driftfile /var/lib/chrony/drift
rtcsync
example of a "normal, tracking status" is:
/ # chronyc tracking
Reference ID : C0A86401 (192.168.100.1)
Stratum : 2
Ref time (UTC) : Wed Dec 01 11:52:08 2021
System time : 0.000004254 seconds fast of NTP time
Last offset : +0.000000371 seconds
RMS offset : 0.000011254 seconds
Frequency : 17.761 ppm fast
Residual freq : +0.001 ppm
Skew : 0.185 ppm
Root delay : 0.000536977 seconds
Root dispersion : 0.000051758 seconds
Update interval : 16.2 seconds
Leap status : Normal
while "unsynchronized" (initial) status is:
/ # chronyc tracking
Reference ID : 00000000 ()
Stratum : 0
Ref time (UTC) : Thu Jan 01 00:00:00 1970
System time : 0.000000000 seconds fast of NTP time
Last offset : +0.000000000 seconds
RMS offset : 0.000000000 seconds
Frequency : 0.000 ppm slow
Residual freq : +0.000 ppm
Skew : 0.000 ppm
Root delay : 1.000000000 seconds
Root dispersion : 1.000000000 seconds
Update interval : 0.0 seconds
Leap status : Not synchronised
I seem to remember crony can call a script whenever stratus level changes, but I was unable to find references.
In any case:
Is there any way to instruct crony to run a script/program or otherwise send some signal whenever acquires/loses tracking with a valid server?
I am currently relying on a rather ugly: while chronyc tracking | grep -q "Not synchronised"; do sleep 1; done but a proactive signalling by chronyd would be preferred.
Details:
System is a (relatively) small IoT device running Linux (Yocto)
It has no RTC (it always starts with clock set to Epoch).
System has no connection to the Internet (initially).
System has connection to a device having a GNSS
receiver and correct time is derived from there.
There may be a (sometimes 'very') long time before GNSS acquires a fix and thus can propagate time.
At a certain point chrony finally gets the right time
and steps system clock. After this is done I need to start a service
(or run a script or whatever).
I am currently polling chronyc tracking and parsing status, but that is not really nice.

I was looking to do the same and came up empty-handed.
I did, however, find chronyc waitsync, which appears to be a built-in way to do the polling, without the need to parse and sleep explicitly. This works well enough for my case, since I only need to delay a single start-up action.
The existence of this command also hints (albeit by no means proves) that direct triggering may not be supported. If triggering is a hard requirement, rsyslogd can help.
BTW, one can only admire the enthusiasm of systemd fans, spreading the love even when their purported answer is obviously and completely irrelevant.
Clearly, the target system does NOT use systemd. The question is about chronyd, not about systemd-timesyncd, while systemd-time-wait-sync.service applies only to the latter.

Suggesting to investigate systemd-time-wait-sync.service in here.
The suggested technique is to use systemd service unit that waits for systemd-time-wait-sync.service to synchronize kernel clock.
Using after command in the service unit file or pipe.
These technique are described here and here.

Related

What time from an NTP time server should be used to set my clock?

I am using Python3 with the ntplib https://pypi.org/project/ntplib/ to query an NTP time server. Works well, but I am confused as to which of the offered time variables to use to correctly set the clock on my computer.
Reading the IETF document for NTP https://www.rfc-editor.org/rfc/rfc5905 on pages 23ff I settled for either:
Transmit Timestamp (xmt): Time at the server when the response left
for the client, in NTP timestamp format.
Destination Timestamp (dst): Time at the client when the reply
arrived from the server, in NTP timestamp format.
My interpretation is that the xmt is the correct time at the moment the server sent it, which seems to suggest that I would still have to add the time delay for the transmission time from server to my computer?
The dst time definition is unclear to me. It could mean either:
it is the xmt time with the transmission time already added and so is the proper time to use to set my clock
or it is the time of my clock at the arrival of the NTP packet. If my clock were wrong, it would NOT be the proper time to use
Which one is it?
I think that #1 (using dst) makes more sense, but most scripts found on the net use plain xmt. In terms of code for ntplib this means:
client = ntplib.NTPClient()
resp = client.request(server, version=3)
xmt = resp.tx_time # for the use of xmt
# or:
dst = resp.dest_time # for the use of dst
In some test runs dst was always later than xmt by 3 ... 30 ms, with no obvious pattern on the use of a local, regional, or global NTP server.
So it is not much, but I don't want to make an illogical choice.
NTP response has 5 timestamps
Field name
Name
Description
ref_timestamp
Reference Timestamp
Time when the system clock was last set or corrected, in NTP timestamp format
orig_timestamp
originate timestamp (T1)
Time at the client when the request departed for the server, in NTP timestamp format.
recv_timestamp
receive timestamp (T2)
Time at the server when the request arrived from the client, in NTP timestamp format.
tx_timestamp
transmit timestamp (T3)
Time at the server when the response left for the client, in NTP timestamp format.
dest_timestamp
Destination timestamp (T4)
Time at the client when the reply arrived from the server, in NTP timestamp format.
Each of the timestamps fields has an associated time field which is the timestamp as system time which is time in seconds since the Epoch.
Field name
Description
ref_time
reference timestamp as system time
orig_time
originate timestamp as system time
recv_time
receive timestamp as system time
tx_time
transmit timestamp as system time
dest_time
destination timestamp as system time
The offset is the difference between your local clock and the clock of the NTP server which is the amount to correct the local clock by in seconds to match the clock of the server.
offset = ((recv_timestamp - orig_timestamp) +
(tx_timestamp - dest_timestamp))/2
offset = ((T2 - T1) + (T3 - T4))/2
Example:
import ntplib
from datetime import datetime
client = ntplib.NTPClient()
server = '0.pool.ntp.org'
resp = client.request(server, version=3)
print("offset", resp.offset)
print("orig_time:", datetime.utcfromtimestamp(resp.orig_time).strftime('%Y-%d-%m %H:%M:%S.%f'))
print("recv_time:", datetime.utcfromtimestamp(resp.recv_time).strftime('%Y-%d-%m %H:%M:%S.%f'))
print("tx_time :", datetime.utcfromtimestamp(resp.tx_time).strftime('%Y-%d-%m %H:%M:%S.%f'))
Output
offset 0.009677410125732422
orig_time: 2021-06-01 00:06:10.553593
recv_time: 2021-06-01 00:06:10.665957
tx_time : 2021-06-01 00:06:10.665980
Offset with positive value means the server clock is ahead of the local clock by that number of seconds. A negative value means the local clock is ahead.
In the output above, the server received the time request at 00:06:10.665957 (recv_time) and responded with a reply at 00:06:10.665980 (tx_time) which took 23 microseconds to complete.
The knowledge of all the various timestamps is not very helpful for the understanding of how to change my computer's time to agree with the NTP time server.
After some days of fiddling I believe I found the solution. And the answer is: Don't use any of the time stamps - instead use only the offset! And the offset is already calculated for you by the ntplib.
This is surprising, since most people use one of the time stamps (mostly xmt), and, I may have missed it, but I have never seen anyone using the offset.
Let's look at an example. I have used 3 NTP server: one in Asia (most remote), one in Europe (medium distance), and one in Germany (closest). The round trip times for the data packages are quite variable, ranging from a few ms to 200ms, independent of close or distant targets. I picked one example to demonstrate my point (code at the end). From the timestamps I subtracted the orig, so all times are relative to their respective orig.
NTP Server Type t-stamp sec
asia.pool.ntp.org orig 0.000
asia.pool.ntp.org recv 0.004
asia.pool.ntp.org tx 0.004
asia.pool.ntp.org dest 0.014
asia.pool.ntp.org offset -0.003
europe.pool.ntp.org orig 0.000
europe.pool.ntp.org recv 0.008
europe.pool.ntp.org tx 0.008
europe.pool.ntp.org dest 0.020
europe.pool.ntp.org offset -0.002
de.pool.ntp.org orig 0.000
de.pool.ntp.org recv 0.008
de.pool.ntp.org tx 0.008
de.pool.ntp.org dest 0.019
de.pool.ntp.org offset -0.002
In the Asia example total round trip takes 14 ms. The clock difference is 4ms in sending, and 10ms in receiving. Thus the offset is (4 - 10)/2 = -3ms.
The all important assumption to make now is that the travel times to and from are the same! Then I can say if I added this offset to my computer times, both times would become the same!
Same works for Europe: round trip 20ms, offset: (8 - 12)/2 = -2ms, and Germany: round trip 19ms, offset:(8 - 11)/2 = -1.5ms.
As the offset is already given by the lib, so all you do is add(!, not subtract) this signed offset to your computer's time.
I have then recorded the ntplib-offsets while using the German (the closest) NTP server for about half hour:
'Ambient' is the offset reported by the ntplib in ms.
It looks like my computer is well set with its time mostly within 5ms of NTP time. But there are some significant excursions up to 70ms! In a program I could have chosen this - obviously wrong - time.
Obvious question: how can I make sure to not get an outlier in my clock adjustment?
The essential part of the code:
for i, ntpserver in enumerate(NTP_SERVERS):
ntps = []
client = ntplib.NTPClient()
try:
response = client.request(ntpserver, version=4, timeout=0.5) # latest NTP version = 4
orig = response.orig_time
recv = response.recv_time
tx = response.tx_time
dest = response.dest_time
offs = response.offset
ntps.append( ["orig" , orig - orig])
ntps.append( ["recv" , recv - orig])
ntps.append( ["tx " , tx - orig])
ntps.append( ["dest" , dest - orig])
ntps.append( ["offset" , offs])
for a in ntps:
print("{:20s} {:15s} {:10.3f} ".format(ntpserver, a[0], a[1]))
except Exception as e:
msg = fncname + "FAILED with Exception: {}".format(e)
edprint(msg)

How to increase kernel poll rate for accelerometer?

I'm using the hwmon/mxc_mma8451.c module to access an accelerometer. Using /sys/devices/virtual/input/input0/poll I can change the polling rate to some degree... if I set a larger millisecond value the polling becomes slower. However, I cannot seem to get below around 30ms per poll, despite the device driver source apparently allowing as low as 1ms per poll. The accelerometer itself supports 800Hz sample rate, so that is not the bottleneck. When I write a value of 1 to the above file, I see each sample occurs either 30ms or 60ms from the previous sample, so it is not even consistent. However, even 30ms is unacceptably slow at it is only 33Hz.
The kernel source for the module clearly shows that I should be able to use a value of 1:
#define POLL_INTERVAL_MIN 1
#define POLL_INTERVAL_MAX 500
#define POLL_INTERVAL 100 /* msecs */
...
mma8451_idev->poll_interval = POLL_INTERVAL;
mma8451_idev->poll_interval_min = POLL_INTERVAL_MIN;
mma8451_idev->poll_interval_max = POLL_INTERVAL_MAX;
I'm not familiar with exactly how Linux does this kind of polling, but this system has a 10ms tick, so even if sampling with ticks, why is it taking 3 or 6 ticks per sample and nothing else? Is there some kernel parameter somewhere else that is throttling how fast polling can occur?
Linux kernel version is 3.14.28 for IMX28 (ARM) if that makes any difference. This is the version available for the device in question, so I can't just up and use a different/newer one.

Synchronize the time between an android app and a server

I use a raspberry pi with a Bluetooth dongle to simulate a beacon. I want to measure the time needed for a mobile app to detect the UUID of a beacon when I change it in the raspberry. With this code I found out the server used by the smartphone to synchronize the tile
final Resources res = this.getResources();
final int id = Resources.getSystem().getIdentifier(
"config_ntpServer", "string","android");
final String defaultServer = res.getString(id);
Than I synchronized the time in the raspberry pi with
sudo ntpdate -u 2.android.pool.ntp.org
Before I change the id of the beacon I print the time
timestamp() {
date +"%T,%3N"
}
timestamp # print timestamp
sudo hcitool -i hci0 cmd 0x08 0x0008 1e 02 01 1.....
Then I compare the time when I changed the UUID and the time in the logcat when the UUID was seen for the first time and the result is alwayse negative
UUID changed at 15:33:03,276 and detected at 15:33:02.301.
Is this a synchronization problem? Is there a better way to do this?
A few thoughts:
Both the Android device and the Pi by default will sync their time to a NTP server automatically if they have a network connection. You should not have to do anything.
The NTP daemon doesn't always change the clock immediately -- it adjusts it slowly over time so as not to upset linux processes by an immediate jump. Since the Raspberry Pi has no real time clock, it always has incorrect time at boot. You may need to wait minutes after boot before it is in sync with the Android device.
NTP is not perfect. Don't expect to get your clocks synchronized to more than a few 10s of milliseconds when using internet time servers. Since bluetooth detection times can be very fast (also in the range of 10s of milliseconds), if you are getting detection times of -100 ms, this may be within the limits of this setup.
What you are showing is a detection time of about -1.0 second. This suggests that the time is not synchronized well. I would suspect the Pi is the problem and troubleshoot there. It might be helpful to show the time to the millisecond on both devices side by side to troubleshoot.

When does linux set the computer's correct time?

In a Linux CentOS 5 machine, I am running process.sh using a cronjob at #reboot, every day (the machine gets shut off every night and turned on every morning).
process.sh takes the 'date' of the computer, and writes it to a log file, then exits.
When I check the logfile, the timestamp in it says "Tue Jan 1 13:14:38 GMT 2008"
When I go to the console of the computer and give it the 'date' command, it prints the correct date.
My best guess is that my cronjob is running BEFORE the computer sets its correct time.
Is there a way to fix this?
The battery that powers the CMOS memory on your motherboard may have run out. Try replacing it by a fresh one. It should look something like this.
This advice is based on the fact that the date of your log entry is "Jan 1 2008" which looks conspicuously like an epoch your motherboard may use. However, the time-of-day 13:14:38 is a little off for this; while the 13 hour shift can be explained if you are in the correct time zone, the nearly 15 minute offset seems odd. Unless your computer takes that long to boot to the point where cron executes your job. And of course, the reason why you eventually see the correct time is probably that ntp fixed the system time, as others have noted.

How do I know the last sched time of a process

I current run into an issue that a process seems stuck somehow, it just doesn't gets scheduled, the status is always 'S'. I have monitored sched_switch_task trace by debugfs for a while, didn't see the process get scheduled. So I would like to know when is that last time scheduled of this process by kernel?
Thanks a lot.
It might be possible using the info in /proc/pid#/sched file.
In there you can find these parameters (depending on the OS version, mine is opensuse 3.16.7-21-desktop):
se.exec_start : 593336938.868448
...
se.statistics.wait_start : 0.000000
se.statistics.sleep_start : 593336938.868448
se.statistics.block_start : 0.000000
The values represent timestamps relative to the system boot time, but in a unit which may depend on your system (in my example the unit is 0.5 msec, for a total value of ~6 days 20 hours and change).
In the last 3 parameters listed above at most one appears to be non-zero at any time and it I suspect that the respective non-zero value represents the time when it last entered the corresponding state (with the process actively running when all are zero).
So if your process is indeed stuck the non-zero value would have recorded when it got stuck.
Note: this is mostly based on observations and assumptions - I didn't find these parameters documented anywhere, so take them with a grain of salt.
Plenty of other scheduling info in that file, but mostly stats and without documentation difficult to use.

Resources