Change in osmocom-bb[master]: trx_toolkit/transceiver.py: implement the transmit burst queue

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

fixeria gerrit-no-reply at lists.osmocom.org
Sun Jul 12 12:54:09 UTC 2020


fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmocom-bb/+/19228 )


Change subject: trx_toolkit/transceiver.py: implement the transmit burst queue
......................................................................

trx_toolkit/transceiver.py: implement the transmit burst queue

In order to reflect the UL/DL delay caused by the premature burst
scheduling (a.k.a. 'fn-advance') in a virtual environment, the
Transceiver implementation now queues all to be transmitted bursts,
so they remain in the queue until the appropriate time of transmission.

The API user is supposed to call recv_data_msg() in order to obtain
a L12TRX message on the TRXD (data) inteface, so it gets queued by
this function.  Then, to ensure the timeous transmission, the user
of this implementation needs to call clck_tick() on each TDMA
frame.  Both functions are thread-safe (queue mutex).

In a multi-trx configuration, the use of queue additionally ensures
proper burst aggregation on multiple TRXD connections, so all L12TRX
messages are guaranteed to be sent in the right order, i.e. with
monolithically-increasing TDMA frame numbers.

Of course, this change increases the overall CPU usage, given that
each transceiver gets its own queue, and we need to serve them all
on every TDMA frame.  According to my measurements, when running
test cases from ttcn3-bts-test, the average load is ~50% higher
than what it used to be.  Still not significantly high, though.

Change-Id: Ie66ef9667dc8d156ad578ce324941a816c07c105
Related: OS#4658, OS#4546
---
M src/target/trx_toolkit/fake_trx.py
M src/target/trx_toolkit/transceiver.py
2 files changed, 74 insertions(+), 4 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmocom-bb refs/changes/28/19228/1

diff --git a/src/target/trx_toolkit/fake_trx.py b/src/target/trx_toolkit/fake_trx.py
index 27c2b88..b487a93 100755
--- a/src/target/trx_toolkit/fake_trx.py
+++ b/src/target/trx_toolkit/fake_trx.py
@@ -388,6 +388,8 @@
 
 		# Init shared clock generator
 		self.clck_gen = CLCKGen([])
+		# This method will be called on each TDMA frame
+		self.clck_gen.clck_handler = self.clck_handler
 
 		# Power measurement emulation
 		# Noise: -120 .. -105
@@ -456,14 +458,18 @@
 			for trx in self.trx_list.trx_list:
 				# DATA interface
 				if trx.data_if.sock in r_event:
-					msg = trx.recv_data_msg()
-					if msg is not None:
-						self.burst_fwd.forward_msg(trx, msg)
+					trx.recv_data_msg()
 
 				# CTRL interface
 				if trx.ctrl_if.sock in r_event:
 					trx.ctrl_if.handle_rx()
 
+	# This method will be called by the clock thread
+	def clck_handler(self, fn):
+		# We assume that this list is immutable at run-time
+		for trx in self.trx_list.trx_list:
+			trx.clck_tick(self.burst_fwd, fn)
+
 	def shutdown(self):
 		log.info("Shutting down...")
 
diff --git a/src/target/trx_toolkit/transceiver.py b/src/target/trx_toolkit/transceiver.py
index 474834d..119f3e2 100644
--- a/src/target/trx_toolkit/transceiver.py
+++ b/src/target/trx_toolkit/transceiver.py
@@ -24,6 +24,7 @@
 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
 import logging as log
+import threading
 
 from ctrl_if_trx import CTRLInterfaceTRX
 from data_if import DATAInterface
@@ -123,6 +124,37 @@
 	Transceiver and all its timeslots, so using in for the BTS side
 	does not make any sense (imagine BCCH hopping together with DCCH).
 
+	== The transmit burst queue
+
+	According to 3GPP 45.002, the time difference between Uplink and
+	Downlink corresponds to three TDMA timeslot periods.  However,
+	in general the L1 implementations (such as osmo-bts-trx and trxcon)
+	never schedule to be transmitted bursts for the current TDMA frame
+	immediately.  Instead, they are being scheduled prematurely.
+
+	The rationale is that both transceiver and the L1 implementation
+	are separete processes that are not perfectly synchronized in time.
+	Moreover, the transceiver needs some time to prepare a burst for
+	transmission.  This is why the time difference between Uplink and
+	Downlink is actually much higher on practice (20 TDMA frame periods
+	by default, at the moment of writing this patch).
+
+	In order to reflect that delay in a virtual environment, this
+	implementation, just like a normal transceiver (e.g. osmo-trx),
+	queues all to be transmitted (L12TRX) bursts, so hey remain in
+	the transmit queue until the appropriate time of transmission.
+
+	The API user is supposed to call recv_data_msg() in order to obtain
+	a L12TRX message on the TRXD (data) inteface, so it gets queued by
+	this function.  Then, to ensure the timeous transmission, the user
+	of this implementation needs to call clck_tick() on each TDMA
+	frame.  Both functions are thread-safe (queue mutex).
+
+	In a multi-trx configuration, the use of queue additionally ensures
+	proper burst aggregation on multiple TRXD connections, so all L12TRX
+	messages are guaranteed to be sent in the right order, i.e. with
+	monolithically-increasing TDMA frame numbers.
+
 	"""
 
 	def __init__(self, bind_addr, remote_addr, base_port, name = None,
@@ -178,6 +210,10 @@
 		# List of child transceivers
 		self.child_trx_list = TRXList()
 
+		# Tx (L12TRX) burst queue and mutex
+		self._tx_queue_lock = threading.Lock()
+		self._tx_queue = []
+
 	def __str__(self):
 		desc = "%s:%d" % (self.remote_addr, self.base_port)
 		if self.child_idx > 0:
@@ -234,10 +270,12 @@
 				trx.running = True
 			elif event == "POWEROFF":
 				trx.running = False
+				trx.tx_queue_clear()
 				trx.disable_fh()
 
-		# Reset frequency hopping parameters
+		# Reset frequency hopping parameters, clear the queue
 		if event == "POWEROFF":
+			self.tx_queue_clear()
 			self.disable_fh()
 
 		# Trigger clock generator if required
@@ -275,8 +313,34 @@
 				"configured => dropping..." % (self, msg.desc_hdr()))
 			return None
 
+		# Enque the message, it will be sent later
+		self.tx_queue_append(msg)
 		return msg
 
 	def handle_data_msg(self, msg):
 		# TODO: make legacy mode configurable (via argv?)
 		self.data_if.send_msg(msg, legacy = True)
+
+	def tx_queue_append(self, msg):
+		with self._tx_queue_lock:
+			self._tx_queue.append(msg)
+
+	def tx_queue_clear(self):
+		with self._tx_queue_lock:
+			self._tx_queue.clear()
+
+	def clck_tick(self, fwd, fn):
+		if not self.running:
+			return
+
+		self._tx_queue_lock.acquire()
+
+		for msg in self._tx_queue:
+			if msg.fn == fn:
+				fwd.forward_msg(self, msg)
+			elif msg.fn < fn:
+				log.warning("(%s) Stale TRXD message (fn=%u): %s"
+					% (self, fn, msg.desc_hdr()))
+
+		self._tx_queue = [msg for msg in self._tx_queue if msg.fn > fn]
+		self._tx_queue_lock.release()

-- 
To view, visit https://gerrit.osmocom.org/c/osmocom-bb/+/19228
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmocom-bb
Gerrit-Branch: master
Gerrit-Change-Id: Ie66ef9667dc8d156ad578ce324941a816c07c105
Gerrit-Change-Number: 19228
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanitskiy at sysmocom.de>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20200712/d99be7e6/attachment.htm>


More information about the gerrit-log mailing list