From 8b92d9a2c651d753f756aba5710b6d59ee0f24a1 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 30 Jan 2017 16:01:30 +0100 Subject: [PATCH] track and return performance metrics per cadet connection --- src/cadet/gnunet-service-cadet-new_channel.c | 16 +-- .../gnunet-service-cadet-new_connection.c | 100 ++++++++++++++++-- .../gnunet-service-cadet-new_connection.h | 74 +++++++++++++ 3 files changed, 176 insertions(+), 14 deletions(-) diff --git a/src/cadet/gnunet-service-cadet-new_channel.c b/src/cadet/gnunet-service-cadet-new_channel.c index f6ef50caa..00866b3d5 100644 --- a/src/cadet/gnunet-service-cadet-new_channel.c +++ b/src/cadet/gnunet-service-cadet-new_channel.c @@ -1417,13 +1417,16 @@ handle_matching_ack (struct CadetChannel *ch, crm->qe = NULL; } if ( (1 == crm->num_transmissions) && - (NULL != cti) && - (0 == memcmp (cti, - &crm->connection_taken, - sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier))) ) + (NULL != cti) ) { - GCC_latency_observed (cti, - GNUNET_TIME_absolute_get_duration (crm->first_transmission_time)); + GCC_ack_observed (cti); + if (0 == memcmp (cti, + &crm->connection_taken, + sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier))) + { + GCC_latency_observed (cti, + GNUNET_TIME_absolute_get_duration (crm->first_transmission_time)); + } } GNUNET_free (crm->data_message); GNUNET_free (crm); @@ -1643,6 +1646,7 @@ data_sent_cb (void *cls, { crm->first_transmission_time = GNUNET_TIME_absolute_get (); crm->connection_taken = *cid; + GCC_ack_expected (cid); } } if (0 == crm->retry_delay.rel_value_us) diff --git a/src/cadet/gnunet-service-cadet-new_connection.c b/src/cadet/gnunet-service-cadet-new_connection.c index bf2aa6aee..8536b638d 100644 --- a/src/cadet/gnunet-service-cadet-new_connection.c +++ b/src/cadet/gnunet-service-cadet-new_connection.c @@ -24,11 +24,6 @@ * end-to-end routes and transmits messages along the route * @author Bartlomiej Polot * @author Christian Grothoff - * - * TODO: - * - keep per-connection performance metrics - * - in particular, interact with channel (!) to see - * if we get ACKs indicating successful payload delivery. */ #include "platform.h" #include "gnunet-service-cadet-new.h" @@ -140,6 +135,11 @@ struct CadetConnection */ struct GNUNET_TIME_Relative retry_delay; + /** + * Performance metrics for this connection. + */ + struct CadetConnectionMetrics metrics; + /** * State of the connection. */ @@ -150,6 +150,11 @@ struct CadetConnection */ enum GNUNET_CADET_ChannelOption options; + /** + * How many latency observations did we make for this connection? + */ + unsigned int latency_datapoints; + /** * Offset of our @e destination in @e path. */ @@ -300,6 +305,19 @@ GCC_get_ct (struct CadetConnection *cc) } +/** + * Obtain performance @a metrics from @a cc. + * + * @param cc connection to query + * @return the metrics + */ +const struct CadetConnectionMetrics * +GCC_get_metrics (struct CadetConnection *cc) +{ + return &cc->metrics; +} + + /** * Send a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE through the * tunnel to prevent it from timing out. @@ -376,19 +394,81 @@ send_keepalive (void *cls) } +/** + * We sent a message for which we expect to receive an ACK via + * the connection identified by @a cti. + * + * @param cid connection identifier where we expect an ACK + */ +void +GCC_ack_expected (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid) +{ + struct CadetConnection *cc; + + cc = GNUNET_CONTAINER_multishortmap_get (connections, + &cid->connection_of_tunnel); + if (NULL == cc) + return; /* whopise, connection alredy down? */ + cc->metrics.num_acked_transmissions++; +} + + +/** + * We observed an ACK for a message that was originally sent via + * the connection identified by @a cti. + * + * @param cti connection identifier where we got an ACK for a message + * that was originally sent via this connection (the ACK + * may have gotten back to us via a different connection). + */ +void +GCC_ack_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid) +{ + struct CadetConnection *cc; + + cc = GNUNET_CONTAINER_multishortmap_get (connections, + &cid->connection_of_tunnel); + if (NULL == cc) + return; /* whopise, connection alredy down? */ + cc->metrics.num_successes++; +} + + /** * We observed some the given @a latency on the connection * identified by @a cti. (The same connection was taken * in both directions.) * - * @param cti connection identifier where we measured latency + * @param cid connection identifier where we measured latency * @param latency the observed latency */ void -GCC_latency_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti, +GCC_latency_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid, struct GNUNET_TIME_Relative latency) { - GNUNET_break (0); // FIXME + struct CadetConnection *cc; + double weight; + double result; + + cc = GNUNET_CONTAINER_multishortmap_get (connections, + &cid->connection_of_tunnel); + if (NULL == cc) + return; /* whopise, connection alredy down? */ + GNUNET_STATISTICS_update (stats, + "# latencies observed", + 1, + GNUNET_NO); + cc->latency_datapoints++; + if (cc->latency_datapoints >= 7) + weight = 7.0; + else + weight = cc->latency_datapoints; + /* Compute weighted average, giving at MOST weight 7 to the + existing values, or less if that value is based on fewer than 7 + measurements. */ + result = (weight * cc->metrics.aged_latency.rel_value_us) + 1.0 * latency.rel_value_us; + result /= (weight + 1.0); + cc->metrics.aged_latency.rel_value_us = (uint64_t) result; } @@ -413,6 +493,7 @@ GCC_handle_connection_create_ack (struct CadetConnection *cc) GNUNET_SCHEDULER_cancel (cc->task); cc->task = NULL; } + cc->metrics.age = GNUNET_TIME_absolute_get (); update_state (cc, CADET_CONNECTION_READY, cc->mqm_ready); @@ -492,6 +573,7 @@ GCC_handle_encrypted (struct CadetConnection *cc, GCC_2s (cc)); GCC_handle_connection_create_ack (cc); } + cc->metrics.last_use = GNUNET_TIME_absolute_get (); GCT_handle_encrypted (cc->ct, msg); } @@ -666,6 +748,7 @@ manage_first_hop_mq (void *cls, break; case CADET_CONNECTION_CREATE_RECEIVED: /* We got the 'CREATE' (incoming connection), should send the CREATE_ACK */ + cc->metrics.age = GNUNET_TIME_absolute_get (); cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack, cc); break; @@ -891,6 +974,7 @@ GCC_transmit (struct CadetConnection *cc, GCC_2s (cc)); GNUNET_assert (GNUNET_YES == cc->mqm_ready); GNUNET_assert (CADET_CONNECTION_READY == cc->state); + cc->metrics.last_use = GNUNET_TIME_absolute_get (); cc->mqm_ready = GNUNET_NO; if (NULL != cc->task) { diff --git a/src/cadet/gnunet-service-cadet-new_connection.h b/src/cadet/gnunet-service-cadet-new_connection.h index c42ec9c46..61d9d5d78 100644 --- a/src/cadet/gnunet-service-cadet-new_connection.h +++ b/src/cadet/gnunet-service-cadet-new_connection.h @@ -176,6 +176,58 @@ GCC_handle_kx_auth (struct CadetConnection *cc, const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg); +/** + * Performance metrics for a connection. + */ +struct CadetConnectionMetrics +{ + + /** + * Our current best estimate of the latency, based on a weighted + * average of at least @a latency_datapoints values. + */ + struct GNUNET_TIME_Relative aged_latency; + + /** + * When was this connection first established? (by us sending or + * receiving the CREATE_ACK for the first time) + */ + struct GNUNET_TIME_Absolute age; + + /** + * When was this connection last used? (by us sending or + * receiving a PAYLOAD message on it) + */ + struct GNUNET_TIME_Absolute last_use; + + /** + * How many packets that ought to generate an ACK did we send via + * this connection? + */ + unsigned long long num_acked_transmissions; + + /** + * Number of packets that were sent via this connection did actually + * receive an ACK? (Note: ACKs may be transmitted and lost via + * other connections, so this value should only be interpreted + * relative to @e num_acked_transmissions and in relation to other + * connections.) + */ + unsigned long long num_successes; + +}; + + +/** + * Obtain performance @a metrics from @a cc. + * + * @param cc connection to query + * @return the metrics + */ +const struct CadetConnectionMetrics * +GCC_get_metrics (struct CadetConnection *cc); + + /** * Handle encrypted message. * @@ -187,6 +239,28 @@ GCC_handle_encrypted (struct CadetConnection *cc, const struct GNUNET_CADET_TunnelEncryptedMessage *msg); +/** + * We sent a message for which we expect to receive an ACK via + * the connection identified by @a cti. + * + * @param cid connection identifier where we expect an ACK + */ +void +GCC_ack_expected (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid); + + +/** + * We observed an ACK for a message that was originally sent via + * the connection identified by @a cti. + * + * @param cid connection identifier where we got an ACK for a message + * that was originally sent via this connection (the ACK + * may have gotten back to us via a different connection). + */ +void +GCC_ack_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid); + + /** * We observed some the given @a latency on the connection * identified by @a cti. (The same connection was taken -- 2.25.1