]> rtime.felk.cvut.cz Git - frescor/fwp.git/commitdiff
Added application to measure FWP timing properites
authorMichal Sojka <sojkam1@fel.cvut.cz>
Tue, 27 Oct 2009 15:28:09 +0000 (16:28 +0100)
committerMichal Sojka <sojkam1@fel.cvut.cz>
Tue, 27 Oct 2009 15:28:09 +0000 (16:28 +0100)
TODO: It is necessary to implement synchronous sending in FWP. Without
this it is possible that FWP vres slows down due to scheduling latencies
and we then measure constantly higher delays.

Signed-off-by: Michal Sojka <sojkam1@fel.cvut.cz>
.topdeps [new file with mode: 0644]
.topmsg [new file with mode: 0644]
fwp/tests/Makefile.omk
fwp/tests/timing/Makefile [new file with mode: 0644]
fwp/tests/timing/Makefile.omk [new file with mode: 0644]
fwp/tests/timing/fwp-timing.c [new file with mode: 0644]

diff --git a/.topdeps b/.topdeps
new file mode 100644 (file)
index 0000000..1f7391f
--- /dev/null
+++ b/.topdeps
@@ -0,0 +1 @@
+master
diff --git a/.topmsg b/.topmsg
new file mode 100644 (file)
index 0000000..b268c6a
--- /dev/null
+++ b/.topmsg
@@ -0,0 +1,10 @@
+From: Michal Sojka <sojkam1@fel.cvut.cz>
+Subject: [PATCH] t/fwp-timing
+
+Application for measure FWP timing properites
+
+TODO: It is necessary to implement synchronous sending in FWP. Without
+this it is possible that FWP vres slows down due to scheduling latencies
+and we then measure constantly higher delays.
+
+Signed-off-by: Michal Sojka <sojkam1@fel.cvut.cz>
index 8b9192a2f463bf2192f78737dadbba894d578c6f..05c9faaf2e5bcdaeb8be6e302830874906283dbc 100644 (file)
@@ -3,3 +3,5 @@
 #CFLAGS += -Wall -D_REENTRANT -g
 #SUBDIRS= fwp_msgtest fwp_vrestest fwp_prototest fwp_mngrtest  
 #fwp_mngrtest unixsocktest
+
+SUBDIRS+=timing
diff --git a/fwp/tests/timing/Makefile b/fwp/tests/timing/Makefile
new file mode 100644 (file)
index 0000000..b22a357
--- /dev/null
@@ -0,0 +1,14 @@
+# Generic directory or leaf node makefile for OCERA make framework
+
+ifndef MAKERULES_DIR
+MAKERULES_DIR := $(shell ( old_pwd="" ;  while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd`  ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) )
+endif
+
+ifeq ($(MAKERULES_DIR),)
+all : default
+.DEFAULT::
+       @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n"
+else
+include $(MAKERULES_DIR)/Makefile.rules
+endif
+
diff --git a/fwp/tests/timing/Makefile.omk b/fwp/tests/timing/Makefile.omk
new file mode 100644 (file)
index 0000000..57aac08
--- /dev/null
@@ -0,0 +1,3 @@
+test_PROGRAMS = fwp-timing
+fwp-timing_SOURCES = fwp-timing.c
+lib_LOADLIBES = frsh
diff --git a/fwp/tests/timing/fwp-timing.c b/fwp/tests/timing/fwp-timing.c
new file mode 100644 (file)
index 0000000..d344489
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * A tool for measuring FWP latency. This program aims to be simpler
+ * than wme_test and is intended to be run on a single machine with
+ * multiple wifi interfaces and send-to-self kernel patch applied.
+ *
+ * This program creates both sides of communication and measures the
+ * communication delays.
+ */
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <frsh.h>
+#include <getopt.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <fwp_res.h>
+#include <error.h>
+#include <sys/mman.h>
+
+int opt_budget = 1024;
+int opt_period = 20;
+
+struct in_addr src, dst;
+
+void set_rt_prio(int priority)
+{
+       int maxpri, minpri;
+       static struct sched_param param;
+
+       if ((maxpri = sched_get_priority_max(SCHED_FIFO)) == -1)        {
+               fprintf(stderr, "warning: sched_get_priority_max failed");
+       }
+
+       if ((minpri = sched_get_priority_min(SCHED_FIFO)) == -1)        {
+               fprintf(stderr, "warning: sched_get_priority_min failed");
+       }
+
+       if (priority > maxpri)  {
+               fprintf(stderr, "warning: maximum priority allowed is %d.\n", maxpri);
+       }
+       if (priority < minpri)  {
+               fprintf(stderr, "warning: minimum priority allowed is %d.\n", minpri);
+       }
+
+       param.sched_priority = priority;
+
+       if (sched_setscheduler(0, SCHED_FIFO, &param) == -1)    {
+               fprintf(stderr, "warning: sched_setscheduler failed");
+       }
+
+       mlockall(MCL_CURRENT | MCL_FUTURE);
+}
+
+
+int negotiate_contract(frsh_vres_id_t *vres)
+{
+       frsh_contract_t contract;
+       int ret;
+       frsh_rel_time_t period;
+       frsh_rel_time_t budget;
+       frsh_rel_time_t deadline;
+       fres_block_fwp *fwp;    
+       
+       ret = frsh_contract_init(&contract);
+       if (ret) PERROR_AND_EXIT(ret, "frsh_contract_init");
+
+       ret = frsh_contract_set_resource_and_label(
+               &contract,
+               FRSH_RT_NETWORK, FRSH_NETPF_FWP,
+               NULL);
+       if (ret) PERROR_AND_EXIT(ret, "frsh_contract_set_resource_and_label");
+
+       frsh_network_bytes_to_budget(FRSH_NETPF_FWP, opt_budget, &budget);
+       period = fosa_msec_to_rel_time(opt_period);
+       ret = frsh_contract_set_basic_params(&contract,
+                                            &budget,
+                                            &period,
+                                            FRSH_WT_BOUNDED,
+                                            FRSH_CT_REGULAR);
+       if (ret) PERROR_AND_EXIT(ret, "frsh_contract_set_basic_params");
+
+
+       /* FWP doesn't accept smaller deadlines than 30 ms. */
+       if (frsh_rel_time_smaller(period, frsh_msec_to_rel_time(30)))
+               deadline = frsh_msec_to_rel_time(30);
+       else
+               deadline = period;
+       ret = frsh_contract_set_timing_reqs(&contract, false, &deadline);
+       if (ret) PERROR_AND_EXIT(ret, "frsh_contract_set_timing_reqs");
+
+       fwp = malloc(sizeof(*fwp));
+       if (!fwp) PERROR_AND_EXIT(errno, "malloc");
+       fwp->src = src.s_addr;
+       ret = fres_contract_add_fwp(contract, fwp);
+       if (ret) PERROR_AND_EXIT(ret, "fres_contract_add_fwp");
+
+       ret = frsh_contract_negotiate(&contract, vres);
+       if (ret) PERROR_AND_EXIT(ret, "frsh_contract_negotiate");
+
+       frsh_contract_destroy(&contract);
+
+       return 0;
+}
+
+void create_endpoints(frsh_vres_id_t vres,
+                     frsh_send_endpoint_t *epsrc,
+                     frsh_receive_endpoint_t *epdst)
+{
+       int ret;
+       frsh_send_endpoint_protocol_info_t    spi = { NULL, 0 };
+       frsh_receive_endpoint_protocol_info_t rpi = { NULL, 0 };
+       frsh_endpoint_queueing_info_t qi = { .queue_size=0,
+                                            .queue_policy=FRSH_QRP_OLDEST };
+
+       ret = frsh_receive_endpoint_create(FRSH_NETPF_FWP, 0, qi, rpi,
+                                          epdst);
+       if (ret != 0) error(1, errno, "fwp_receive_endpoint_create");
+               
+       unsigned int port;
+       frsh_receive_endpoint_get_params(*epdst, NULL, &port, NULL, NULL);
+
+       ret = frsh_send_endpoint_create(FRSH_NETPF_FWP,
+                                       dst.s_addr, port, spi,
+                                       epsrc);
+       if (ret < 0) error(1, errno, "frsh_send_endpoint_create()");
+               
+       ret = frsh_send_endpoint_bind(vres, *epsrc);
+       if (ret != 0) error(1, errno, "frsh_send_endpoint_bind");
+}
+
+
+static struct option long_opts[] = {
+    { "period", 1, 0, 'p' },
+    { "budget", 1, 0, 'b' },
+    { "source", 1, 0, 's' },
+    { "dest",  1, 0, 'd' },
+    { 0, 0, 0, 0}
+};
+
+static void
+usage(void)
+{
+       printf("usage: fwp-timing [ options ]\n");
+       printf("  -p, --period <ms>  period in miliseconds\n");
+       printf("  -b, --budget <bytes>  how many bytes is sent in each period\n");
+       printf("  -s, --source <ip>  source IP address\n");
+       printf("  -d, --dest <ip:port> destination IP address and port\n");
+}
+
+void parse_opts(int argc, char *argv[])
+{
+       char opt;
+       int ret;
+
+       while ((opt = getopt_long(argc, argv, "b:p:s:d:", long_opts, NULL)) != -1) {
+               switch (opt) {
+               case 'b':
+                       opt_budget = atoi(optarg);
+                       break;
+               case 'p':
+                       opt_period = atoi(optarg);
+                       break;
+               case 's':
+                       ret = inet_aton(optarg, &src);
+                       if (!ret) {
+                               fprintf(stderr, "Source IP address not recognized: %s\n",
+                                       optarg);
+                               usage();
+                               exit(1);
+                       }
+                       break;
+               case 'd':
+                       ret = inet_aton(optarg, &dst);
+                       if (!ret) {
+                               fprintf(stderr, "Destination IP address not recognized: %s\n",
+                                       optarg);
+                               usage();
+                               exit(1);
+                       }
+                       break;
+               default:
+                       usage();
+                       exit(1);
+               }
+       }
+}
+
+volatile bool exit_flag = false;
+
+void stopper()
+{
+       exit_flag = true;
+}
+
+int
+timespec_subtract (result, x, y)
+     struct timespec *result, *x, *y;
+{
+  /* Perform the carry for the later subtraction by updating Y. */
+  if (x->tv_nsec < y->tv_nsec) {
+    int nsec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1;
+    y->tv_nsec -= 1000000000 * nsec;
+    y->tv_sec += nsec;
+  }
+  if (x->tv_nsec - y->tv_nsec > 1000000000) {
+    int nsec = (x->tv_nsec - y->tv_nsec) / 1000000000;
+    y->tv_nsec += 1000000000 * nsec;
+    y->tv_sec -= nsec;
+  }
+
+  /* Compute the time remaining to wait.
+     `tv_nsec' is certainly positive. */
+  result->tv_sec = x->tv_sec - y->tv_sec;
+  result->tv_nsec = x->tv_nsec - y->tv_nsec;
+
+  /* Return 1 if result is negative. */
+  return x->tv_sec < y->tv_sec;
+}
+
+static inline double ts2d(struct timespec *ts)
+{
+       return ts->tv_sec + 1e-9*ts->tv_nsec;
+}
+
+static inline double tsdiff2d(struct timespec *x,
+                             struct timespec *y)
+{
+       struct timespec r;
+       timespec_subtract(&r, x, y);
+       return ts2d(&r);
+}
+
+struct msg {
+       int cnt;
+       struct timespec ts;
+};
+
+void *receiver(void *arg)
+{
+       frsh_receive_endpoint_t epdst = (frsh_receive_endpoint_t)arg;
+       size_t mlen;
+       int ret;
+       struct timespec tss, tsr;
+       struct msg *msg;
+       msg = malloc(opt_budget);
+       if (!msg) error(1, errno, "malloc msg");
+
+       while (!exit_flag) {
+               ret = frsh_receive_sync(epdst, msg, opt_budget, &mlen, NULL);
+               clock_gettime(CLOCK_MONOTONIC, &tsr);
+               tss = msg->ts;
+               printf("%10d: %10.3lf ms\n",
+                      msg->cnt, tsdiff2d(&tsr, &tss)*1000);
+       }
+       return NULL;
+}
+
+void run()
+{
+       frsh_vres_id_t vres;
+       frsh_send_endpoint_t epsrc;
+       frsh_receive_endpoint_t epdst;
+       int ret;
+       struct msg *msg;
+       long int cnt=0;
+       pthread_t receiver_id;
+
+       msg = malloc(opt_budget);
+       if (!msg) error(1, errno, "malloc msg");
+
+       ret = frsh_init();
+       if (ret) PERROR_AND_EXIT(ret, "frsh_init");
+       
+       negotiate_contract(&vres);
+       create_endpoints(vres, &epsrc, &epdst);
+
+       set_rt_prio(50);
+
+       ret = pthread_create(&receiver_id, NULL, receiver, epdst);
+       
+       if (signal(SIGTERM, stopper) == SIG_ERR)
+               error(1, errno, "Error in signal registration");
+       if (signal(SIGINT, stopper) == SIG_ERR)
+               error(1, errno, "Signal handler registration error");
+
+       struct timespec next_period, tss;
+       clock_gettime(CLOCK_MONOTONIC, &next_period);
+       while (!exit_flag) {
+               clock_gettime(CLOCK_MONOTONIC, &tss);
+               msg->cnt = cnt++;
+               msg->ts = tss;
+               ret = frsh_send_async(epsrc, msg, opt_budget);
+
+               next_period.tv_nsec += opt_period * 1000000;
+               if (next_period.tv_nsec >= 1000000000) {
+                       next_period.tv_nsec -= 1000000000;
+                       next_period.tv_sec++;
+               }
+
+               clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME,
+                               &next_period, NULL);
+       }
+       
+       frsh_contract_cancel(vres);
+}
+
+int main(int argc, char *argv[])
+{
+       src.s_addr = htonl(INADDR_LOOPBACK);
+       dst.s_addr = htonl(INADDR_LOOPBACK);
+       
+       parse_opts(argc, argv);
+       run();
+       return 0;
+}