aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gprs_bssgp_pcu.cpp57
-rw-r--r--src/gprs_bssgp_pcu.h5
-rw-r--r--src/gprs_rlcmac_sched.cpp3
-rw-r--r--src/tbf.h9
-rw-r--r--src/tbf_dl.cpp36
-rw-r--r--tests/tbf/TbfTest.err2
6 files changed, 106 insertions, 6 deletions
diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp
index 7f50e17d..cce184d5 100644
--- a/src/gprs_bssgp_pcu.cpp
+++ b/src/gprs_bssgp_pcu.cpp
@@ -591,6 +591,32 @@ static uint32_t get_and_reset_avg_queue_delay(void)
return avg_delay_ms;
}
+static int get_and_reset_measured_leak_rate(int *usage_by_1000, unsigned num_pdch)
+{
+ int rate; /* byte per second */
+
+ if (the_pcu.queue_frames_sent == 0)
+ return -1;
+
+ if (the_pcu.queue_frames_recv == 0)
+ return -1;
+
+ *usage_by_1000 = the_pcu.queue_frames_recv * 1000 /
+ the_pcu.queue_frames_sent;
+
+ /* 20ms/num_pdch is the average RLC block duration, so the rate is
+ * calculated as:
+ * rate = bytes_recv / (block_dur * block_count) */
+ rate = the_pcu.queue_bytes_recv * 1000 * num_pdch /
+ (20 * the_pcu.queue_frames_recv);
+
+ the_pcu.queue_frames_sent = 0;
+ the_pcu.queue_bytes_recv = 0;
+ the_pcu.queue_frames_recv = 0;
+
+ return rate;
+}
+
int gprs_bssgp_tx_fc_bvc(void)
{
struct gprs_rlcmac_bts *bts;
@@ -630,6 +656,26 @@ int gprs_bssgp_tx_fc_bvc(void)
ms_leak_rate = bts->fc_ms_leak_rate;
if (leak_rate == 0) {
+ int meas_rate;
+ int usage; /* in 0..1000 */
+
+ if (num_pdch < 0)
+ num_pdch = count_pdch(bts);
+
+ meas_rate = get_and_reset_measured_leak_rate(&usage, num_pdch);
+ if (meas_rate > 0) {
+ leak_rate = gprs_bssgp_max_leak_rate(max_cs_dl, num_pdch);
+ leak_rate =
+ (meas_rate * usage + leak_rate * (1000 - usage)) /
+ 1000;
+ LOGP(DBSSGP, LOGL_DEBUG,
+ "Estimated BVC leak rate = %d "
+ "(measured %d, usage %d%%)\n",
+ leak_rate, meas_rate, usage/10);
+ }
+ }
+
+ if (leak_rate == 0) {
if (num_pdch < 0)
num_pdch = count_pdch(bts);
@@ -853,6 +899,17 @@ struct bssgp_bvc_ctx *gprs_bssgp_pcu_current_bctx(void)
return the_pcu.bctx;
}
+void gprs_bssgp_update_frames_sent()
+{
+ the_pcu.queue_frames_sent += 1;
+}
+
+void gprs_bssgp_update_bytes_received(unsigned bytes_recv, unsigned frames_recv)
+{
+ the_pcu.queue_bytes_recv += bytes_recv;
+ the_pcu.queue_frames_recv += frames_recv;
+}
+
void gprs_bssgp_update_queue_delay(const struct timeval *tv_recv,
const struct timeval *tv_now)
{
diff --git a/src/gprs_bssgp_pcu.h b/src/gprs_bssgp_pcu.h
index e0b83121..bb449034 100644
--- a/src/gprs_bssgp_pcu.h
+++ b/src/gprs_bssgp_pcu.h
@@ -62,6 +62,9 @@ struct gprs_bssgp_pcu {
struct timeval queue_delay_sum;
unsigned queue_delay_count;
uint8_t fc_tag;
+ unsigned queue_frames_sent;
+ unsigned queue_bytes_recv;
+ unsigned queue_frames_recv;
/** callbacks below */
@@ -86,5 +89,7 @@ struct bssgp_bvc_ctx *gprs_bssgp_pcu_current_bctx(void);
void gprs_bssgp_update_queue_delay(const struct timeval *tv_recv,
const struct timeval *tv_now);
+void gprs_bssgp_update_frames_sent();
+void gprs_bssgp_update_bytes_received(unsigned bytes_recv, unsigned frames_recv);
#endif // GPRS_BSSGP_PCU_H
diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp
index dedea269..ac1991df 100644
--- a/src/gprs_rlcmac_sched.cpp
+++ b/src/gprs_rlcmac_sched.cpp
@@ -332,6 +332,9 @@ int gprs_rlcmac_rcv_rts_block(struct gprs_rlcmac_bts *bts,
/* set USF */
msg->data[0] = (msg->data[0] & 0xf8) | usf;
+ /* Used to measure the leak rate, count all blocks */
+ gprs_bssgp_update_frames_sent();
+
/* send PDTCH/PACCH to L1 */
pcu_l1if_tx_pdtch(msg, trx, ts, arfcn, fn, block_nr);
diff --git a/src/tbf.h b/src/tbf.h
index 3619910e..5b83bed1 100644
--- a/src/tbf.h
+++ b/src/tbf.h
@@ -371,6 +371,13 @@ struct gprs_rlcmac_dl_tbf : public gprs_rlcmac_tbf {
} m_bw;
protected:
+ struct ana_result {
+ unsigned received_packets;
+ unsigned lost_packets;
+ unsigned received_bytes;
+ unsigned lost_bytes;
+ };
+
struct msgb *create_new_bsn(const uint32_t fn, const uint8_t ts);
struct msgb *create_dl_acked_block(const uint32_t fn, const uint8_t ts,
const int index);
@@ -379,7 +386,7 @@ protected:
bool dl_window_stalled() const;
void reuse_tbf();
void start_llc_timer();
- int analyse_errors(char *show_rbb, uint8_t ssn);
+ int analyse_errors(char *show_rbb, uint8_t ssn, ana_result *res);
void schedule_next_frame();
struct osmo_timer_list m_llc_timer;
diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp
index aabe8e3e..64fbef4e 100644
--- a/src/tbf_dl.cpp
+++ b/src/tbf_dl.cpp
@@ -712,7 +712,8 @@ static uint16_t bitnum_to_bsn(int bitnum, uint16_t ssn, uint16_t mod_sns)
return (ssn - 1 - bitnum) & mod_sns;
}
-int gprs_rlcmac_dl_tbf::analyse_errors(char *show_rbb, uint8_t ssn)
+int gprs_rlcmac_dl_tbf::analyse_errors(char *show_rbb, uint8_t ssn,
+ ana_result *res)
{
gprs_rlc_data *rlc_data;
uint16_t lost = 0, received = 0, skipped = 0;
@@ -720,9 +721,13 @@ int gprs_rlcmac_dl_tbf::analyse_errors(char *show_rbb, uint8_t ssn)
memset(info, '.', sizeof(info));
info[64] = 0;
uint16_t bsn = 0;
+ unsigned received_bytes = 0, lost_bytes = 0;
+ unsigned received_packets = 0, lost_packets = 0;
/* SSN - 1 is in range V(A)..V(S)-1 */
for (int bitpos = 0; bitpos < m_window.ws(); bitpos++) {
+ bool is_received = show_rbb[m_window.ws() - 1 - bitpos] == 'R';
+
bsn = bitnum_to_bsn(bitpos, ssn, m_window.mod_sns());
if (bsn == ((m_window.v_a() - 1) & m_window.mod_sns())) {
@@ -736,6 +741,17 @@ int gprs_rlcmac_dl_tbf::analyse_errors(char *show_rbb, uint8_t ssn)
continue;
}
+ /* Get general statistics */
+ if (is_received && !m_window.m_v_b.is_acked(bsn)) {
+ received_packets += 1;
+ received_bytes += rlc_data->len;
+ } else if (!is_received && !m_window.m_v_b.is_nacked(bsn)) {
+ lost_packets += 1;
+ lost_bytes += rlc_data->len;
+ }
+
+ /* Get statistics for current CS */
+
if (rlc_data->cs != current_cs()) {
/* This block has already been encoded with a different
* CS, so it doesn't help us to decide, whether the
@@ -745,7 +761,7 @@ int gprs_rlcmac_dl_tbf::analyse_errors(char *show_rbb, uint8_t ssn)
continue;
}
- if (show_rbb[m_window.ws() - 1 - bitpos] == 'R') {
+ if (is_received) {
if (!m_window.m_v_b.is_acked(bsn)) {
received += 1;
info[bitpos] = 'R';
@@ -763,6 +779,11 @@ int gprs_rlcmac_dl_tbf::analyse_errors(char *show_rbb, uint8_t ssn)
name(), m_window.v_a(), m_window.v_s(), lost, received,
skipped, bsn, info);
+ res->received_packets = received_packets;
+ res->lost_packets = lost_packets;
+ res->received_bytes = received_bytes;
+ res->lost_bytes = lost_bytes;
+
if (lost + received <= 1)
return -1;
@@ -778,6 +799,7 @@ int gprs_rlcmac_dl_tbf::update_window(const uint8_t ssn, const uint8_t *rbb)
char show_v_b[RLC_MAX_SNS + 1];
const uint16_t mod_sns = m_window.mod_sns();
int error_rate;
+ struct ana_result ana_res;
Decoding::extract_rbb(rbb, show_rbb);
/* show received array in debug (bit 64..1) */
@@ -800,10 +822,10 @@ int gprs_rlcmac_dl_tbf::update_window(const uint8_t ssn, const uint8_t *rbb)
return 1; /* indicate to free TBF */
}
- if (bts_data()->cs_adj_enabled && ms()) {
- error_rate = analyse_errors(show_rbb, ssn);
+ error_rate = analyse_errors(show_rbb, ssn, &ana_res);
+
+ if (bts_data()->cs_adj_enabled && ms())
ms()->update_error_rate(this, error_rate);
- }
m_window.update(bts, show_rbb, ssn,
&lost, &received);
@@ -811,6 +833,10 @@ int gprs_rlcmac_dl_tbf::update_window(const uint8_t ssn, const uint8_t *rbb)
/* report lost and received packets */
gprs_rlcmac_received_lost(this, received, lost);
+ /* Used to measure the leak rate */
+ gprs_bssgp_update_bytes_received(ana_res.received_bytes,
+ ana_res.received_packets + ana_res.lost_packets);
+
/* raise V(A), if possible */
m_window.raise(m_window.move_window());
diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err
index 70b5c570..2869ffd0 100644
--- a/tests/tbf/TbfTest.err
+++ b/tests/tbf/TbfTest.err
@@ -360,6 +360,7 @@ Polling is already sheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW), so
Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=91 block=9 data=07 00 28 0a 41 c6 c7 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) downlink acknowledge
- ack: (BSN=85)"RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"(BSN=20) R=ACK I=NACK
+TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) DL analysis, range=0:21, lost=0, recv=21, skipped=0, bsn=127, info='RRRRRRRRRRRRRRRRRRRRR$..........................................'
- got ack for BSN=20
- got ack for BSN=19
- got ack for BSN=18
@@ -395,6 +396,7 @@ Polling is already sheduled for TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW), so
Sending data request: trx=0 ts=4 sapi=5 arfcn=0 fn=95 block=10 data=07 00 2a 4d 43 c0 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) downlink acknowledge
- ack: (BSN=86)"RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"(BSN=21) R=ACK I=NACK
+TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) DL analysis, range=21:22, lost=0, recv=1, skipped=0, bsn=20, info='R$..............................................................'
- got ack for BSN=21
- V(B): (V(A)=22)""(V(S)-1=21) A=Acked N=Nacked U=Unacked X=Resend-Unacked I=Invalid
Scheduling data message at RTS for DL TFI=0 (TRX=0, TS=4) prio=4