kirr has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmocom-bb/+/40062?usp=email )
Change subject: trx_toolkit/_clck_gen: Optimize timerfd read ......................................................................
trx_toolkit/_clck_gen: Optimize timerfd read
As can be seen from http://navytux.spb.ru/~kirr/osmo/fake_trx/pyx-base.html (CLCKGen_11tick) the system is spending just a bit of time doing os.read. But it is also the fact that os.read releases/reacquires gil which, as Iaa675c95059ec8ccfad667f69984d5a7f608c249 (trx_toolkit/clck_gen: Don't use threads because Python GIL is latency killer) shows can have dramatic effect.
-> Avoid both py wrapper overhead and potential gil ping-pong performance penalty by doing read from ._timerfd ourselves.
Change-Id: I23d5fc2b7209592c62a4655c42004777b8bb31a8 --- M src/target/trx_toolkit/_clck_gen.pyx 1 file changed, 12 insertions(+), 3 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmocom-bb refs/changes/62/40062/1
diff --git a/src/target/trx_toolkit/_clck_gen.pyx b/src/target/trx_toolkit/_clck_gen.pyx index 46e28c1..e63eacb 100644 --- a/src/target/trx_toolkit/_clck_gen.pyx +++ b/src/target/trx_toolkit/_clck_gen.pyx @@ -22,8 +22,11 @@ import os import sys
+from udp_link cimport _raise_oserr from cython cimport final
+from libc.stdint cimport uint64_t +from posix.unistd cimport read
import gsm_shared cdef int GSM_HYPERFRAME = gsm_shared.GSM_HYPERFRAME @@ -88,9 +91,15 @@ # run .send_clck_ind() every .ctr_interval # NOTE timerfd is careful not to accumulate timing error when organizing the clock loop
- _ = os.read(self._timerfd, 8) - assert len(_) == 8, len(_) - ticks = int.from_bytes(_, byteorder=sys.byteorder) + cdef uint64_t ticks + # NOTE we do not release/reacquire gil to save us from gil ping-pong performance penalty + # we can do that because fake_trx is single-threaded and invokes us here then .timerfd is ready + # for standalone usage the worst that would happen is 1 GSM frame pause. + # But standalone-usage in clck_gen.py is single-threaded as well, so that is also ok. + n = read(self._timerfd, &ticks, sizeof(ticks)) + if n == -1: + _raise_oserr() + assert n == 8, n assert ticks > 0, ticks if ticks > 1: log.warning("CLCKGen: time overrun by %dus; resetting the clock" % ((ticks-1)*self._t_tick * ns // us))