You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
rtpengine/daemon/statistics.c

234 lines
7.5 KiB

#include "call.h"
#include "statistics.h"
#include "graphite.h"
#include "main.h"
struct totalstats rtpe_totalstats;
struct totalstats rtpe_totalstats_interval;
mutex_t rtpe_totalstats_lastinterval_lock;
struct totalstats rtpe_totalstats_lastinterval;
static void timeval_totalstats_average_add(struct totalstats *s, const struct timeval *add) {
struct timeval dp, oa;
mutex_lock(&s->total_average_lock);
// new average = ((old average * old num sessions) + datapoint) / new num sessions
// ... but this will overflow when num sessions becomes very large
// timeval_multiply(&t, &s->total_average_call_dur, s->total_managed_sess);
// timeval_add(&t, &t, add);
// s->total_managed_sess++;
// timeval_divide(&s->total_average_call_dur, &t, s->total_managed_sess);
// alternative:
// new average = old average + (datapoint / new num sessions) - (old average / new num sessions)
s->total_managed_sess++;
timeval_divide(&dp, add, s->total_managed_sess);
timeval_divide(&oa, &s->total_average_call_dur, s->total_managed_sess);
timeval_add(&s->total_average_call_dur, &s->total_average_call_dur, &dp);
timeval_subtract(&s->total_average_call_dur, &s->total_average_call_dur, &oa);
mutex_unlock(&s->total_average_lock);
}
static void timeval_totalstats_interval_call_duration_add(struct totalstats *s,
struct timeval *call_start, struct timeval *call_stop,
struct timeval *interval_start, int interval_dur_s) {
/* work with graphite interval start val which might be changed elsewhere in the code*/
struct timeval real_iv_start = *interval_start;
struct timeval call_duration;
struct timeval *call_start_in_iv = call_start;
/* in case graphite interval needs to be the previous one */
if (timercmp(&real_iv_start, call_stop, >)) {
struct timeval graph_dur = { .tv_sec = interval_dur_s, .tv_usec = 0LL };
timeval_subtract(&real_iv_start, interval_start, &graph_dur);
}
if (timercmp(&real_iv_start, call_start, >))
call_start_in_iv = &real_iv_start;
/* this should never happen and is here for sanitization of output */
if (timercmp(call_start_in_iv, call_stop, >)) {
ilog(LOG_ERR, "Call start seems to exceed call stop");
return;
}
timeval_subtract(&call_duration, call_stop, call_start_in_iv);
mutex_lock(&s->total_calls_duration_lock);
timeval_add(&s->total_calls_duration_interval,
&s->total_calls_duration_interval, &call_duration);
mutex_unlock(&s->total_calls_duration_lock);
}
void statistics_update_totals(struct packet_stream *ps) {
atomic64_add(&rtpe_totalstats.total_relayed_packets,
atomic64_get(&ps->stats.packets));
atomic64_add(&rtpe_totalstats_interval.total_relayed_packets,
atomic64_get(&ps->stats.packets));
atomic64_add(&rtpe_totalstats.total_relayed_errors,
atomic64_get(&ps->stats.errors));
atomic64_add(&rtpe_totalstats_interval.total_relayed_errors,
atomic64_get(&ps->stats.errors));
}
void statistics_update_foreignown_dec(struct call* c) {
if (IS_FOREIGN_CALL(c)) {
atomic64_dec(&rtpe_stats.foreign_sessions);
}
if(IS_OWN_CALL(c)) {
mutex_lock(&rtpe_totalstats_interval.managed_sess_lock);
rtpe_totalstats_interval.managed_sess_min = MIN(rtpe_totalstats_interval.managed_sess_min,
g_hash_table_size(rtpe_callhash) - atomic64_get(&rtpe_stats.foreign_sessions));
mutex_unlock(&rtpe_totalstats_interval.managed_sess_lock);
}
}
void statistics_update_foreignown_inc(struct call* c) {
if (IS_OWN_CALL(c)) {
mutex_lock(&rtpe_totalstats_interval.managed_sess_lock);
rtpe_totalstats_interval.managed_sess_max = MAX(
rtpe_totalstats_interval.managed_sess_max,
g_hash_table_size(rtpe_callhash)
- atomic64_get(&rtpe_stats.foreign_sessions));
mutex_unlock(&rtpe_totalstats_interval.managed_sess_lock);
}
else if (IS_FOREIGN_CALL(c)) { /* foreign call*/
atomic64_inc(&rtpe_stats.foreign_sessions);
atomic64_inc(&rtpe_totalstats.total_foreign_sessions);
}
}
void statistics_update_oneway(struct call* c) {
struct packet_stream *ps = NULL, *ps2 = NULL;
struct call_monologue *ml;
struct call_media *md;
GList *k, *o;
int found = 0;
GList *l;
struct timeval tim_result_duration;
// --- for statistics getting one way stream or no relay at all
int total_nopacket_relayed_sess = 0;
for (l = c->monologues.head; l; l = l->next) {
ml = l->data;
// --- go through partner ml and search the RTP
for (k = ml->medias.head; k; k = k->next) {
md = k->data;
for (o = md->streams.head; o; o = o->next) {
ps = o->data;
if (PS_ISSET(ps, RTP)) {
// --- only RTP is interesting
found = 1;
break;
}
}
if (found) { break; }
}
if (!found)
ps = NULL;
found = 0;
if (ml->active_dialogue) {
// --- go through partner ml and search the RTP
for (k = ml->active_dialogue->medias.head; k; k = k->next) {
md = k->data;
for (o = md->streams.head; o; o = o->next) {
ps2 = o->data;
if (PS_ISSET(ps2, RTP)) {
// --- only RTP is interesting
found = 1;
break;
}
}
if (found) { break; }
}
}
if (!found)
ps2 = NULL;
if (ps && ps2 && atomic64_get(&ps2->stats.packets)==0) {
if (atomic64_get(&ps->stats.packets)!=0 && IS_OWN_CALL(c)){
if (atomic64_get(&ps->stats.packets)!=0) {
atomic64_inc(&rtpe_totalstats.total_oneway_stream_sess);
atomic64_inc(&rtpe_totalstats_interval.total_oneway_stream_sess);
}
}
else {
total_nopacket_relayed_sess++;
}
}
}
if (IS_OWN_CALL(c)) {
atomic64_add(&rtpe_totalstats.total_nopacket_relayed_sess, total_nopacket_relayed_sess / 2);
atomic64_add(&rtpe_totalstats_interval.total_nopacket_relayed_sess, total_nopacket_relayed_sess / 2);
}
if (c->monologues.head) {
ml = c->monologues.head->data;
timeval_subtract(&tim_result_duration, &rtpe_now, &ml->started);
if (IS_OWN_CALL(c)) {
if (ml->term_reason==TIMEOUT) {
atomic64_inc(&rtpe_totalstats.total_timeout_sess);
atomic64_inc(&rtpe_totalstats_interval.total_timeout_sess);
} else if (ml->term_reason==SILENT_TIMEOUT) {
atomic64_inc(&rtpe_totalstats.total_silent_timeout_sess);
atomic64_inc(&rtpe_totalstats_interval.total_silent_timeout_sess);
} else if (ml->term_reason==REGULAR) {
atomic64_inc(&rtpe_totalstats.total_regular_term_sess);
atomic64_inc(&rtpe_totalstats_interval.total_regular_term_sess);
} else if (ml->term_reason==FORCED) {
atomic64_inc(&rtpe_totalstats.total_forced_term_sess);
atomic64_inc(&rtpe_totalstats_interval.total_forced_term_sess);
}
timeval_totalstats_average_add(&rtpe_totalstats, &tim_result_duration);
timeval_totalstats_average_add(&rtpe_totalstats_interval, &tim_result_duration);
timeval_totalstats_interval_call_duration_add(
&rtpe_totalstats_interval, &ml->started, &ml->terminated,
&rtpe_latest_graphite_interval_start,
rtpe_config.graphite_interval);
}
if (ml->term_reason==FINAL_TIMEOUT) {
atomic64_inc(&rtpe_totalstats.total_final_timeout_sess);
atomic64_inc(&rtpe_totalstats_interval.total_final_timeout_sess);
}
}
}
void statistics_init() {
mutex_init(&rtpe_totalstats.total_average_lock);
mutex_init(&rtpe_totalstats_interval.total_average_lock);
mutex_init(&rtpe_totalstats_interval.managed_sess_lock);
mutex_init(&rtpe_totalstats_interval.total_calls_duration_lock);
rtpe_totalstats.started = rtpe_now.tv_sec;
//rtpe_totalstats_interval.managed_sess_min = 0; // already zeroed
//rtpe_totalstats_interval.managed_sess_max = 0;
mutex_init(&rtpe_totalstats_lastinterval_lock);
mutex_init(&rtpe_totalstats_interval.offers_ps.lock);
mutex_init(&rtpe_totalstats_interval.answers_ps.lock);
mutex_init(&rtpe_totalstats_interval.deletes_ps.lock);
}