> Date: Mon, 18 Apr 2016 10:50:46 +0200
> From: Martin Pieuchot <m...@openbsd.org>
> 
> The current goal of the Network SMP effort is to have a single CPU
> process the IP forwarding path in a process context without holding
> the KERNEL_LOCK().  To achieve this goal we're progressively moving
> code from the softnet interrupt context to the if_input_task.  In
> the end we'll completely get rid of this soft-interrupt.
> 
> So now would be a good time to know if moving all the code currently
> run in a soft-interrupt context to a task uncovers any bug.  I'm
> happily running the diff below on amd64 and macppc, it even gives me
> a small performance boost.
> 
> I'd appreciate more tests especially on exotic archs.

Yes, please test this.  And report back how this changes the results
of your favourite benchmark.

However, this diff uses the same taskq for both the "unlocked" and
"locked" parts.  My experience with crypto code was that frequently
grabbing and releasing the kernel lock did affect latency in a bad
way.  Some time ago dlg@ had a somewhat similar diff that had a
separate taskq for the "locked" bits.  That would avoid blocking of
the "unlocked" bits when the "locked" code is grabbing the kernel
lock.  Of course such an approach would probably introduce additional
context switches.  Did you consider such an approach?


> Index: net/if.c
> ===================================================================
> RCS file: /cvs/src/sys/net/if.c,v
> retrieving revision 1.429
> diff -u -p -r1.429 if.c
> --- net/if.c  16 Mar 2016 12:08:09 -0000      1.429
> +++ net/if.c  18 Apr 2016 08:00:08 -0000
> @@ -64,9 +64,12 @@
>  #include "bpfilter.h"
>  #include "bridge.h"
>  #include "carp.h"
> +#include "ether.h"
>  #include "pf.h"
> +#include "pfsync.h"
> +#include "ppp.h"
> +#include "pppoe.h"
>  #include "trunk.h"
> -#include "ether.h"
>  
>  #include <sys/param.h>
>  #include <sys/systm.h>
> @@ -148,6 +151,7 @@ int       if_group_egress_build(void);
>  void if_watchdog_task(void *);
>  
>  void if_input_process(void *);
> +void if_netisr(void *);
>  
>  #ifdef DDB
>  void ifa_print_all(void);
> @@ -216,13 +220,15 @@ void    net_tick(void *);
>  int  net_livelocked(void);
>  int  ifq_congestion;
>  
> -struct taskq *softnettq;
> +int           netisr;
> +struct taskq *softnettq;
> +
> +struct mbuf_queue if_input_queue = MBUF_QUEUE_INITIALIZER(8192, IPL_NET);
> +struct task if_input_task = TASK_INITIALIZER(if_input_process, 
> &if_input_queue);
> +struct task if_input_task_locked = TASK_INITIALIZER(if_netisr, NULL);
>  
>  /*
>   * Network interface utility routines.
> - *
> - * Routines with ifa_ifwith* names take sockaddr *'s as
> - * parameters.
>   */
>  void
>  ifinit(void)
> @@ -590,9 +596,6 @@ if_enqueue(struct ifnet *ifp, struct mbu
>       return (0);
>  }
>  
> -struct mbuf_queue if_input_queue = MBUF_QUEUE_INITIALIZER(8192, IPL_NET);
> -struct task if_input_task = TASK_INITIALIZER(if_input_process, 
> &if_input_queue);
> -
>  void
>  if_input(struct ifnet *ifp, struct mbuf_list *ml)
>  {
> @@ -803,6 +806,50 @@ if_input_process(void *xmq)
>               if_put(ifp);
>       }
>       splx(s);
> +}
> +
> +void
> +if_netisr(void *unused)
> +{
> +     int n, t = 0;
> +     int s;
> +
> +     KERNEL_LOCK();
> +     s = splsoftnet();
> +
> +     while ((n = netisr) != 0) {
> +             sched_pause();
> +
> +             atomic_clearbits_int(&netisr, n);
> +
> +             if (n & (1 << NETISR_IP))
> +                     ipintr();
> +#ifdef INET6
> +             if (n & (1 << NETISR_IPV6))
> +                     ip6intr();
> +#endif
> +#if NPPP > 0
> +             if (n & (1 << NETISR_PPP))
> +                     pppintr();
> +#endif
> +#if NBRIDGE > 0
> +             if (n & (1 << NETISR_BRIDGE))
> +                     bridgeintr();
> +#endif
> +#if NPPPOE > 0
> +             if (n & (1 << NETISR_PPPOE))
> +                     pppoeintr();
> +#endif
> +             t |= n;
> +     }
> +
> +#if NPFSYNC > 0
> +     if (t & (1 << NETISR_PFSYNC))
> +             pfsyncintr();
> +#endif
> +
> +     splx(s);
> +     KERNEL_UNLOCK();
>  }
>  
>  void
> Index: net/netisr.c
> ===================================================================
> RCS file: net/netisr.c
> diff -N net/netisr.c
> --- net/netisr.c      8 Jan 2016 13:53:24 -0000       1.10
> +++ /dev/null 1 Jan 1970 00:00:00 -0000
> @@ -1,74 +0,0 @@
> -/*
> - * Copyright (c) 2010 Owain G. Ainsworth <o...@openbsd.org>
> - *
> - * Permission to use, copy, modify, and distribute this software for any
> - * purpose with or without fee is hereby granted, provided that the above
> - * copyright notice and this permission notice appear in all copies.
> - *
> - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> - */
> -#include <sys/param.h>
> -#include <sys/systm.h>
> -
> -#include <net/netisr.h>
> -
> -#include <machine/intr.h>
> -
> -#include "ppp.h"
> -#include "bridge.h"
> -#include "pppoe.h"
> -#include "pfsync.h"
> -
> -void  netintr(void *);
> -
> -int   netisr;
> -void *netisr_intr;
> -
> -void
> -netintr(void *unused)
> -{
> -     int n, t = 0;
> -
> -     while ((n = netisr) != 0) {
> -             atomic_clearbits_int(&netisr, n);
> -
> -             if (n & (1 << NETISR_IP))
> -                     ipintr();
> -#ifdef INET6
> -             if (n & (1 << NETISR_IPV6))
> -                     ip6intr();
> -#endif
> -#if NPPP > 0
> -             if (n & (1 << NETISR_PPP))
> -                     pppintr();
> -#endif
> -#if NBRIDGE > 0
> -             if (n & (1 << NETISR_BRIDGE))
> -                     bridgeintr();
> -#endif
> -#if NPPPOE > 0
> -             if (n & (1 << NETISR_PPPOE))
> -                     pppoeintr();
> -#endif
> -             t |= n;
> -     }
> -
> -#if NPFSYNC > 0
> -     if (t & (1 << NETISR_PFSYNC))
> -             pfsyncintr();
> -#endif
> -}
> -
> -void
> -netisr_init(void)
> -{
> -     netisr_intr = softintr_establish(IPL_SOFTNET, netintr, NULL);
> -     if (netisr_intr == NULL)
> -             panic("can't establish softnet handler");
> -}
> Index: net/netisr.h
> ===================================================================
> RCS file: /cvs/src/sys/net/netisr.h,v
> retrieving revision 1.44
> diff -u -p -r1.44 netisr.h
> --- net/netisr.h      8 Jan 2016 13:53:24 -0000       1.44
> +++ net/netisr.h      18 Apr 2016 07:52:28 -0000
> @@ -61,7 +61,12 @@
>  
>  #ifndef _LOCORE
>  #ifdef _KERNEL
> +
> +#include <sys/task.h>
> +#include <sys/atomic.h>
> +
>  extern int   netisr;                 /* scheduling bits for network */
> +extern struct task if_input_task_locked;
>  
>  void ipintr(void);
>  void ip6intr(void);
> @@ -70,16 +75,11 @@ void      bridgeintr(void);
>  void pppoeintr(void);
>  void pfsyncintr(void);
>  
> -#include <machine/atomic.h>
> -
> -extern void *netisr_intr;
>  #define      schednetisr(anisr)                                              
> \
>  do {                                                                 \
>       atomic_setbits_int(&netisr, (1 << (anisr)));                    \
> -     softintr_schedule(netisr_intr);                                 \
> +     task_add(softnettq, &if_input_task_locked);                     \
>  } while (/* CONSTCOND */0)
> -
> -void netisr_init(void);
>  
>  #endif /* _KERNEL */
>  #endif /*_LOCORE */
> Index: kern/init_main.c
> ===================================================================
> RCS file: /cvs/src/sys/kern/init_main.c,v
> retrieving revision 1.249
> diff -u -p -r1.249 init_main.c
> --- kern/init_main.c  19 Mar 2016 12:04:15 -0000      1.249
> +++ kern/init_main.c  18 Apr 2016 07:48:40 -0000
> @@ -394,7 +394,6 @@ main(void *framep)
>        * until everything is ready.
>        */
>       s = splnet();
> -     netisr_init();
>       domaininit();
>       splx(s);
>  
> 
> 

Reply via email to