bssgp: Use measured leak rate for flow control

The leak rate sent to the SGSN does not reflect the current CS level,
lost frames, and control message overhead. So the SGSN cannot do
proper queue control under non-optimal conditions.

This commit computes the leak rate for the last flow control interval
by computing the maximum theoretical leak rate and basically
substracting control blocks, nacked blocks, and reduced block sizes
due to CS downgrade. By using this approach, the value will by more
stable on low load, where the value will tend to be near the value
derived from the configuration. On full load the transmitted value is
completely derived from the measurements.

Note that the MS default values are no adapted to the adapted BVC
leak rate, since a single MS which has a lower link quality would
otherwise be reducing the rate of another MS with good radio
conditions, which would not make much sense if they did not share any
PDCH.

Sponsored-by: On-Waves ehf
This commit is contained in:
Jacob Erlbeck 2015-09-07 18:49:00 +02:00
parent 7c8d39a67b
commit 2db0f08e08
6 changed files with 106 additions and 6 deletions

View File

@ -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;
@ -629,6 +655,26 @@ int gprs_bssgp_tx_fc_bvc(void)
ms_bucket_size = bts->fc_ms_bucket_size;
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)
{

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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());

View File

@ -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