Implement recvmmsg/sendmmsg gateway
authorMichal Sojka <sojkam1@fel.cvut.cz>
Mon, 20 Jan 2014 15:10:04 +0000 (16:10 +0100)
committerMichal Sojka <sojkam1@fel.cvut.cz>
Mon, 20 Jan 2014 15:10:04 +0000 (16:10 +0100)
ugw/data/bench-all.sh
ugw/data/plot-thr.gp
ugw/data/preprocess.m
ugw/ugw.c

index 78e560a..deb38c4 100755 (executable)
@@ -33,7 +33,7 @@ while [ "${1#-}" != "$1" ]; do
     shift
 done
 
-methods=${@:-rtems kernel read-write readnb-write readnb-mmap read-mmap mmap-write mmap-mmap mmapbusy-write mmapbusy-mmap readbusy-write readbusynoirq-write}
+methods=${@:-rtems kernel read-write readnb-write readnb-mmap read-mmap mmap-write mmap-mmap mmapbusy-write mmapbusy-mmap readbusy-write readbusynoirq-write mmsg-mmsg}
 
 set -x
 for method in $methods; do
@@ -50,6 +50,7 @@ for method in $methods; do
        mmapbusy-mmap)  ../ppc/boot -a "ugw=|-r mmapbusy -t mmap|" --exiton "UGW started";;
        readbusy-write) ../ppc/boot -a "ugw=|-b 300|" --exiton "UGW started";;
        readbusynoirq-write) ../ppc/boot -a "ugw=|-b 300|" --kernel uImage.noirq --exiton "UGW started";;
+       mmsg-mmsg)      ../ppc/boot -a "ugw=|-r mmsg -t mmsg|" --exiton "UGW started";;
        *)
            echo >&2 "Unknown method '$method'";
            exit 1;
index 8eb1a71..8eb0840 100755 (executable)
@@ -15,6 +15,7 @@ set grid
 loss_scale=3
 plot \
      'kernel.dat' using 1:2:($3*loss_scale) title 'kernel', \
+     'mmsg-mmsg.dat' using 1:2:($3*loss_scale) title 'mmsg-mmsg', \
      'mmap-mmap.dat' using 1:2:($3*loss_scale) title 'mmap-mmap', \
      'mmapbusy-mmap.dat' using 1:2:($3*loss_scale) title 'mmapbusy-mmap', \
      'mmap-write.dat' using 1:2:($3*loss_scale) title 'mmap-write', \
index b9a557f..242798b 100755 (executable)
@@ -15,6 +15,7 @@ datafiles = {
             "read-write.dat"
             "mmap-write.dat"
             "mmap-mmap.dat"
+            "mmsg-mmsg.dat"
 };
 
 quantiles = [0 0.5 0.90 0.99];
index 876d9ce..a5c1e7c 100644 (file)
--- a/ugw/ugw.c
+++ b/ugw/ugw.c
@@ -33,6 +33,8 @@
 #define BLOCK_NR 2
 #define FRAME_NR (BLOCK_NR*(BLOCK_SIZE/FRAME_SIZE))
 
+#define MMSG_MAX 64
+
 #define STRINGIFY(val) #val
 #define TOSTRING(val) STRINGIFY(val)
 #define CHECK(cmd) ({ int ret = (cmd); if (ret == -1) { perror(#cmd " line " TOSTRING(__LINE__)); exit(1); }; ret; })
@@ -41,7 +43,7 @@
 char *devin = "can0";
 char *devout = "can1";
 enum { IN_READ, IN_RECVMMSG, IN_MMAP, IN_MMAPBUSY } in_method = IN_READ;
-enum { WRITE, OUT_MMAP } out_method = WRITE;
+enum { WRITE, OUT_MMAP, OUT_SENDMMSG } out_method = WRITE;
 bool quiet = false;
 int busy_poll_us = 0;
 bool nonblocking = false;
@@ -57,19 +59,31 @@ enum in2out {
 
 struct in_ctx {
        int s;
+       enum in2out (*in_fn)(struct in_ctx *ctx, struct can_frame *cf);
+       /* mmap */
        void *ptr;
        int hdrlen;
        int current;
-       enum in2out (*in_fn)(struct in_ctx *ctx, struct can_frame *cf);
+       /* mmsg */
+       int received;
+       struct mmsghdr msgs[MMSG_MAX];
+       struct iovec iovecs[MMSG_MAX];
+       char bufs[MMSG_MAX][sizeof(struct can_frame)];
 };
 
 struct out_ctx {
        int s;
        enum in2out from_in;
+       int (*out_fn)(struct out_ctx *ctx, struct can_frame *cf);
+       /* mmap */
        void *ptr;
        int hdrlen;
        int current;
-       int (*out_fn)(struct out_ctx *ctx, struct can_frame *cf);
+       /* mmsg */
+       int stored;
+       struct mmsghdr msgs[MMSG_MAX];
+       struct iovec iovecs[MMSG_MAX];
+       char bufs[MMSG_MAX][sizeof(struct can_frame)];
 };
 
 struct stats {
@@ -132,6 +146,41 @@ void init_read(struct in_ctx *ctx)
        ctx->in_fn = in_read;
 }
 
+enum in2out in_recvmmsg(struct in_ctx *ctx, struct can_frame *cf)
+{
+       int ret;
+
+       if (ctx->current >= ctx->received) {
+               ret = CHECK(recvmmsg(ctx->s, ctx->msgs, MMSG_MAX, MSG_WAITFORONE, NULL));
+               if (nonblocking && ret == -1 && errno == EAGAIN)
+                       return NOP;
+               ctx->received = ret;
+               ctx->current = 0;
+       }
+
+       memcpy(cf, ctx->bufs[ctx->current], sizeof(struct can_frame));
+       ctx->current++;
+
+       return (ctx->current < ctx->received) ? STORE_ONLY : SEND;
+}
+
+void init_recvmmg(struct in_ctx *ctx)
+{
+       int i;
+
+       init_read(ctx);
+       ctx->in_fn = in_recvmmsg;
+       ctx->current = 0;
+       memset(ctx->msgs, 0, sizeof(ctx->msgs));
+       memset(ctx->iovecs, 0, sizeof(ctx->iovecs));
+       for (i = 0; i < MMSG_MAX; i++) {
+               ctx->iovecs[i].iov_base         = ctx->bufs[i];
+               ctx->iovecs[i].iov_len          = sizeof(struct can_frame);
+               ctx->msgs[i].msg_hdr.msg_iov    = &ctx->iovecs[i];
+               ctx->msgs[i].msg_hdr.msg_iovlen = 1;
+       }
+}
+
 enum in2out in_packet_rx(struct in_ctx *ctx, struct can_frame *cf)
 {
        volatile struct tpacket2_hdr *hdr = ctx->ptr + ctx->current*FRAME_SIZE;
@@ -233,6 +282,42 @@ void init_write(struct out_ctx *ctx)
        ctx->out_fn = out_write;
 }
 
+int out_sendmmsg(struct out_ctx *ctx, struct can_frame *cf)
+{
+       if (ctx->from_in == NOP)
+               return 0;
+
+       memcpy(ctx->bufs[ctx->current++], cf, sizeof(*cf));
+
+       if (ctx->from_in == SEND ||
+           ctx->current >= MMSG_MAX) {
+               int ret, i;
+               for (i = 0; i < ctx->current; i += ret)
+                       ret = CHECK(sendmmsg(ctx->s, &ctx->msgs[i], ctx->current - i, 0));
+               ctx->current = 0;
+       }
+       return 0;
+}
+
+void init_sendmmsg(struct out_ctx *ctx)
+{
+       int i;
+
+       init_write(ctx);
+       ctx->out_fn = out_sendmmsg;
+       ctx->current = 0;
+       ctx->stored = 0;
+
+       memset(ctx->msgs, 0, sizeof(ctx->msgs));
+       memset(ctx->iovecs, 0, sizeof(ctx->iovecs));
+       for (i = 0; i < MMSG_MAX; i++) {
+               ctx->iovecs[i].iov_base         = &ctx->bufs[i];
+               ctx->iovecs[i].iov_len          = sizeof(struct can_frame);
+               ctx->msgs[i].msg_hdr.msg_iov    = &ctx->iovecs[i];
+               ctx->msgs[i].msg_hdr.msg_iovlen = 1;
+       }
+}
+
 int out_packet_tx(struct out_ctx *ctx, struct can_frame *cf)
 {
        volatile struct tpacket2_hdr *hdr = ctx->ptr + ctx->current*FRAME_SIZE;
@@ -305,6 +390,9 @@ void init_in(struct in_ctx *in)
        case IN_READ:
                init_read(in);
                break;
+       case IN_RECVMMSG:
+               init_recvmmg(in);
+               break;
        case IN_MMAP:
        case IN_MMAPBUSY:
                init_packet_rx(in);
@@ -325,6 +413,7 @@ void init_out(struct out_ctx *out)
        memset(out, 0, sizeof(*out));
        switch (out_method) {
        case WRITE: init_write(out); break;
+       case OUT_SENDMMSG: init_sendmmsg(out); break;
        case OUT_MMAP: init_packet_tx(out); break;
        default:
                fprintf(stderr, "Unknown \"out method\" %d\n", out_method);
@@ -382,6 +471,8 @@ int main(int argc, char *argv[])
                                in_method = IN_MMAP;
                        else if (strcmp(optarg, "mmapbusy") == 0)
                                in_method = IN_MMAPBUSY;
+                       else if (strcmp(optarg, "mmsg") == 0)
+                               in_method = IN_RECVMMSG;
                        else {
                                fprintf(stderr, "Unsuported RX method: %s\n", optarg);
                                exit(1);
@@ -392,6 +483,8 @@ int main(int argc, char *argv[])
                                out_method = WRITE;
                        else if (strcmp(optarg, "mmap") == 0)
                                out_method = OUT_MMAP;
+                       else if (strcmp(optarg, "mmsg") == 0)
+                               out_method = OUT_SENDMMSG;
                        else {
                                fprintf(stderr, "Unsuported TX method: %s\n", optarg);
                                exit(1);