From owner-freebsd-bugs@FreeBSD.ORG Mon May 2 16:10:10 2011 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 4EB871065670 for ; Mon, 2 May 2011 16:10:10 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 284B18FC17 for ; Mon, 2 May 2011 16:10:10 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.4/8.14.4) with ESMTP id p42GAAEb042109 for ; Mon, 2 May 2011 16:10:10 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.4/8.14.4/Submit) id p42GAAWr042108; Mon, 2 May 2011 16:10:10 GMT (envelope-from gnats) Resent-Date: Mon, 2 May 2011 16:10:10 GMT Resent-Message-Id: <201105021610.p42GAAWr042108@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Alexandr Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id A42B2106564A for ; Mon, 2 May 2011 16:01:39 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from red.freebsd.org (red.freebsd.org [IPv6:2001:4f8:fff6::22]) by mx1.freebsd.org (Postfix) with ESMTP id 92A498FC0A for ; Mon, 2 May 2011 16:01:39 +0000 (UTC) Received: from red.freebsd.org (localhost [127.0.0.1]) by red.freebsd.org (8.14.4/8.14.4) with ESMTP id p42G1dSx034696 for ; Mon, 2 May 2011 16:01:39 GMT (envelope-from nobody@red.freebsd.org) Received: (from nobody@localhost) by red.freebsd.org (8.14.4/8.14.4/Submit) id p42G1diT034695; Mon, 2 May 2011 16:01:39 GMT (envelope-from nobody) Message-Id: <201105021601.p42G1diT034695@red.freebsd.org> Date: Mon, 2 May 2011 16:01:39 GMT From: Alexandr To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-3.1 Cc: Subject: kern/156769: netisr: SMP patch for 7.x and 6.x X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 02 May 2011 16:10:10 -0000 >Number: 156769 >Category: kern >Synopsis: netisr: SMP patch for 7.x and 6.x >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Mon May 02 16:10:09 UTC 2011 >Closed-Date: >Last-Modified: >Originator: Alexandr >Release: 7.2-RELEASE-p8 >Organization: NetAssist >Environment: FreeBSD homecat.alter.org.ua 7.2-RELEASE-p8 FreeBSD 7.2-RELEASE-p8 #6: Sat Apr 23 12:52:20 EEST 2011 root@homecat.alter.org.ua:/usr/src/sys/i386/compile/CAT_v14c i386 >Description: Network dispatch netisr can now be paralellized on SMP machines. Since netisr was not changed for a long time, this patch may bu suitable for earlier versions of kernel. Netisr behavior is now managed via sysctl: net.isr.maxthreads=NNN Also added one specific option: net.isr.direct_arp=[0|1] >How-To-Repeat: >Fix: http://alter.org.ua/soft/fbsd/netisr/netisr_smp.7x.20110501.patch.gz Patch attached with submission follows: diff -crN orig/sys/net/netisr.c new/sys/net/netisr.c *** orig/sys/net/netisr.c Wed Apr 15 06:14:26 2009 --- new/sys/net/netisr.c Wed Apr 13 15:13:22 2011 *************** *** 55,61 **** #include #include ! volatile unsigned int netisr; /* scheduling bits for network */ struct netisr { netisr_t *ni_handler; --- 55,71 ---- #include #include ! static MALLOC_DEFINE(M_NETISR, "netisr", "Net ISR dispatch"); ! ! #ifdef SMP ! unsigned int netisrmask[MAXCPU+1]; /* scheduling bits for network */ ! volatile unsigned int current_netisr; /* current isr thread */ ! unsigned int unsafe_netisr_mask=0; /* unsafe isr nums */ ! static void *net_ihs[MAXCPU]; ! #else ! volatile unsigned int netisrmask; /* scheduling bits for network */ ! static void *net_ih; ! #endif /* SMP */ struct netisr { netisr_t *ni_handler; *************** *** 63,76 **** int ni_flags; } netisrs[32]; - static void *net_ih; - - void - legacy_setsoftnet(void) - { - swi_sched(net_ih, 0); - } - void netisr_register(int num, netisr_t *handler, struct ifqueue *inq, int flags) { --- 73,78 ---- *************** *** 80,85 **** --- 82,94 ---- netisrs[num].ni_handler = handler; netisrs[num].ni_queue = inq; netisrs[num].ni_flags = flags; + #ifdef SMP + if(flags & NETISR_MPSAFE) { + unsafe_netisr_mask &= ~(1 << num); + } else { + unsafe_netisr_mask |= (1 << num); + } + #endif /* SMP */ } void *************** *** 94,99 **** --- 103,111 ---- if (ni->ni_queue != NULL) IF_DRAIN(ni->ni_queue); ni->ni_queue = NULL; + #ifdef SMP + unsafe_netisr_mask &= ~(1 << num); + #endif /* SMP */ } struct isrstat { *************** *** 101,108 **** --- 113,123 ---- int isrs_directed; /* ...directly dispatched */ int isrs_deferred; /* ...queued instead */ int isrs_queued; /* intentionally queueued */ + int isrs_giant_queued; + int isrs_dequeued; /* dequeueued */ int isrs_drop; /* dropped 'cuz no handler */ int isrs_swi_count; /* swi_net handlers called */ + int isrs_swi_retry_count; /* swi_net handlers loop retries */ }; static struct isrstat isrstat; *************** *** 113,118 **** --- 128,169 ---- &netisr_direct, 0, "enable direct dispatch"); TUNABLE_INT("net.isr.direct", &netisr_direct); + static int netisr_direct_arp = 1; + SYSCTL_INT(_net_isr, OID_AUTO, direct_arp, CTLFLAG_RW, + &netisr_direct_arp, 0, "enable direct ARP dispatch"); + TUNABLE_INT("net.isr.direct_arp", &netisr_direct_arp); + + #ifdef SMP + //static int netisr_active_threads = 1; + static int netisr_threads = 1; + static int max_netisr = MAXCPU; + + static int + sysctl_netisr_threads(SYSCTL_HANDLER_ARGS) + { + int error, new_val; + + if((netisr_threads > max_netisr) || (netisr_threads <= 0)) { + netisr_threads = max_netisr; + } + new_val = netisr_threads; + + error = sysctl_handle_int(oidp, &new_val, 0, req); + if (error != 0 || req->newptr == NULL) + return (error); + if((new_val > max_netisr) || (new_val <= 0)) { + return (EINVAL); + } + netisr_threads = new_val; + return (0); + } + + SYSCTL_PROC(_net_isr, OID_AUTO, maxthreads, CTLTYPE_INT|CTLFLAG_RW, + 0, sizeof(netisr_threads), sysctl_netisr_threads, "I", + "parallel NET-ISR threads"); + //TUNABLE_INT("net.isr.maxthreads", &netisr_threads); + #endif /* SMP */ + SYSCTL_INT(_net_isr, OID_AUTO, count, CTLFLAG_RD, &isrstat.isrs_count, 0, ""); SYSCTL_INT(_net_isr, OID_AUTO, directed, CTLFLAG_RD, *************** *** 121,130 **** --- 172,187 ---- &isrstat.isrs_deferred, 0, ""); SYSCTL_INT(_net_isr, OID_AUTO, queued, CTLFLAG_RD, &isrstat.isrs_queued, 0, ""); + SYSCTL_INT(_net_isr, OID_AUTO, giant_queued, CTLFLAG_RD, + &isrstat.isrs_giant_queued, 0, ""); + SYSCTL_INT(_net_isr, OID_AUTO, dequeued, CTLFLAG_RD, + &isrstat.isrs_dequeued, 0, ""); SYSCTL_INT(_net_isr, OID_AUTO, drop, CTLFLAG_RD, &isrstat.isrs_drop, 0, ""); SYSCTL_INT(_net_isr, OID_AUTO, swi_count, CTLFLAG_RD, &isrstat.isrs_swi_count, 0, ""); + /*SYSCTL_INT(_net_isr, OID_AUTO, swi_retry_count, CTLFLAG_RD, + &isrs_swi_retry_count, 0, "");*/ /* * Process all packets currently present in a netisr queue. Used to *************** *** 140,149 **** --- 197,229 ---- IF_DEQUEUE(ni->ni_queue, m); if (m == NULL) break; + isrstat.isrs_dequeued++; ni->ni_handler(m); } } + void + legacy_setsoftnet(int isrbits) + { + #ifdef SMP + int i; + if(isrbits == (1 << NETISR_IP)) { + if(netisr_threads > max_netisr) { + netisr_threads = max_netisr; + } + i = current_netisr % netisr_threads; + current_netisr++; + } else { + i = 0; + } + atomic_set_rel_int(&(netisrmask[i]), isrbits); + swi_sched(net_ihs[i], 0); + #else + atomic_set_rel_int(&(netisrmask), isrbits); + swi_sched(net_ih, 0); + #endif /* SMP */ + } + /* * Call the netisr directly instead of queueing the packet, if possible. */ *************** *** 173,180 **** * between multiple places in the system (e.g. IP * dispatched from interfaces vs. IP queued from IPSec). */ ! if (netisr_direct && (ni->ni_flags & NETISR_MPSAFE)) { ! isrstat.isrs_directed++; /* * NB: We used to drain the queue before handling * the packet but now do not. Doing so here will --- 253,263 ---- * between multiple places in the system (e.g. IP * dispatched from interfaces vs. IP queued from IPSec). */ ! if ((netisr_direct || ! (netisr_direct_arp && (num == NETISR_ARP))) ! && ! (ni->ni_flags & NETISR_MPSAFE)) { ! isrstat.isrs_directed++; /* * NB: We used to drain the queue before handling * the packet but now do not. Doing so here will *************** *** 211,216 **** --- 294,302 ---- return (ENXIO); } isrstat.isrs_queued++; + if ((ni->ni_flags & NETISR_MPSAFE) == 0) { + isrstat.isrs_giant_queued++; + } if (!IF_HANDOFF(ni->ni_queue, m, NULL)) return (ENOBUFS); /* IF_HANDOFF has free'd the mbuf */ schednetisr(num); *************** *** 230,236 **** #endif do { ! bits = atomic_readandclear_int(&netisr); if (bits == 0) break; while ((i = ffs(bits)) != 0) { --- 316,326 ---- #endif do { ! #ifdef SMP ! bits = atomic_readandclear_int((volatile int*)dummy); ! #else ! bits = atomic_readandclear_int(&netisrmask); ! #endif /* SMP */ if (bits == 0) break; while ((i = ffs(bits)) != 0) { *************** *** 244,253 **** } if ((ni->ni_flags & NETISR_MPSAFE) == 0) { mtx_lock(&Giant); ! if (ni->ni_queue == NULL) ni->ni_handler(NULL); ! else netisr_processqueue(ni); mtx_unlock(&Giant); } else { if (ni->ni_queue == NULL) --- 334,349 ---- } if ((ni->ni_flags & NETISR_MPSAFE) == 0) { mtx_lock(&Giant); ! if (ni->ni_queue == NULL) { ni->ni_handler(NULL); ! } else { ! /*if(netisr_giant_workaround) { ! netisr_processqueue_gwa(ni); ! } else { ! netisr_processqueue(ni); ! }*/ netisr_processqueue(ni); + } mtx_unlock(&Giant); } else { if (ni->ni_queue == NULL) *************** *** 262,269 **** static void start_netisr(void *dummy) { ! ! if (swi_add(NULL, "net", swi_net, NULL, SWI_NET, INTR_MPSAFE, &net_ih)) ! panic("start_netisr"); } SYSINIT(start_netisr, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_netisr, NULL); --- 358,379 ---- static void start_netisr(void *dummy) { ! #ifdef SMP ! int i; ! char swiname[] = "netNNxxxx"; ! current_netisr = 0; ! void *t; ! ! for(i=0; iRelease-Note: >Audit-Trail: >Unformatted: