Use clock_gettime(CLOCK_MONOTONIC) and timespec everywhere
We should really be using monotonic clock in all places that gettimeofday is used right now. Since clock_gettime() uses timespec, let's move all code to use timespecs instead to avoid having to convert in several places between timespec and timeval. Actually use osmo_clock_gettime() shim everywhere to be able to control the time everywhere from unit tests. Change-Id: Ie265d70f8ffa7dbf7efbef6030505d9fcb5dc338
This commit is contained in:
parent
29aeb901e4
commit
1de6873810
|
@ -662,16 +662,16 @@ static uint32_t compute_bucket_size(struct gprs_rlcmac_bts *bts,
|
|||
|
||||
static uint32_t get_and_reset_avg_queue_delay(void)
|
||||
{
|
||||
struct timeval *delay_sum = &the_pcu.queue_delay_sum;
|
||||
struct timespec *delay_sum = &the_pcu.queue_delay_sum;
|
||||
uint32_t delay_sum_ms = delay_sum->tv_sec * 1000 +
|
||||
delay_sum->tv_usec / 1000000;
|
||||
delay_sum->tv_nsec / 1000000000;
|
||||
uint32_t avg_delay_ms = 0;
|
||||
|
||||
if (the_pcu.queue_delay_count > 0)
|
||||
avg_delay_ms = delay_sum_ms / the_pcu.queue_delay_count;
|
||||
|
||||
/* Reset accumulator */
|
||||
delay_sum->tv_sec = delay_sum->tv_usec = 0;
|
||||
delay_sum->tv_sec = delay_sum->tv_nsec = 0;
|
||||
the_pcu.queue_delay_count = 0;
|
||||
|
||||
return avg_delay_ms;
|
||||
|
@ -1024,14 +1024,14 @@ void gprs_bssgp_update_bytes_received(unsigned bytes_recv, unsigned frames_recv)
|
|||
the_pcu.queue_frames_recv += frames_recv;
|
||||
}
|
||||
|
||||
void gprs_bssgp_update_queue_delay(const struct timeval *tv_recv,
|
||||
const struct timeval *tv_now)
|
||||
void gprs_bssgp_update_queue_delay(const struct timespec *tv_recv,
|
||||
const struct timespec *tv_now)
|
||||
{
|
||||
struct timeval *delay_sum = &the_pcu.queue_delay_sum;
|
||||
struct timeval tv_delay;
|
||||
struct timespec *delay_sum = &the_pcu.queue_delay_sum;
|
||||
struct timespec tv_delay;
|
||||
|
||||
timersub(tv_now, tv_recv, &tv_delay);
|
||||
timeradd(delay_sum, &tv_delay, delay_sum);
|
||||
timespecsub(tv_now, tv_recv, &tv_delay);
|
||||
timespecadd(delay_sum, &tv_delay, delay_sum);
|
||||
|
||||
the_pcu.queue_delay_count += 1;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,8 @@ struct bssgp_bvc_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei);
|
|||
}
|
||||
#include <gprs_debug.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#define QOS_PROFILE 4
|
||||
#define BSSGP_HDR_LEN 53
|
||||
#define NS_HDR_LEN 4
|
||||
|
@ -57,7 +59,7 @@ struct gprs_bssgp_pcu {
|
|||
int bvc_unblocked;
|
||||
|
||||
/* Flow control */
|
||||
struct timeval queue_delay_sum;
|
||||
struct timespec queue_delay_sum;
|
||||
unsigned queue_delay_count;
|
||||
uint8_t fc_tag;
|
||||
unsigned queue_frames_sent;
|
||||
|
@ -87,8 +89,8 @@ void gprs_bssgp_destroy(void);
|
|||
|
||||
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_queue_delay(const struct timespec *tv_recv,
|
||||
const struct timespec *tv_now);
|
||||
void gprs_bssgp_update_frames_sent();
|
||||
void gprs_bssgp_update_bytes_received(unsigned bytes_recv, unsigned frames_recv);
|
||||
|
||||
|
|
|
@ -22,12 +22,13 @@
|
|||
#include "gprs_debug.h"
|
||||
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/timer_compat.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
static void control_law(struct gprs_codel *state, struct timeval *delta)
|
||||
static void control_law(struct gprs_codel *state, struct timespec *delta)
|
||||
{
|
||||
/* 256 / sqrt(x), limited to 255 */
|
||||
static uint8_t inv_sqrt_tab[] = {255,
|
||||
|
@ -57,12 +58,12 @@ static void control_law(struct gprs_codel *state, struct timeval *delta)
|
|||
inv_sqrt = inv_sqrt_tab[state->count];
|
||||
|
||||
/* delta = state->interval / sqrt(count) */
|
||||
delta_usecs = state->interval.tv_sec * 1000000 + state->interval.tv_usec;
|
||||
delta_usecs = state->interval.tv_sec * 1000000 + state->interval.tv_nsec/1000;
|
||||
delta_usecs = delta_usecs * inv_sqrt / 256;
|
||||
|
||||
q = div(delta_usecs, 1000000);
|
||||
delta->tv_sec = q.quot;
|
||||
delta->tv_usec = q.rem;
|
||||
delta->tv_nsec = q.rem * 1000;
|
||||
}
|
||||
|
||||
void gprs_codel_init(struct gprs_codel *state)
|
||||
|
@ -83,12 +84,12 @@ void gprs_codel_set_interval(struct gprs_codel *state, int interval_ms)
|
|||
|
||||
q = div(interval_ms, 1000);
|
||||
state->interval.tv_sec = q.quot;
|
||||
state->interval.tv_usec = q.rem * 1000;
|
||||
state->interval.tv_nsec = q.rem * 1000000;
|
||||
|
||||
/* target ~ 5% of interval */
|
||||
q = div(interval_ms * 13 / 256, 1000);
|
||||
state->target.tv_sec = q.quot;
|
||||
state->target.tv_usec = q.rem * 1000;
|
||||
state->target.tv_nsec = q.rem * 1000000;
|
||||
}
|
||||
|
||||
void gprs_codel_set_maxpacket(struct gprs_codel *state, int maxpacket)
|
||||
|
@ -104,29 +105,29 @@ void gprs_codel_set_maxpacket(struct gprs_codel *state, int maxpacket)
|
|||
* This is an broken up variant of the algorithm being described in
|
||||
* http://queue.acm.org/appendices/codel.html
|
||||
*/
|
||||
int gprs_codel_control(struct gprs_codel *state, const struct timeval *recv,
|
||||
const struct timeval *now, int bytes)
|
||||
int gprs_codel_control(struct gprs_codel *state, const struct timespec *recv,
|
||||
const struct timespec *now, int bytes)
|
||||
{
|
||||
struct timeval sojourn_time;
|
||||
struct timeval delta;
|
||||
struct timespec sojourn_time;
|
||||
struct timespec delta;
|
||||
|
||||
if (recv == NULL)
|
||||
goto stop_dropping;
|
||||
|
||||
timersub(now, recv, &sojourn_time);
|
||||
timespecsub(now, recv, &sojourn_time);
|
||||
|
||||
if (timercmp(&sojourn_time, &state->target, <))
|
||||
if (timespeccmp(&sojourn_time, &state->target, <))
|
||||
goto stop_dropping;
|
||||
|
||||
if (bytes >= 0 && (unsigned)bytes <= state->maxpacket)
|
||||
goto stop_dropping;
|
||||
|
||||
if (!timerisset(&state->first_above_time)) {
|
||||
timeradd(now, &state->interval, &state->first_above_time);
|
||||
if (!timespecisset(&state->first_above_time)) {
|
||||
timespecadd(now, &state->interval, &state->first_above_time);
|
||||
goto not_ok_to_drop;
|
||||
}
|
||||
|
||||
if (timercmp(now, &state->first_above_time, <))
|
||||
if (timespeccmp(now, &state->first_above_time, <))
|
||||
goto not_ok_to_drop;
|
||||
|
||||
/* Ok to drop */
|
||||
|
@ -134,14 +135,14 @@ int gprs_codel_control(struct gprs_codel *state, const struct timeval *recv,
|
|||
if (!state->dropping) {
|
||||
int recently = 0;
|
||||
int in_drop_cycle = 0;
|
||||
if (timerisset(&state->drop_next)) {
|
||||
timersub(now, &state->drop_next, &delta);
|
||||
in_drop_cycle = timercmp(&delta, &state->interval, <);
|
||||
if (timespecisset(&state->drop_next)) {
|
||||
timespecsub(now, &state->drop_next, &delta);
|
||||
in_drop_cycle = timespeccmp(&delta, &state->interval, <);
|
||||
recently = in_drop_cycle;
|
||||
}
|
||||
if (!recently) {
|
||||
timersub(now, &state->first_above_time, &delta);
|
||||
recently = !timercmp(&delta, &state->interval, <);
|
||||
timespecsub(now, &state->first_above_time, &delta);
|
||||
recently = !timespeccmp(&delta, &state->interval, <);
|
||||
};
|
||||
if (!recently)
|
||||
return 0;
|
||||
|
@ -155,24 +156,24 @@ int gprs_codel_control(struct gprs_codel *state, const struct timeval *recv,
|
|||
|
||||
state->drop_next = *now;
|
||||
} else {
|
||||
if (timercmp(now, &state->drop_next, <))
|
||||
if (timespeccmp(now, &state->drop_next, <))
|
||||
return 0;
|
||||
|
||||
state->count += 1;
|
||||
}
|
||||
|
||||
control_law(state, &delta);
|
||||
timeradd(&state->drop_next, &delta, &state->drop_next);
|
||||
timespecadd(&state->drop_next, &delta, &state->drop_next);
|
||||
|
||||
#if 1
|
||||
LOGP(DRLCMAC, LOGL_INFO,
|
||||
"CoDel decided to drop packet, window = %d.%03dms, count = %d\n",
|
||||
(int)delta.tv_sec, (int)(delta.tv_usec / 1000), state->count);
|
||||
(int)delta.tv_sec, (int)(delta.tv_nsec / 1000000), state->count);
|
||||
#endif
|
||||
return 1;
|
||||
|
||||
stop_dropping:
|
||||
timerclear(&state->first_above_time);
|
||||
timespecclear(&state->first_above_time);
|
||||
not_ok_to_drop:
|
||||
state->dropping = 0;
|
||||
return 0;
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
/* Spec default values */
|
||||
#define GPRS_CODEL_DEFAULT_INTERVAL_MS 100
|
||||
|
@ -40,10 +40,10 @@ extern "C" {
|
|||
struct gprs_codel {
|
||||
int dropping;
|
||||
unsigned count;
|
||||
struct timeval first_above_time;
|
||||
struct timeval drop_next;
|
||||
struct timeval target;
|
||||
struct timeval interval;
|
||||
struct timespec first_above_time;
|
||||
struct timespec drop_next;
|
||||
struct timespec target;
|
||||
struct timespec interval;
|
||||
unsigned maxpacket;
|
||||
};
|
||||
|
||||
|
@ -66,8 +66,8 @@ struct gprs_codel {
|
|||
*
|
||||
* \return != 0 if the packet should be dropped, 0 otherwise
|
||||
*/
|
||||
int gprs_codel_control(struct gprs_codel *state, const struct timeval *recv,
|
||||
const struct timeval *now, int bytes);
|
||||
int gprs_codel_control(struct gprs_codel *state, const struct timespec *recv,
|
||||
const struct timespec *now, int bytes);
|
||||
|
||||
/*!
|
||||
* \brief Initialise CoDel state
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
extern "C" {
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/timer.h>
|
||||
#include <osmocom/gsm/protocol/gsm_04_08.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
#include "coding_scheme.h"
|
||||
|
@ -45,7 +46,7 @@ extern void *tall_pcu_ctx;
|
|||
static int64_t now_msec()
|
||||
{
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
osmo_clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
|
||||
return int64_t(ts.tv_sec) * 1000 + ts.tv_nsec / 1000000;
|
||||
}
|
||||
|
|
37
src/llc.cpp
37
src/llc.cpp
|
@ -27,6 +27,8 @@ extern "C" {
|
|||
#include <osmocom/core/msgb.h>
|
||||
}
|
||||
|
||||
#include "pcu_utils.h"
|
||||
|
||||
/* reset LLC frame */
|
||||
void gprs_llc::reset()
|
||||
{
|
||||
|
@ -104,7 +106,7 @@ void gprs_llc_queue::init()
|
|||
}
|
||||
|
||||
|
||||
void gprs_llc_queue::enqueue(struct msgb *llc_msg, const struct timeval *expire_time)
|
||||
void gprs_llc_queue::enqueue(struct msgb *llc_msg, const struct timespec *expire_time)
|
||||
{
|
||||
MetaInfo *meta_storage;
|
||||
|
||||
|
@ -114,7 +116,7 @@ void gprs_llc_queue::enqueue(struct msgb *llc_msg, const struct timeval *expire_
|
|||
m_queue_octets += msgb_length(llc_msg);
|
||||
|
||||
meta_storage = (MetaInfo *)&llc_msg->cb[0];
|
||||
osmo_gettimeofday(&meta_storage->recv_time, NULL);
|
||||
osmo_clock_gettime(CLOCK_MONOTONIC, &meta_storage->recv_time);
|
||||
meta_storage->expire_time = *expire_time;
|
||||
|
||||
msgb_enqueue(&m_queue, llc_msg);
|
||||
|
@ -162,7 +164,7 @@ void gprs_llc_queue::move_and_merge(gprs_llc_queue *o)
|
|||
const MetaInfo *mi1 = (MetaInfo *)&msg1->cb[0];
|
||||
const MetaInfo *mi2 = (MetaInfo *)&msg2->cb[0];
|
||||
|
||||
if (timercmp(&mi2->recv_time, &mi1->recv_time, >)) {
|
||||
if (timespeccmp(&mi2->recv_time, &mi1->recv_time, >)) {
|
||||
msg = msg1;
|
||||
msg1 = NULL;
|
||||
} else {
|
||||
|
@ -192,7 +194,7 @@ void gprs_llc_queue::move_and_merge(gprs_llc_queue *o)
|
|||
struct msgb *gprs_llc_queue::dequeue(const MetaInfo **info)
|
||||
{
|
||||
struct msgb *msg;
|
||||
struct timeval *tv, tv_now, tv_result;
|
||||
struct timespec *tv, tv_now, tv_result;
|
||||
uint32_t lifetime;
|
||||
const MetaInfo *meta_storage;
|
||||
|
||||
|
@ -209,17 +211,17 @@ struct msgb *gprs_llc_queue::dequeue(const MetaInfo **info)
|
|||
m_queue_octets -= msgb_length(msg);
|
||||
|
||||
/* take the second time */
|
||||
osmo_gettimeofday(&tv_now, NULL);
|
||||
tv = (struct timeval *)&msg->data[sizeof(*tv)];
|
||||
timersub(&tv_now, &meta_storage->recv_time, &tv_result);
|
||||
osmo_clock_gettime(CLOCK_MONOTONIC, &tv_now);
|
||||
tv = (struct timespec *)&msg->data[sizeof(*tv)];
|
||||
timespecsub(&tv_now, &meta_storage->recv_time, &tv_result);
|
||||
|
||||
lifetime = tv_result.tv_sec*1000 + tv_result.tv_usec/1000;
|
||||
lifetime = tv_result.tv_sec*1000 + tv_result.tv_nsec/1000000;
|
||||
m_avg_queue_delay = m_avg_queue_delay * ALPHA + lifetime * (1-ALPHA);
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
void gprs_llc_queue::calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec, struct timeval *tv)
|
||||
void gprs_llc_queue::calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec, struct timespec *tv)
|
||||
{
|
||||
uint16_t delay_csec;
|
||||
if (bts->bts_data()->force_llc_lifetime)
|
||||
|
@ -234,20 +236,19 @@ void gprs_llc_queue::calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec,
|
|||
}
|
||||
|
||||
/* calculate timestamp of timeout */
|
||||
struct timeval now, csec;
|
||||
osmo_gettimeofday(&now, NULL);
|
||||
csec.tv_usec = (delay_csec % 100) * 10000;
|
||||
csec.tv_sec = delay_csec / 100;
|
||||
struct timespec now, csec;
|
||||
osmo_clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
csecs_to_timespec(delay_csec, &csec);
|
||||
|
||||
timeradd(&now, &csec, tv);
|
||||
timespecadd(&now, &csec, tv);
|
||||
}
|
||||
|
||||
bool gprs_llc_queue::is_frame_expired(const struct timeval *tv_now,
|
||||
const struct timeval *tv)
|
||||
bool gprs_llc_queue::is_frame_expired(const struct timespec *tv_now,
|
||||
const struct timespec *tv)
|
||||
{
|
||||
/* Timeout is infinite */
|
||||
if (tv->tv_sec == 0 && tv->tv_usec == 0)
|
||||
if (tv->tv_sec == 0 && tv->tv_nsec == 0)
|
||||
return false;
|
||||
|
||||
return timercmp(tv_now, tv, >);
|
||||
return timespeccmp(tv_now, tv, >);
|
||||
}
|
||||
|
|
14
src/llc.h
14
src/llc.h
|
@ -24,7 +24,7 @@ extern "C" {
|
|||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
#define LLC_MAX_LEN 1543
|
||||
|
||||
|
@ -63,19 +63,19 @@ struct gprs_llc {
|
|||
*/
|
||||
struct gprs_llc_queue {
|
||||
struct MetaInfo {
|
||||
struct timeval recv_time;
|
||||
struct timeval expire_time;
|
||||
struct timespec recv_time;
|
||||
struct timespec expire_time;
|
||||
};
|
||||
|
||||
static void calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec,
|
||||
struct timeval *tv);
|
||||
static bool is_frame_expired(const struct timeval *now,
|
||||
const struct timeval *tv);
|
||||
struct timespec *tv);
|
||||
static bool is_frame_expired(const struct timespec *now,
|
||||
const struct timespec *tv);
|
||||
static bool is_user_data_frame(uint8_t *data, size_t len);
|
||||
|
||||
void init();
|
||||
|
||||
void enqueue(struct msgb *llc_msg, const struct timeval *expire_time);
|
||||
void enqueue(struct msgb *llc_msg, const struct timespec *expire_time);
|
||||
struct msgb *dequeue(const MetaInfo **info = 0);
|
||||
void clear(BTS *bts);
|
||||
void move_and_merge(gprs_llc_queue *o);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
extern "C" {
|
||||
#include <osmocom/gsm/gsm_utils.h>
|
||||
}
|
||||
#include <time.h>
|
||||
|
||||
inline int msecs_to_frames(int msecs) {
|
||||
return (msecs * (1024 * 1000 / 4615)) / 1024;
|
||||
|
@ -29,9 +30,9 @@ inline uint32_t next_fn(uint32_t fn, uint32_t offset)
|
|||
return (fn + offset) % GSM_MAX_FN;
|
||||
}
|
||||
|
||||
inline void csecs_to_timeval(unsigned csecs, struct timeval *tv) {
|
||||
tv->tv_sec = csecs / 100;
|
||||
tv->tv_usec = (csecs % 100) * 10000;
|
||||
inline void csecs_to_timespec(unsigned csecs, struct timespec *ts) {
|
||||
ts->tv_sec = csecs / 100;
|
||||
ts->tv_nsec = (csecs % 100) * 10000000;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
|
|
@ -98,9 +98,9 @@ void gprs_rlcmac_dl_tbf::cleanup()
|
|||
void gprs_rlcmac_dl_tbf::start_llc_timer()
|
||||
{
|
||||
if (bts_data()->llc_idle_ack_csec > 0) {
|
||||
struct timeval tv;
|
||||
csecs_to_timeval(bts_data()->llc_idle_ack_csec, &tv);
|
||||
osmo_timer_schedule(&m_llc_timer, tv.tv_sec, tv.tv_usec);
|
||||
struct timespec tv;
|
||||
csecs_to_timespec(bts_data()->llc_idle_ack_csec, &tv);
|
||||
osmo_timer_schedule(&m_llc_timer, tv.tv_sec, tv.tv_nsec / 1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,7 +108,7 @@ int gprs_rlcmac_dl_tbf::append_data(const uint8_t ms_class,
|
|||
const uint16_t pdu_delay_csec,
|
||||
const uint8_t *data, const uint16_t len)
|
||||
{
|
||||
struct timeval expire_time;
|
||||
struct timespec expire_time;
|
||||
|
||||
LOGPTBFDL(this, LOGL_DEBUG, "appending %u bytes\n", len);
|
||||
|
||||
|
@ -262,21 +262,21 @@ int gprs_rlcmac_dl_tbf::handle(struct gprs_rlcmac_bts *bts,
|
|||
struct msgb *gprs_rlcmac_dl_tbf::llc_dequeue(bssgp_bvc_ctx *bctx)
|
||||
{
|
||||
struct msgb *msg;
|
||||
struct timeval tv_now, tv_now2;
|
||||
struct timespec tv_now, tv_now2;
|
||||
uint32_t octets = 0, frames = 0;
|
||||
struct timeval hyst_delta = {0, 0};
|
||||
struct timespec hyst_delta = {0, 0};
|
||||
const unsigned keep_small_thresh = 60;
|
||||
const gprs_llc_queue::MetaInfo *info;
|
||||
|
||||
if (bts_data()->llc_discard_csec)
|
||||
csecs_to_timeval(bts_data()->llc_discard_csec, &hyst_delta);
|
||||
csecs_to_timespec(bts_data()->llc_discard_csec, &hyst_delta);
|
||||
|
||||
gettimeofday(&tv_now, NULL);
|
||||
timeradd(&tv_now, &hyst_delta, &tv_now2);
|
||||
osmo_clock_gettime(CLOCK_MONOTONIC, &tv_now);
|
||||
timespecadd(&tv_now, &hyst_delta, &tv_now2);
|
||||
|
||||
while ((msg = llc_queue()->dequeue(&info))) {
|
||||
const struct timeval *tv_disc = &info->expire_time;
|
||||
const struct timeval *tv_recv = &info->recv_time;
|
||||
const struct timespec *tv_disc = &info->expire_time;
|
||||
const struct timespec *tv_recv = &info->recv_time;
|
||||
|
||||
gprs_bssgp_update_queue_delay(tv_recv, &tv_now);
|
||||
|
||||
|
|
|
@ -72,7 +72,6 @@ struct gprs_rlcmac_dl_tbf : public gprs_rlcmac_tbf {
|
|||
void set_window_size();
|
||||
void update_coding_scheme_counter_dl(enum CodingScheme cs);
|
||||
|
||||
/* TODO: add the gettimeofday as parameter */
|
||||
struct msgb *llc_dequeue(bssgp_bvc_ctx *bctx);
|
||||
|
||||
/* Please note that all variables here will be reset when changing
|
||||
|
|
|
@ -13,16 +13,17 @@
|
|||
#endif
|
||||
#include <osmocom/core/application.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/timer_compat.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
|
||||
#include "gprs_codel.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
static int do_codel_control(struct gprs_codel *state, const struct timeval *recv,
|
||||
struct timeval *now, const struct timeval *delta_now, int count)
|
||||
static int do_codel_control(struct gprs_codel *state, const struct timespec *recv,
|
||||
struct timespec *now, const struct timespec *delta_now, int count)
|
||||
{
|
||||
int drop;
|
||||
|
||||
|
@ -32,11 +33,11 @@ static int do_codel_control(struct gprs_codel *state, const struct timeval *recv
|
|||
"recv = %d.%03d, now = %d.%03d, "
|
||||
"codel.count = %d\n",
|
||||
count,
|
||||
(int)recv->tv_sec, (int)recv->tv_usec/1000,
|
||||
(int)now->tv_sec, (int)now->tv_usec/1000,
|
||||
(int)recv->tv_sec, (int)recv->tv_nsec/1000000,
|
||||
(int)now->tv_sec, (int)now->tv_nsec/1000000,
|
||||
state->count);
|
||||
} else {
|
||||
timeradd(now, delta_now, now);
|
||||
timespecadd(now, delta_now, now);
|
||||
}
|
||||
|
||||
return drop == 0 ? 0 : 1;
|
||||
|
@ -45,11 +46,11 @@ static int do_codel_control(struct gprs_codel *state, const struct timeval *recv
|
|||
static void test_codel(void)
|
||||
{
|
||||
struct gprs_codel codel;
|
||||
struct timeval now;
|
||||
struct timeval recv;
|
||||
const struct timeval delta_now = {0, 10000};
|
||||
const struct timeval init_delta_recv = {0, 5000};
|
||||
struct timeval delta_recv;
|
||||
struct timespec now;
|
||||
struct timespec recv;
|
||||
const struct timespec delta_now = {0, 10000000};
|
||||
const struct timespec init_delta_recv = {0, 5000000};
|
||||
struct timespec delta_recv;
|
||||
unsigned count;
|
||||
unsigned sum = 0;
|
||||
unsigned dropped = 0;
|
||||
|
@ -59,13 +60,13 @@ static void test_codel(void)
|
|||
gprs_codel_init(&codel);
|
||||
gprs_codel_set_interval(&codel, 100);
|
||||
|
||||
timerclear(&now);
|
||||
timerclear(&recv);
|
||||
timespecclear(&now);
|
||||
timespecclear(&recv);
|
||||
delta_recv = init_delta_recv;
|
||||
|
||||
for (count = 0; count < 20; count++, sum++) {
|
||||
drop = do_codel_control(&codel, &recv, &now, &delta_now, sum);
|
||||
timeradd(&recv, &delta_recv, &recv);
|
||||
timespecadd(&recv, &delta_recv, &recv);
|
||||
dropped += drop;
|
||||
}
|
||||
|
||||
|
@ -75,7 +76,7 @@ static void test_codel(void)
|
|||
|
||||
for (count = 0; count < 20; count++, sum++) {
|
||||
drop = do_codel_control(&codel, &recv, &now, &delta_now, sum);
|
||||
timeradd(&recv, &delta_recv, &recv);
|
||||
timespecadd(&recv, &delta_recv, &recv);
|
||||
dropped += drop;
|
||||
}
|
||||
|
||||
|
@ -83,11 +84,11 @@ static void test_codel(void)
|
|||
OSMO_ASSERT(codel.dropping);
|
||||
|
||||
/* slow down recv rate */
|
||||
delta_recv.tv_usec = delta_now.tv_usec;
|
||||
delta_recv.tv_nsec = delta_now.tv_nsec;
|
||||
|
||||
for (count = 0; count < 75; count++, sum++) {
|
||||
drop = do_codel_control(&codel, &recv, &now, &delta_now, sum);
|
||||
timeradd(&recv, &delta_recv, &recv);
|
||||
timespecadd(&recv, &delta_recv, &recv);
|
||||
dropped += drop;
|
||||
}
|
||||
|
||||
|
@ -96,7 +97,7 @@ static void test_codel(void)
|
|||
|
||||
for (count = 0; count < 50; count++, sum++) {
|
||||
drop = do_codel_control(&codel, &recv, &now, &delta_now, sum);
|
||||
timeradd(&recv, &delta_recv, &recv);
|
||||
timespecadd(&recv, &delta_recv, &recv);
|
||||
dropped += drop;
|
||||
}
|
||||
|
||||
|
@ -109,7 +110,7 @@ static void test_codel(void)
|
|||
|
||||
for (count = 0; count < 20; count++, sum++) {
|
||||
drop = do_codel_control(&codel, &recv, &now, &delta_now, sum);
|
||||
timeradd(&recv, &delta_recv, &recv);
|
||||
timespecadd(&recv, &delta_recv, &recv);
|
||||
dropped += drop;
|
||||
}
|
||||
|
||||
|
@ -118,7 +119,7 @@ static void test_codel(void)
|
|||
|
||||
for (count = 0; count < 20; count++, sum++) {
|
||||
drop = do_codel_control(&codel, &recv, &now, &delta_now, sum);
|
||||
timeradd(&recv, &delta_recv, &recv);
|
||||
timespecadd(&recv, &delta_recv, &recv);
|
||||
dropped += drop;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,11 +42,12 @@ extern "C" {
|
|||
void *tall_pcu_ctx;
|
||||
int16_t spoof_mnc = 0, spoof_mcc = 0;
|
||||
bool spoof_mnc_3_digits = false;
|
||||
static struct timespec *clk_mono_override_time;
|
||||
|
||||
static void enqueue_data(gprs_llc_queue *queue, const uint8_t *data, size_t len,
|
||||
const struct timeval *expire_time)
|
||||
const struct timespec *expire_time)
|
||||
{
|
||||
struct timeval *tv;
|
||||
struct timespec *tv;
|
||||
uint8_t *msg_data;
|
||||
struct msgb *llc_msg = msgb_alloc(len + sizeof(*tv) * 2,
|
||||
"llc_pdu_queue");
|
||||
|
@ -81,7 +82,7 @@ static void dequeue_and_check(gprs_llc_queue *queue, const uint8_t *exp_data,
|
|||
}
|
||||
|
||||
static void enqueue_data(gprs_llc_queue *queue, const char *message,
|
||||
const struct timeval *expire_time)
|
||||
const struct timespec *expire_time)
|
||||
{
|
||||
enqueue_data(queue, (uint8_t *)(message), strlen(message), expire_time);
|
||||
}
|
||||
|
@ -96,7 +97,7 @@ static void dequeue_and_check(gprs_llc_queue *queue, const char *exp_message,
|
|||
static void test_llc_queue()
|
||||
{
|
||||
gprs_llc_queue queue;
|
||||
struct timeval expire_time = {0};
|
||||
struct timespec expire_time = {0};
|
||||
|
||||
printf("=== start %s ===\n", __func__);
|
||||
|
||||
|
@ -144,17 +145,17 @@ static void test_llc_meta()
|
|||
OSMO_ASSERT(queue.octets() == 0);
|
||||
|
||||
info1.recv_time.tv_sec = 123456777;
|
||||
info1.recv_time.tv_usec = 123456;
|
||||
info1.recv_time.tv_nsec = 123456000;
|
||||
info1.expire_time.tv_sec = 123456789;
|
||||
info1.expire_time.tv_usec = 987654;
|
||||
osmo_gettimeofday_override_time = info1.recv_time;
|
||||
info1.expire_time.tv_nsec = 987654000;
|
||||
*clk_mono_override_time = info1.recv_time;
|
||||
enqueue_data(&queue, "LLC message 1", &info1.expire_time);
|
||||
|
||||
info2.recv_time.tv_sec = 123458000;
|
||||
info2.recv_time.tv_usec = 547352;
|
||||
info2.recv_time.tv_nsec = 547352000;
|
||||
info2.expire_time.tv_sec = 123458006;
|
||||
info2.expire_time.tv_usec = 867252;
|
||||
osmo_gettimeofday_override_time = info2.recv_time;
|
||||
info2.expire_time.tv_nsec = 867252000;
|
||||
*clk_mono_override_time = info2.recv_time;
|
||||
enqueue_data(&queue, "LLC message 2", &info2.expire_time);
|
||||
|
||||
dequeue_and_check(&queue, "LLC message 1", &info1);
|
||||
|
@ -171,26 +172,26 @@ static void test_llc_merge()
|
|||
{
|
||||
gprs_llc_queue queue1;
|
||||
gprs_llc_queue queue2;
|
||||
struct timeval expire_time = {0};
|
||||
struct timespec expire_time = {0};
|
||||
|
||||
printf("=== start %s ===\n", __func__);
|
||||
|
||||
queue1.init();
|
||||
queue2.init();
|
||||
|
||||
osmo_gettimeofday_override_time.tv_sec += 1;
|
||||
clk_mono_override_time->tv_sec += 1;
|
||||
enqueue_data(&queue1, "*A*", &expire_time);
|
||||
|
||||
osmo_gettimeofday_override_time.tv_sec += 1;
|
||||
clk_mono_override_time->tv_sec += 1;
|
||||
enqueue_data(&queue1, "*B*", &expire_time);
|
||||
|
||||
osmo_gettimeofday_override_time.tv_sec += 1;
|
||||
clk_mono_override_time->tv_sec += 1;
|
||||
enqueue_data(&queue2, "*C*", &expire_time);
|
||||
|
||||
osmo_gettimeofday_override_time.tv_sec += 1;
|
||||
clk_mono_override_time->tv_sec += 1;
|
||||
enqueue_data(&queue1, "*D*", &expire_time);
|
||||
|
||||
osmo_gettimeofday_override_time.tv_sec += 1;
|
||||
clk_mono_override_time->tv_sec += 1;
|
||||
enqueue_data(&queue2, "*E*", &expire_time);
|
||||
|
||||
OSMO_ASSERT(queue1.size() == 3);
|
||||
|
@ -235,9 +236,10 @@ int main(int argc, char **argv)
|
|||
vty_init(&pcu_vty_info);
|
||||
pcu_vty_init();
|
||||
|
||||
osmo_gettimeofday_override = true;
|
||||
osmo_gettimeofday_override_time.tv_sec = 123456777;
|
||||
osmo_gettimeofday_override_time.tv_usec = 123456;
|
||||
osmo_clock_override_enable(CLOCK_MONOTONIC, true);
|
||||
clk_mono_override_time = osmo_clock_override_gettimespec(CLOCK_MONOTONIC);
|
||||
clk_mono_override_time->tv_sec = 123456777;
|
||||
clk_mono_override_time->tv_nsec = 123456000;
|
||||
|
||||
test_llc_queue();
|
||||
test_llc_meta();
|
||||
|
|
Loading…
Reference in New Issue