Files
dragonpilot/common/realtime.py

83 lines
2.3 KiB
Python
Raw Normal View History

2016-11-29 18:34:21 -08:00
"""Utilities for reading real time clocks and keeping soft real time constraints."""
2017-06-28 13:57:09 -07:00
import os
2016-11-29 18:34:21 -08:00
import time
import platform
import subprocess
import multiprocessing
2017-06-28 13:57:09 -07:00
from cffi import FFI
2017-01-25 16:16:00 +03:00
2019-06-06 04:38:45 +00:00
# Build and load cython module
import pyximport
installer = pyximport.install(inplace=True, build_dir='/tmp')
from common.clock import monotonic_time, sec_since_boot # pylint: disable=no-name-in-module, import-error
pyximport.uninstall(*installer)
assert monotonic_time
assert sec_since_boot
2017-01-25 16:16:00 +03:00
2016-11-29 18:34:21 -08:00
2019-06-28 21:11:30 +00:00
# time step for each process
DT_CTRL = 0.01 # controlsd
DT_PLAN = 0.05 # mpc
DT_MDL = 0.05 # model
2019-10-09 18:43:53 +00:00
DT_RDR = 0.05 # radar
2019-06-28 21:11:30 +00:00
DT_DMON = 0.1 # driver monitoring
2019-07-30 02:27:48 +00:00
DT_TRML = 0.5 # thermald and manager
2019-06-28 21:11:30 +00:00
2019-06-06 04:38:45 +00:00
ffi = FFI()
ffi.cdef("long syscall(long number, ...);")
2017-06-28 13:57:09 -07:00
libc = ffi.dlopen(None)
2016-11-29 18:34:21 -08:00
2017-06-28 13:57:09 -07:00
2016-11-29 18:34:21 -08:00
def set_realtime_priority(level):
if os.getuid() != 0:
2017-01-09 20:59:00 -08:00
print("not setting priority, not root")
2016-11-29 18:34:21 -08:00
return
if platform.machine() == "x86_64":
NR_gettid = 186
elif platform.machine() == "aarch64":
NR_gettid = 178
else:
raise NotImplementedError
tid = libc.syscall(NR_gettid)
2016-12-12 17:47:46 -08:00
return subprocess.call(['chrt', '-f', '-p', str(level), str(tid)])
2016-11-29 18:34:21 -08:00
2019-10-09 18:43:53 +00:00
class Ratekeeper():
2016-11-29 18:34:21 -08:00
def __init__(self, rate, print_delay_threshold=0.):
"""Rate in Hz for ratekeeping. print_delay_threshold must be nonnegative."""
self._interval = 1. / rate
self._next_frame_time = sec_since_boot() + self._interval
self._print_delay_threshold = print_delay_threshold
self._frame = 0
self._remaining = 0
self._process_name = multiprocessing.current_process().name
@property
def frame(self):
return self._frame
@property
def remaining(self):
return self._remaining
# Maintain loop rate by calling this at the end of each loop
def keep_time(self):
2017-01-09 20:59:00 -08:00
lagged = self.monitor_time()
2016-11-29 18:34:21 -08:00
if self._remaining > 0:
time.sleep(self._remaining)
2017-01-09 20:59:00 -08:00
return lagged
2016-11-29 18:34:21 -08:00
# this only monitor the cumulative lag, but does not enforce a rate
def monitor_time(self):
2017-01-09 20:59:00 -08:00
lagged = False
2016-11-29 18:34:21 -08:00
remaining = self._next_frame_time - sec_since_boot()
self._next_frame_time += self._interval
2019-06-06 04:38:45 +00:00
if self._print_delay_threshold is not None and remaining < -self._print_delay_threshold:
2017-02-08 09:51:56 -08:00
print("%s lagging by %.2f ms" % (self._process_name, -remaining * 1000))
2017-01-09 20:59:00 -08:00
lagged = True
2016-11-29 18:34:21 -08:00
self._frame += 1
self._remaining = remaining
2017-01-09 20:59:00 -08:00
return lagged