track and return performance metrics per cadet connection
authorChristian Grothoff <christian@grothoff.org>
Mon, 30 Jan 2017 15:01:30 +0000 (16:01 +0100)
committerChristian Grothoff <christian@grothoff.org>
Mon, 30 Jan 2017 15:01:30 +0000 (16:01 +0100)
src/cadet/gnunet-service-cadet-new_channel.c
src/cadet/gnunet-service-cadet-new_connection.c
src/cadet/gnunet-service-cadet-new_connection.h

index f6ef50caa7067b017cf21321cf27e9191c6daa3e..00866b3d540e39a4c44322461ed36f34360b8c86 100644 (file)
@@ -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)
index bf2aa6aee27c04294b520d1877faf4e6ecbd59db..8536b638da8821bb4c98fee7876fa4a4800ab517 100644 (file)
  *        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)
   {
index c42ec9c46bcd1209abae9c4a8ab5676ca95878b2..61d9d5d78631544b132667426490acc1805ac2d1 100644 (file)
@@ -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