Author: luigi
Date: Thu May 30 11:10:42 2013
New Revision: 251132
URL: http://svnweb.freebsd.org/changeset/base/251132

Log:
  add support for rate-limiting in the sender (-R ...)
  
  Obtained from:        Giuseppe Lettieri

Modified:
  head/tools/tools/netmap/pkt-gen.c

Modified: head/tools/tools/netmap/pkt-gen.c
==============================================================================
--- head/tools/tools/netmap/pkt-gen.c   Thu May 30 11:09:41 2013        
(r251131)
+++ head/tools/tools/netmap/pkt-gen.c   Thu May 30 11:10:42 2013        
(r251132)
@@ -25,7 +25,7 @@
 
 /*
  * $FreeBSD$
- * $Id: pkt-gen.c 12024 2013-01-25 05:41:51Z luigi $
+ * $Id$
  *
  * Example program to show how to build a multithreaded packet
  * source/sink using the netmap device.
@@ -89,6 +89,9 @@ struct glob_arg {
        int dev_type;
        pcap_t *p;
 
+       int tx_rate;
+       struct timespec tx_period;
+
        int affinity;
        int main_fd;
        int report_interval;
@@ -114,7 +117,7 @@ struct targ {
        struct netmap_if *nifp;
        uint16_t        qfirst, qlast; /* range of queues to scan */
        volatile uint64_t count;
-       struct timeval tic, toc;
+       struct timespec tic, toc;
        int me;
        pthread_t thread;
        int affinity;
@@ -669,6 +672,76 @@ ponger_body(void *data)
        return NULL;
 }
 
+static __inline int
+timespec_ge(const struct timespec *a, const struct timespec *b)
+{
+
+       if (a->tv_sec > b->tv_sec)
+               return (1);
+       if (a->tv_sec < b->tv_sec)
+               return (0);
+       if (a->tv_nsec >= b->tv_nsec)
+               return (1);
+       return (0);
+}
+
+static __inline struct timespec
+timeval2spec(const struct timeval *a)
+{
+       struct timespec ts = {
+               .tv_sec = a->tv_sec,
+               .tv_nsec = a->tv_usec * 1000
+       };
+       return ts;
+}
+
+static __inline struct timeval
+timespec2val(const struct timespec *a)
+{
+       struct timeval tv = {
+               .tv_sec = a->tv_sec,
+               .tv_usec = a->tv_nsec / 1000
+       };
+       return tv;
+}
+
+
+static int
+wait_time(struct timespec ts, struct timespec *wakeup_ts, long long *waited)
+{
+       struct timespec curtime;
+
+       curtime.tv_sec = 0;
+       curtime.tv_nsec = 0;
+
+       if (clock_gettime(CLOCK_REALTIME_PRECISE, &curtime) == -1) {
+               D("clock_gettime: %s", strerror(errno));
+               return (-1);
+       }
+       while (timespec_ge(&ts, &curtime)) {
+               if (waited != NULL)
+                       (*waited)++;
+               if (clock_gettime(CLOCK_REALTIME_PRECISE, &curtime) == -1) {
+                       D("clock_gettime");
+                       return (-1);
+               }
+       }
+       if (wakeup_ts != NULL)
+               *wakeup_ts = curtime;
+       return (0);
+}
+
+static __inline void
+timespec_add(struct timespec *tsa, struct timespec *tsb)
+{
+       tsa->tv_sec += tsb->tv_sec;
+       tsa->tv_nsec += tsb->tv_nsec;
+       if (tsa->tv_nsec >= 1000000000) {
+               tsa->tv_sec++;
+               tsa->tv_nsec -= 1000000000;
+       }
+}
+
 
 static void *
 sender_body(void *data)
@@ -680,7 +753,10 @@ sender_body(void *data)
        struct netmap_ring *txring;
        int i, n = targ->g->npackets / targ->g->nthreads, sent = 0;
        int options = targ->g->options | OPT_COPY;
-D("start");
+       struct timespec tmptime, nexttime = { 0, 0}; // XXX silence compiler
+       int rate_limit = targ->g->tx_rate;
+       long long waited = 0;
+       D("start");
        if (setaffinity(targ->thread, targ->affinity))
                goto quit;
        /* setup poll(2) mechanism. */
@@ -689,8 +765,18 @@ D("start");
        fds[0].events = (POLLOUT);
 
        /* main loop.*/
-       gettimeofday(&targ->tic, NULL);
-
+       clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic);
+       if (rate_limit) {
+               tmptime.tv_sec = 2;
+               tmptime.tv_nsec = 0;
+               timespec_add(&targ->tic, &tmptime);
+               targ->tic.tv_nsec = 0;
+               if (wait_time(targ->tic, NULL, NULL) == -1) {
+                       D("wait_time: %s", strerror(errno));
+                       goto quit;
+               }
+               nexttime = targ->tic;
+       }
     if (targ->g->dev_type == DEV_PCAP) {
            int size = targ->g->pkt_size;
            void *pkt = &targ->pkt;
@@ -718,8 +804,18 @@ D("start");
                }
            }
     } else {
+       int tosend = 0;
        while (!targ->cancel && (n == 0 || sent < n)) {
 
+               if (rate_limit && tosend <= 0) {
+                       tosend = targ->g->burst;
+                       timespec_add(&nexttime, &targ->g->tx_period);
+                       if (wait_time(nexttime, &tmptime, &waited) == -1) {
+                               D("wait_time");
+                               goto quit;
+                       }
+               }
+
                /*
                 * wait for available room in the send queue(s)
                 */
@@ -737,7 +833,7 @@ D("start");
                        options &= ~OPT_COPY;
                }
                for (i = targ->qfirst; i < targ->qlast; i++) {
-                       int m, limit = targ->g->burst;
+                       int m, limit = rate_limit ?  tosend : targ->g->burst;
                        if (n > 0 && n - sent < limit)
                                limit = n - sent;
                        txring = NETMAP_TXRING(nifp, i);
@@ -746,6 +842,7 @@ D("start");
                        m = send_packets(txring, &targ->pkt, targ->g->pkt_size,
                                         limit, options);
                        sent += m;
+                       tosend -= m;
                        targ->count = sent;
                }
        }
@@ -762,7 +859,7 @@ D("start");
        }
     }
 
-       gettimeofday(&targ->toc, NULL);
+       clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc);
        targ->completed = 1;
        targ->count = sent;
 
@@ -834,7 +931,7 @@ receiver_body(void *data)
        }
 
        /* main loop, exit after 1s silence */
-       gettimeofday(&targ->tic, NULL);
+       clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic);
     if (targ->g->dev_type == DEV_PCAP) {
        while (!targ->cancel) {
                /* XXX should we poll ? */
@@ -852,8 +949,8 @@ receiver_body(void *data)
        while (!targ->cancel) {
                /* Once we started to receive packets, wait at most 1 seconds
                   before quitting. */
-               if (poll(fds, 1, 1 * 1000) <= 0 && targ->g->forever == 0) {
-                       gettimeofday(&targ->toc, NULL);
+               if (poll(fds, 1, 1 * 1000) <= 0 && !targ->g->forever) {
+                       clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc);
                        targ->toc.tv_sec -= 1; /* Subtract timeout time. */
                        break;
                }
@@ -1085,11 +1182,13 @@ main_thread(struct glob_arg *g)
        timerclear(&tic);
        timerclear(&toc);
        for (i = 0; i < g->nthreads; i++) {
+               struct timespec t_tic, t_toc;
                /*
                 * Join active threads, unregister interfaces and close
                 * file descriptors.
                 */
-               pthread_join(targs[i].thread, NULL);
+               if (targs[i].used)
+                       pthread_join(targs[i].thread, NULL);
                close(targs[i].fd);
 
                if (targs[i].completed == 0)
@@ -1100,10 +1199,12 @@ main_thread(struct glob_arg *g)
                 * how long it took to send all the packets.
                 */
                count += targs[i].count;
-               if (!timerisset(&tic) || timercmp(&targs[i].tic, &tic, <))
-                       tic = targs[i].tic;
-               if (!timerisset(&toc) || timercmp(&targs[i].toc, &toc, >))
-                       toc = targs[i].toc;
+               t_tic = timeval2spec(&tic);
+               t_toc = timeval2spec(&toc);
+               if (!timerisset(&tic) || timespec_ge(&targs[i].tic, &t_tic))
+                       tic = timespec2val(&targs[i].tic);
+               if (!timerisset(&toc) || timespec_ge(&targs[i].toc, &t_toc))
+                       toc = timespec2val(&targs[i].toc);
        }
 
        /* print output. */
@@ -1115,7 +1216,6 @@ main_thread(struct glob_arg *g)
                rx_output(count, delta_t);
 
        if (g->dev_type == DEV_NETMAP) {
-               ioctl(g->main_fd, NIOCUNREGIF, NULL); // XXX deprecated
                munmap(g->mmap_addr, g->mmap_size);
                close(g->main_fd);
        }
@@ -1224,9 +1324,10 @@ main(int arc, char **argv)
        g.burst = 512;          // default
        g.nthreads = 1;
        g.cpus = 1;
+       g.tx_rate = 0;
 
        while ( (ch = getopt(arc, argv,
-                       "a:f:n:i:t:r:l:d:s:D:S:b:c:o:p:PT:w:Wv")) != -1) {
+                       "a:f:n:i:t:r:l:d:s:D:S:b:c:o:p:PT:w:WvR:")) != -1) {
                struct sf *fn;
 
                switch(ch) {
@@ -1325,6 +1426,10 @@ main(int arc, char **argv)
                        break;
                case 'v':
                        verbose++;
+                       break;
+               case 'R':
+                       g.tx_rate = atoi(optarg);
+                       break;
                }
        }
 
@@ -1473,6 +1578,23 @@ main(int arc, char **argv)
                        g.options & OPT_MEMCPY ? " memcpy" : "",
                        g.options & OPT_COPY ? " copy" : "");
        }
+       
+       if (g.tx_rate == 0) {
+               g.tx_period.tv_sec = 0;
+               g.tx_period.tv_nsec = 0;
+       } else if (g.tx_rate == 1) {
+               g.tx_period.tv_sec = 1;
+               g.tx_period.tv_nsec = 0;
+       } else {
+               g.tx_period.tv_sec = 0;
+               g.tx_period.tv_nsec = (1e9 / g.tx_rate) * g.burst;
+               if (g.tx_period.tv_nsec > 1000000000) {
+                       g.tx_period.tv_sec = g.tx_period.tv_nsec / 1000000000;
+                       g.tx_period.tv_nsec = g.tx_period.tv_nsec % 1000000000;
+               }
+       }
+       D("Sending %d packets every  %d.%09d ns",
+                       g.burst, (int)g.tx_period.tv_sec, 
(int)g.tx_period.tv_nsec);
        /* Wait for PHY reset. */
        D("Wait %d secs for phy reset", wait_link);
        sleep(wait_link);
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to