Change 86091 by rwatson@rwatson_peppercorn on 2005/10/30 23:45:49

	Not entirely pretty hack: allow preemption by the netisr thread to
	be configurable separate from global preemption.  Specifically, if
	net.isr.preempt=0, pass SWI_NOPREEMPT to swi_sched().  Implement
	SWI_NOPREEMPT by adding IE_FLAG_NOPREEMPT (don't preempt due to an
	interrupt event, only wakeup), which in turn is implemented by
	adding SRQ_NOPREEMPT, a flag to the scheduler run queue calls.
	
	The reason to add this is that loopback traffic is seeing a lot of
	context switches, and avoiding the context switches through
	avoiding unnecessary preemption may help illustrate if this is a
	performance problem, and possibly be part of a fix.
	
	This may not work, either functionally, or in its overall goal, and
	is an experiment.

Affected files ...

... //depot/projects/netsmp/src/sys/kern/kern_intr.c#4 edit
... //depot/projects/netsmp/src/sys/kern/sched_4bsd.c#2 edit
... //depot/projects/netsmp/src/sys/kern/sched_ule.c#6 edit
... //depot/projects/netsmp/src/sys/net/netisr.c#3 edit
... //depot/projects/netsmp/src/sys/sys/interrupt.h#4 edit
... //depot/projects/netsmp/src/sys/sys/proc.h#5 edit

Differences ...

==== //depot/projects/netsmp/src/sys/kern/kern_intr.c#4 (text+ko) ====

@@ -485,7 +485,7 @@
 }
 
 int
-intr_event_schedule_thread(struct intr_event *ie)
+intr_event_schedule_thread_flags(struct intr_event *ie, int flags)
 {
 	struct intr_entropy entropy;
 	struct intr_thread *it;
@@ -531,7 +531,8 @@
 		CTR3(KTR_INTR, "%s: schedule pid %d (%s)", __func__, p->p_pid,
 		    p->p_comm);
 		TD_CLR_IWAIT(td);
-		setrunqueue(td, SRQ_INTR);
+		setrunqueue(td, SRQ_INTR |
+		    (flags & IE_FLAG_NOPREEMPT ? SRQ_NOPREEMPT : 0));
 	} else {
 		CTR5(KTR_INTR, "%s: pid %d (%s): it_need %d, state %d",
 		    __func__, p->p_pid, p->p_comm, it->it_need, td->td_state);
@@ -541,6 +542,13 @@
 	return (0);
 }
 
+int
+intr_event_schedule_thread(struct intr_event *ie)
+{
+
+	return (intr_event_schedule_thread_flags(ie, 0));
+}
+
 /*
  * Add a software interrupt handler to a specified event.  If a given event
  * is not specified, then a new event is created.
@@ -595,7 +603,8 @@
 	 */
 	atomic_store_rel_int(&ih->ih_need, 1);
 	if (!(flags & SWI_DELAY)) {
-		error = intr_event_schedule_thread(ie);
+		error = intr_event_schedule_thread_flags(ie,
+		    (flags & SWI_NOPREEMPT) ? IE_FLAG_NOPREEMPT : 0);
 		KASSERT(error == 0, ("stray software interrupt"));
 	}
 }

==== //depot/projects/netsmp/src/sys/kern/sched_4bsd.c#2 (text+ko) ====

@@ -1174,7 +1174,9 @@
 		}
 
 		if (!forwarded) {
-			if ((flags & SRQ_YIELDING) == 0 && maybe_preempt(td))
+			if ((flags & SRQ_YIELDING) == 0 &&
+			    (flags & SRQ_NOPREEMPT) == 0 &&
+			    maybe_preempt(td))
 				return;
 			else
 				maybe_resched(td);
@@ -1214,7 +1216,7 @@
 	 * OURSELF case, we are puting ourself on the run queue
 	 * which also only happens when we are about to yield.
 	 */
-	if((flags & SRQ_YIELDING) == 0) {
+	if ((flags & SRQ_YIELDING) == 0 && (flags & SRQ_NOPREEMPT) == 0) {
 		if (maybe_preempt(td))
 			return;
 	}	

==== //depot/projects/netsmp/src/sys/kern/sched_ule.c#6 (text+ko) ====

@@ -1767,7 +1767,7 @@
 	ke = td->td_kse;
 	kg = td->td_ksegrp;
 	canmigrate = 1;
-	preemptive = !(flags & SRQ_YIELDING);
+	preemptive = !(flags & SRQ_YIELDING || flags & SRQ_NOPREEMPT);
 	class = PRI_BASE(kg->kg_pri_class);
 	kseq = KSEQ_SELF();
 	if ((ke->ke_flags & KEF_INTERNAL) == 0)

==== //depot/projects/netsmp/src/sys/net/netisr.c#3 (text+ko) ====

@@ -74,6 +74,8 @@
 SYSCTL_INT(_debug, OID_AUTO, mpsafenet, CTLFLAG_RD, &debug_mpsafenet, 0,
     "Enable/disable MPSAFE network support");
 
+static int	netisr_preempt = 1;	/* netisr will preempt when woken. */
+
 volatile unsigned int	netisr;	/* scheduling bits for network */
 
 struct netisr {
@@ -159,7 +161,8 @@
 void
 legacy_setsoftnet(void)
 {
-	swi_sched(net_ih, 0);
+
+	swi_sched(net_ih, netisr_preempt ? 0 : SWI_NOPREEMPT);
 }
 
 void
@@ -219,6 +222,9 @@
 SYSCTL_INT(_net_isr, OID_AUTO, swi_count, CTLFLAG_RD, 
     &isrstat.isrs_swi_count, 0, "");
 
+SYSCTL_INT(_net_isr, OID_AUTO, preempt, CTLFLAG_RW,
+    &netisr_preempt, 0, "");
+
 /*
  * Process all packets currently present in a netisr queue.  Used to
  * drain an existing set of packets waiting for processing when we

==== //depot/projects/netsmp/src/sys/sys/interrupt.h#4 (text+ko) ====

@@ -81,8 +81,14 @@
 #define	IE_ENTROPY	0x000002	/* Interrupt is an entropy source. */
 #define	IE_ADDING_THREAD 0x000004	/* Currently building an ithread. */
 
+/*
+ * Flags passed to intr_event_schedule_thread_flags().
+ */
+#define	IE_FLAG_NOPREEMPT	0x00000001	/* Schedule; don't preempt. */
+
 /* Flags to pass to sched_swi. */
 #define	SWI_DELAY	0x2
+#define	SWI_NOPREEMPT	0x4
 
 /*
  * Software interrupt numbers in priority order.  The priority determines
@@ -121,6 +127,7 @@
 int	intr_event_destroy(struct intr_event *ie);
 int	intr_event_remove_handler(void *cookie);
 int	intr_event_schedule_thread(struct intr_event *ie);
+int	intr_event_schedule_thread_flags(struct intr_event *ie, int flags);
 int	swi_add(struct intr_event **eventp, const char *name,
 	    driver_intr_t handler, void *arg, int pri, enum intr_type flags,
 	    void **cookiep);

==== //depot/projects/netsmp/src/sys/sys/proc.h#5 (text+ko) ====

@@ -685,6 +685,7 @@
 #define SRQ_OURSELF	0x0002		/* It is ourself (from mi_switch). */
 #define SRQ_INTR	0x0004		/* It is probably urgent. */
 #define SRQ_PREEMPTED	0x0008		/* has been preempted.. be kind */
+#define	SRQ_NOPREEMPT	0x0010		/* Caller hints not to preempt. */
 
 /* How values for thread_single(). */
 #define	SINGLE_NO_EXIT	0
