<p>Pau Espin Pedrol has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/14167">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Add rate_ctr support to store/retrieve SDR errors through VTY<br><br>Introduce a unified implementation-agnostic interface for radioDevice to<br>signal SDR error counters to upper layers and manage them.<br>This patch only implements counters for osmo-trx-lms (other devices will<br>show all counters unchanged during time).<br><br>Sample use through VTY:<br>"""<br>OsmoTRX> show rate-counters<br>osmo-trx statistics 0:<br>   device:rx_underruns:          0 (0/s 0/m 0/h 0/d) Number of Rx underruns<br>    device:rx_overruns:          0 (0/s 0/m 0/h 0/d) Number of Rx overruns<br>   device:tx_underruns:          0 (0/s 0/m 0/h 0/d) Number of Tx underruns<br> device:rx_drop_events:          4 (0/s 2/m 3/h 0/d) Number of times Rx samples were dropped by HW<br>device:rx_drop_samples:        513 (0/s 196/m 425/h 0/d) Number of Rx samples dropped by HW<br>"""<br><br>Change-Id: I78b158141697e5714d04db8b9ccc96f31f34f439<br>---<br>M CommonLibs/Makefile.am<br>M CommonLibs/osmo_signal.h<br>A CommonLibs/trx_rate_ctr.cpp<br>A CommonLibs/trx_rate_ctr.h<br>M Transceiver52M/device/common/radioDevice.h<br>M Transceiver52M/device/lms/LMSDevice.cpp<br>M Transceiver52M/device/lms/LMSDevice.h<br>M Transceiver52M/osmo-trx.cpp<br>8 files changed, 262 insertions(+), 37 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-trx refs/changes/67/14167/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/CommonLibs/Makefile.am b/CommonLibs/Makefile.am</span><br><span>index 83bd0c0..22572e1 100644</span><br><span>--- a/CommonLibs/Makefile.am</span><br><span>+++ b/CommonLibs/Makefile.am</span><br><span>@@ -35,6 +35,7 @@</span><br><span>    Timeval.cpp \</span><br><span>        Logger.cpp \</span><br><span>         Utils.cpp \</span><br><span style="color: hsl(120, 100%, 40%);">+   trx_rate_ctr.cpp \</span><br><span>   trx_vty.c \</span><br><span>  debug.c</span><br><span> libcommon_la_LIBADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOCTRL_LIBS) $(LIBOSMOVTY_LIBS)</span><br><span>@@ -50,6 +51,7 @@</span><br><span>      Vector.h \</span><br><span>   Logger.h \</span><br><span>   Utils.h \</span><br><span style="color: hsl(120, 100%, 40%);">+     trx_rate_ctr.h \</span><br><span>     trx_vty.h \</span><br><span>  debug.h \</span><br><span>    osmo_signal.h \</span><br><span>diff --git a/CommonLibs/osmo_signal.h b/CommonLibs/osmo_signal.h</span><br><span>index 00b8097..2bbde03 100644</span><br><span>--- a/CommonLibs/osmo_signal.h</span><br><span>+++ b/CommonLibs/osmo_signal.h</span><br><span>@@ -27,9 +27,28 @@</span><br><span> /* Signalling subsystems */</span><br><span> enum signal_subsystems {</span><br><span>         SS_TRANSC,</span><br><span style="color: hsl(120, 100%, 40%);">+    SS_DEVICE</span><br><span> };</span><br><span> </span><br><span> /* SS_TRANSC signals */</span><br><span> enum SS_TRANSC {</span><br><span>   S_TRANSC_STOP_REQUIRED, /* Transceiver fatal error, it should be stopped */</span><br><span> };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* SS_DEVICE signals */</span><br><span style="color: hsl(120, 100%, 40%);">+enum SS_DEVICE {</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Device internal counters changed. Counters are provided as cb data</span><br><span style="color: hsl(120, 100%, 40%);">+    (struct device_counters). Must be sent with PTHREAD_CANCEL_DISABLE</span><br><span style="color: hsl(120, 100%, 40%);">+    to avoid deadlocks in case osmo-trx process is asked to exit. */</span><br><span style="color: hsl(120, 100%, 40%);">+   S_DEVICE_COUNTER_CHANGE,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* signal cb for signal <SS_DEVICE,S_DEVICE_COUNTER_CHANGE> */</span><br><span style="color: hsl(120, 100%, 40%);">+struct device_counters {</span><br><span style="color: hsl(120, 100%, 40%);">+        size_t chan;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint32_t rx_underruns;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint32_t rx_overruns;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t tx_underruns;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint32_t rx_dropped_events;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint32_t rx_dropped_samples;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span>diff --git a/CommonLibs/trx_rate_ctr.cpp b/CommonLibs/trx_rate_ctr.cpp</span><br><span>new file mode 100644</span><br><span>index 0000000..c9c336b</span><br><span>--- /dev/null</span><br><span>+++ b/CommonLibs/trx_rate_ctr.cpp</span><br><span>@@ -0,0 +1,179 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2019 sysmocom - s.f.m.c. GmbH</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Pau Espin Pedrol <pespin@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 2 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * rate_ctr API uses several osmocom select loop features, and as a result,</span><br><span style="color: hsl(120, 100%, 40%);">+ * calls to it must be done through the main thread (the one running the osmocom</span><br><span style="color: hsl(120, 100%, 40%);">+ * loop in osmo-trx).</span><br><span style="color: hsl(120, 100%, 40%);">+ * Since read/write from/to SDR is done in separate threads (even read and write</span><br><span style="color: hsl(120, 100%, 40%);">+ * each use a different thread), we must use some sort of message passing system</span><br><span style="color: hsl(120, 100%, 40%);">+ * between main thread feeding rate_ctr structures and the Rx/Tx threads</span><br><span style="color: hsl(120, 100%, 40%);">+ * generating the events.</span><br><span style="color: hsl(120, 100%, 40%);">+ * The idea is that upon read/write issues, lower layers (SDR APIs) provide us with</span><br><span style="color: hsl(120, 100%, 40%);">+ * underrun/overrun/droppedPackets information, and in that case we pass that up</span><br><span style="color: hsl(120, 100%, 40%);">+ * the stack through signal <SS_DEVICE,S_DEVICE_COUNTER_CHANGE> with signal_cb</span><br><span style="color: hsl(120, 100%, 40%);">+ * being a pointer to a "struct device_counters" structure, which contains</span><br><span style="color: hsl(120, 100%, 40%);">+ * device (implementation agnostic) statful counters for different kind of</span><br><span style="color: hsl(120, 100%, 40%);">+ * statistics.</span><br><span style="color: hsl(120, 100%, 40%);">+ * That signal is processed here in device_sig_cb, where a copy of the "struct</span><br><span style="color: hsl(120, 100%, 40%);">+ * device_counters" structure is held and the main thread is instructed through</span><br><span style="color: hsl(120, 100%, 40%);">+ * a timerfd to update rate_ctr APIs against this copy. All this is done inside</span><br><span style="color: hsl(120, 100%, 40%);">+ * a mutex to avoid different race conditons (between Rx andTx threads, and</span><br><span style="color: hsl(120, 100%, 40%);">+ * between Rx/Tx and main thread). For the same reason, callers of signal</span><br><span style="color: hsl(120, 100%, 40%);">+ * <SS_DEVICE,S_DEVICE_COUNTER_CHANGE> (device_sig_cb), that is Rx/Tx threads,</span><br><span style="color: hsl(120, 100%, 40%);">+ * must do so with PTHREAD_CANCEL_DISABLE, in order to avoid possible deadlocks</span><br><span style="color: hsl(120, 100%, 40%);">+ * in case the main thread decides to cancel other threads due to a shutdown</span><br><span style="color: hsl(120, 100%, 40%);">+ * operation (fi SIGKILL received)</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <inttypes.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <netinet/in.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <arpa/inet.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" {</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/rate_ctr.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/stats.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "osmo_signal.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "trx_vty.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "trx_rate_ctr.h"</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+#include "Threads.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "Logger.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Used in ctrs_pending, when set it means that channel slot contains unused</span><br><span style="color: hsl(120, 100%, 40%);">+   (non-pending) counter data */</span><br><span style="color: hsl(120, 100%, 40%);">+#define PENDING_CHAN_NONE ((uint32_t)-1)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct rate_ctr_group** rate_ctrs;</span><br><span style="color: hsl(120, 100%, 40%);">+struct device_counters* ctrs_pending;</span><br><span style="color: hsl(120, 100%, 40%);">+static size_t chan_len;</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_fd rate_ctr_timerfd;</span><br><span style="color: hsl(120, 100%, 40%);">+Mutex rate_ctr_mutex;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum {</span><br><span style="color: hsl(120, 100%, 40%);">+    TRX_CTR_RX_UNDERRUNS,</span><br><span style="color: hsl(120, 100%, 40%);">+ TRX_CTR_RX_OVERRUNS,</span><br><span style="color: hsl(120, 100%, 40%);">+  TRX_CTR_TX_UNDERRUNS,</span><br><span style="color: hsl(120, 100%, 40%);">+ TRX_CTR_RX_DROP_EV,</span><br><span style="color: hsl(120, 100%, 40%);">+   TRX_CTR_RX_DROP_SMPL,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct rate_ctr_desc trx_chan_ctr_desc[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        [TRX_CTR_RX_UNDERRUNS]          = { "device:rx_underruns",    "Number of Rx underruns" },</span><br><span style="color: hsl(120, 100%, 40%);">+ [TRX_CTR_RX_OVERRUNS]           = { "device:rx_overruns",     "Number of Rx overruns" },</span><br><span style="color: hsl(120, 100%, 40%);">+  [TRX_CTR_TX_UNDERRUNS]          = { "device:tx_underruns",    "Number of Tx underruns" },</span><br><span style="color: hsl(120, 100%, 40%);">+ [TRX_CTR_RX_DROP_EV]            = { "device:rx_drop_events",  "Number of times Rx samples were dropped by HW" },</span><br><span style="color: hsl(120, 100%, 40%);">+  [TRX_CTR_RX_DROP_SMPL]          = { "device:rx_drop_samples", "Number of Rx samples dropped by HW" },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct rate_ctr_group_desc trx_chan_ctr_group_desc = {</span><br><span style="color: hsl(120, 100%, 40%);">+  .group_name_prefix              = "trx:chan",</span><br><span style="color: hsl(120, 100%, 40%);">+       .group_description              = "osmo-trx statistics",</span><br><span style="color: hsl(120, 100%, 40%);">+    .class_id                       = OSMO_STATS_CLASS_GLOBAL,</span><br><span style="color: hsl(120, 100%, 40%);">+    .num_ctr                        = ARRAY_SIZE(trx_chan_ctr_desc),</span><br><span style="color: hsl(120, 100%, 40%);">+      .ctr_desc                       = trx_chan_ctr_desc,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int rate_ctr_timerfd_cb(struct osmo_fd *ofd, unsigned int what) {</span><br><span style="color: hsl(120, 100%, 40%);">+  size_t chan;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct rate_ctr *ctr;</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGC(DMAIN, NOTICE) << "Main thread is updating counters";</span><br><span style="color: hsl(120, 100%, 40%);">+    rate_ctr_mutex.lock();</span><br><span style="color: hsl(120, 100%, 40%);">+        for (chan = 0; chan < chan_len; chan++) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (ctrs_pending[chan].chan == PENDING_CHAN_NONE)</span><br><span style="color: hsl(120, 100%, 40%);">+                     continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGCHAN(chan, DMAIN, INFO) << "rate_ctr update";</span><br><span style="color: hsl(120, 100%, 40%);">+              ctr = &rate_ctrs[chan]->ctr[TRX_CTR_RX_UNDERRUNS];</span><br><span style="color: hsl(120, 100%, 40%);">+             rate_ctr_add(ctr, ctrs_pending[chan].rx_underruns - ctr->current);</span><br><span style="color: hsl(120, 100%, 40%);">+         ctr = &rate_ctrs[chan]->ctr[TRX_CTR_RX_OVERRUNS];</span><br><span style="color: hsl(120, 100%, 40%);">+              rate_ctr_add(ctr, ctrs_pending[chan].rx_overruns - ctr->current);</span><br><span style="color: hsl(120, 100%, 40%);">+          ctr = &rate_ctrs[chan]->ctr[TRX_CTR_TX_UNDERRUNS];</span><br><span style="color: hsl(120, 100%, 40%);">+             rate_ctr_add(ctr, ctrs_pending[chan].tx_underruns - ctr->current);</span><br><span style="color: hsl(120, 100%, 40%);">+         ctr = &rate_ctrs[chan]->ctr[TRX_CTR_RX_DROP_EV];</span><br><span style="color: hsl(120, 100%, 40%);">+               rate_ctr_add(ctr, ctrs_pending[chan].rx_dropped_events - ctr->current);</span><br><span style="color: hsl(120, 100%, 40%);">+            ctr = &rate_ctrs[chan]->ctr[TRX_CTR_RX_DROP_SMPL];</span><br><span style="color: hsl(120, 100%, 40%);">+             rate_ctr_add(ctr, ctrs_pending[chan].rx_dropped_samples - ctr->current);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         /* Mark as done */</span><br><span style="color: hsl(120, 100%, 40%);">+            ctrs_pending[chan].chan = PENDING_CHAN_NONE;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (osmo_timerfd_disable(&rate_ctr_timerfd) < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGC(DMAIN, ERROR) << "Failed to disable timerfd";</span><br><span style="color: hsl(120, 100%, 40%);">+    rate_ctr_mutex.unlock();</span><br><span style="color: hsl(120, 100%, 40%);">+      return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Callback function to be called every time we receive a signal from DEVICE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int device_sig_cb(unsigned int subsys, unsigned int signal,</span><br><span style="color: hsl(120, 100%, 40%);">+                    void *handler_data, void *signal_data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct device_counters *ctr;</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Delay sched around 20 ms, in case we receive several calls from several</span><br><span style="color: hsl(120, 100%, 40%);">+     * channels batched */</span><br><span style="color: hsl(120, 100%, 40%);">+        struct timespec next_sched = {.tv_sec = 0, .tv_nsec = 20*1000*1000};</span><br><span style="color: hsl(120, 100%, 40%);">+  /* no automatic re-trigger */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct timespec intv_sched = {.tv_sec = 0, .tv_nsec = 0};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (signal) {</span><br><span style="color: hsl(120, 100%, 40%);">+     case S_DEVICE_COUNTER_CHANGE:</span><br><span style="color: hsl(120, 100%, 40%);">+         ctr = (struct device_counters *)signal_data;</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGCHAN(ctr->chan, DMAIN, NOTICE) << "Received counter change from radioDevice";</span><br><span style="color: hsl(120, 100%, 40%);">+           rate_ctr_mutex.lock();</span><br><span style="color: hsl(120, 100%, 40%);">+                ctrs_pending[ctr->chan] = *ctr;</span><br><span style="color: hsl(120, 100%, 40%);">+            if (osmo_timerfd_schedule(&rate_ctr_timerfd, &next_sched, &intv_sched) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  LOGC(DMAIN, ERROR) << "Failed to schedule timerfd: " << errno << " = "<< strerror(errno);</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+             rate_ctr_mutex.unlock();</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Init rate_ctr subsystem. Expected to be called during process start by main thread */</span><br><span style="color: hsl(120, 100%, 40%);">+void trx_rate_ctr_init(void *ctx, struct trx_ctx* trx_ctx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       chan_len = trx_ctx->cfg.num_chans;</span><br><span style="color: hsl(120, 100%, 40%);">+ ctrs_pending = (struct device_counters*) talloc_zero_size(ctx, chan_len * sizeof(struct device_counters));</span><br><span style="color: hsl(120, 100%, 40%);">+    rate_ctrs = (struct rate_ctr_group**) talloc_zero_size(ctx, chan_len * sizeof(struct rate_ctr_group*));         size_t  i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  for (i = 0; i < chan_len; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ctrs_pending[i].chan = PENDING_CHAN_NONE;</span><br><span style="color: hsl(120, 100%, 40%);">+             rate_ctrs[i] = rate_ctr_group_alloc(ctx, &trx_chan_ctr_group_desc, i);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!rate_ctrs[i]) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  LOGCHAN(i, DMAIN, ERROR) << "Failed to allocate rate ctr";</span><br><span style="color: hsl(120, 100%, 40%);">+                    exit(1);</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     rate_ctr_timerfd.fd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (osmo_timerfd_setup(&rate_ctr_timerfd, rate_ctr_timerfd_cb, NULL) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGC(DMAIN, ERROR) << "Failed to setup timerfd";</span><br><span style="color: hsl(120, 100%, 40%);">+              exit(1);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_signal_register_handler(SS_DEVICE, device_sig_cb, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/CommonLibs/trx_rate_ctr.h b/CommonLibs/trx_rate_ctr.h</span><br><span>new file mode 100644</span><br><span>index 0000000..48131e7</span><br><span>--- /dev/null</span><br><span>+++ b/CommonLibs/trx_rate_ctr.h</span><br><span>@@ -0,0 +1,4 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct trx_ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+void trx_rate_ctr_init(void *ctx, struct trx_ctx* trx_ctx);</span><br><span>diff --git a/Transceiver52M/device/common/radioDevice.h b/Transceiver52M/device/common/radioDevice.h</span><br><span>index 30e0f43..cd378a8 100644</span><br><span>--- a/Transceiver52M/device/common/radioDevice.h</span><br><span>+++ b/Transceiver52M/device/common/radioDevice.h</span><br><span>@@ -23,6 +23,7 @@</span><br><span> </span><br><span> extern "C" {</span><br><span> #include "config_defs.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "osmo_signal.h"</span><br><span> }</span><br><span> </span><br><span> #ifdef HAVE_CONFIG_H</span><br><span>@@ -168,13 +169,20 @@</span><br><span>   size_t chans;</span><br><span>   double lo_offset;</span><br><span>   std::vector<std::string> tx_paths, rx_paths;</span><br><span style="color: hsl(120, 100%, 40%);">+  std::vector<struct device_counters> m_ctr;</span><br><span> </span><br><span>   RadioDevice(size_t tx_sps, size_t rx_sps, InterfaceType type, size_t chans, double offset,</span><br><span>               const std::vector<std::string>& tx_paths,</span><br><span>               const std::vector<std::string>& rx_paths):</span><br><span>               tx_sps(tx_sps), rx_sps(rx_sps), iface(type), chans(chans), lo_offset(offset),</span><br><span>                tx_paths(tx_paths), rx_paths(rx_paths)</span><br><span style="color: hsl(0, 100%, 40%);">-  { }</span><br><span style="color: hsl(120, 100%, 40%);">+   {</span><br><span style="color: hsl(120, 100%, 40%);">+             m_ctr.resize(chans);</span><br><span style="color: hsl(120, 100%, 40%);">+          for (size_t i = 0; i < chans; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       memset(&m_ctr[i], 0, sizeof(m_ctr[i]));</span><br><span style="color: hsl(120, 100%, 40%);">+                   m_ctr[i].chan = i;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span> </span><br><span>   bool set_antennas() {</span><br><span>     unsigned int i;</span><br><span>diff --git a/Transceiver52M/device/lms/LMSDevice.cpp b/Transceiver52M/device/lms/LMSDevice.cpp</span><br><span>index a1ca983..866235f 100644</span><br><span>--- a/Transceiver52M/device/lms/LMSDevice.cpp</span><br><span>+++ b/Transceiver52M/device/lms/LMSDevice.cpp</span><br><span>@@ -25,7 +25,10 @@</span><br><span> </span><br><span> #include <lime/LimeSuite.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" {</span><br><span style="color: hsl(120, 100%, 40%);">+#include "osmo_signal.h"</span><br><span> #include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> </span><br><span> #ifdef HAVE_CONFIG_H</span><br><span> #include "config.h"</span><br><span>@@ -53,11 +56,6 @@</span><br><span>         m_lms_stream_rx.resize(chans);</span><br><span>       m_lms_stream_tx.resize(chans);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      m_last_rx_underruns.resize(chans, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-   m_last_rx_overruns.resize(chans, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-    m_last_rx_dropped.resize(chans, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-     m_last_tx_underruns.resize(chans, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>        rx_buffers.resize(chans);</span><br><span> }</span><br><span> </span><br><span>@@ -580,32 +578,46 @@</span><br><span> void LMSDevice::update_stream_stats(size_t chan, bool * underrun, bool * overrun)</span><br><span> {</span><br><span>         lms_stream_status_t status;</span><br><span style="color: hsl(0, 100%, 40%);">-     if (LMS_GetStreamStatus(&m_lms_stream_rx[chan], &status) == 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                if (status.underrun > m_last_rx_underruns[chan]) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   *underrun = true;</span><br><span style="color: hsl(0, 100%, 40%);">-                       LOGCHAN(chan, DDEV, ERROR) << "recv Underrun! ("</span><br><span style="color: hsl(0, 100%, 40%);">-                                                   << m_last_rx_underruns[chan] << " -> "</span><br><span style="color: hsl(0, 100%, 40%);">-                                                 << status.underrun << ")";</span><br><span style="color: hsl(0, 100%, 40%);">-             }</span><br><span style="color: hsl(0, 100%, 40%);">-               m_last_rx_underruns[chan] = status.underrun;</span><br><span style="color: hsl(120, 100%, 40%);">+  bool changed = false;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-               if (status.overrun > m_last_rx_overruns[chan]) {</span><br><span style="color: hsl(0, 100%, 40%);">-                     *overrun = true;</span><br><span style="color: hsl(0, 100%, 40%);">-                        LOGCHAN(chan, DDEV, ERROR) << "recv Overrun! ("</span><br><span style="color: hsl(0, 100%, 40%);">-                                            << m_last_rx_overruns[chan] << " -> "</span><br><span style="color: hsl(0, 100%, 40%);">-                                                  << status.overrun << ")";</span><br><span style="color: hsl(0, 100%, 40%);">-              }</span><br><span style="color: hsl(0, 100%, 40%);">-               m_last_rx_overruns[chan] = status.overrun;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-              if (status.droppedPackets) {</span><br><span style="color: hsl(0, 100%, 40%);">-                    LOGCHAN(chan, DDEV, ERROR) << "recv Dropped packets by HW! ("</span><br><span style="color: hsl(0, 100%, 40%);">-                                              << m_last_rx_dropped[chan] << " -> "</span><br><span style="color: hsl(0, 100%, 40%);">-                                                   << m_last_rx_dropped[chan] +</span><br><span style="color: hsl(0, 100%, 40%);">-                                                 status.droppedPackets</span><br><span style="color: hsl(0, 100%, 40%);">-                                                << ")";</span><br><span style="color: hsl(0, 100%, 40%);">-              }</span><br><span style="color: hsl(0, 100%, 40%);">-               m_last_rx_dropped[chan] += status.droppedPackets;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (LMS_GetStreamStatus(&m_lms_stream_rx[chan], &status) != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGCHAN(chan, DDEV, ERROR) << "LMS_GetStreamStatus failed";</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</span><br><span>      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (status.underrun > m_ctr[chan].rx_underruns) {</span><br><span style="color: hsl(120, 100%, 40%);">+          changed = true;</span><br><span style="color: hsl(120, 100%, 40%);">+               *underrun = true;</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGCHAN(chan, DDEV, ERROR) << "recv Underrun! ("</span><br><span style="color: hsl(120, 100%, 40%);">+                                         << m_ctr[chan].rx_underruns << " -> "</span><br><span style="color: hsl(120, 100%, 40%);">+                                        << status.underrun << ")";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     m_ctr[chan].rx_underruns = status.underrun;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (status.overrun > m_ctr[chan].rx_overruns) {</span><br><span style="color: hsl(120, 100%, 40%);">+            changed = true;</span><br><span style="color: hsl(120, 100%, 40%);">+               *overrun = true;</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGCHAN(chan, DDEV, ERROR) << "recv Overrun! ("</span><br><span style="color: hsl(120, 100%, 40%);">+                                          << m_ctr[chan].rx_overruns << " -> "</span><br><span style="color: hsl(120, 100%, 40%);">+                                         << status.overrun << ")";</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     m_ctr[chan].rx_overruns = status.overrun;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (status.droppedPackets) {</span><br><span style="color: hsl(120, 100%, 40%);">+          changed = true;</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGCHAN(chan, DDEV, ERROR) << "recv Dropped packets by HW! ("</span><br><span style="color: hsl(120, 100%, 40%);">+                                    << m_ctr[chan].rx_dropped_samples << " -> "</span><br><span style="color: hsl(120, 100%, 40%);">+                                          << m_ctr[chan].rx_dropped_samples +</span><br><span style="color: hsl(120, 100%, 40%);">+                                        status.droppedPackets</span><br><span style="color: hsl(120, 100%, 40%);">+                                      << ")";</span><br><span style="color: hsl(120, 100%, 40%);">+            m_ctr[chan].rx_dropped_events++;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     m_ctr[chan].rx_dropped_samples += status.droppedPackets;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (changed)</span><br><span style="color: hsl(120, 100%, 40%);">+          osmo_signal_dispatch(SS_DEVICE, S_DEVICE_COUNTER_CHANGE, &m_ctr[chan]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> }</span><br><span> </span><br><span> // NOTE: Assumes sequential reads</span><br><span>@@ -719,9 +731,12 @@</span><br><span>           }</span><br><span> </span><br><span>                if (LMS_GetStreamStatus(&m_lms_stream_tx[i], &status) == 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   if (status.underrun > m_last_tx_underruns[i])</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (status.underrun > m_ctr[i].tx_underruns) {</span><br><span>                            *underrun = true;</span><br><span style="color: hsl(0, 100%, 40%);">-                       m_last_tx_underruns[i] = status.underrun;</span><br><span style="color: hsl(120, 100%, 40%);">+                             m_ctr[i].tx_underruns = status.underrun;</span><br><span style="color: hsl(120, 100%, 40%);">+                              osmo_signal_dispatch(SS_DEVICE, S_DEVICE_COUNTER_CHANGE, &m_ctr[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+                      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>          }</span><br><span>            thread_enable_cancel(true);</span><br><span>  }</span><br><span>diff --git a/Transceiver52M/device/lms/LMSDevice.h b/Transceiver52M/device/lms/LMSDevice.h</span><br><span>index 2828578..8b5fe93 100644</span><br><span>--- a/Transceiver52M/device/lms/LMSDevice.h</span><br><span>+++ b/Transceiver52M/device/lms/LMSDevice.h</span><br><span>@@ -49,11 +49,6 @@</span><br><span>      std::vector<lms_stream_t> m_lms_stream_rx;</span><br><span>     std::vector<lms_stream_t> m_lms_stream_tx;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    std::vector<uint32_t> m_last_rx_underruns;</span><br><span style="color: hsl(0, 100%, 40%);">-        std::vector<uint32_t> m_last_rx_overruns;</span><br><span style="color: hsl(0, 100%, 40%);">- std::vector<uint32_t> m_last_rx_dropped;</span><br><span style="color: hsl(0, 100%, 40%);">-  std::vector<uint32_t> m_last_tx_underruns;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>     std::vector<smpl_buf *> rx_buffers;</span><br><span> </span><br><span>        double actualSampleRate;        ///< the actual USRP sampling rate</span><br><span>diff --git a/Transceiver52M/osmo-trx.cpp b/Transceiver52M/osmo-trx.cpp</span><br><span>index 8c592aa..a79c26e 100644</span><br><span>--- a/Transceiver52M/osmo-trx.cpp</span><br><span>+++ b/Transceiver52M/osmo-trx.cpp</span><br><span>@@ -59,6 +59,7 @@</span><br><span> #include "trx_vty.h"</span><br><span> #include "debug.h"</span><br><span> #include "osmo_signal.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "trx_rate_ctr.h"</span><br><span> }</span><br><span> </span><br><span> #define DEFAULT_CONFIG_FILE "osmo-trx.cfg"</span><br><span>@@ -626,6 +627,8 @@</span><br><span>                       return EXIT_FAILURE;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ trx_rate_ctr_init(tall_trx_ctx, g_trx_ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>        srandom(time(NULL));</span><br><span> </span><br><span>     if(trx_start(g_trx_ctx) < 0)</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/14167">change 14167</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/14167"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-trx </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I78b158141697e5714d04db8b9ccc96f31f34f439 </div>
<div style="display:none"> Gerrit-Change-Number: 14167 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Pau Espin Pedrol <pespin@sysmocom.de> </div>