tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: memcpy of struct buf, or similar?



Chris Gilbert wrote:
> Chris Gilbert wrote:
>> Attached is a slightly revised patch, to get rid of the changes to
>> whitespace and sleeptab_lookup being moved.
>>
>> I also added the KASSERT back to the cv_unsleep, as the lwp lock should
>> be held at that point, and the lwp lock will be set to the sleepq lock,
>> so it's safe to look at the sleepq.
>>
>> Note there is an assumption that cv_has_waiters will be called with the
>> mutex used to access the cv held, and so locking the sleepq lock will
>> make sure we get a consistent state.
> 
> I've now checked that patch in, as it fixes the issue.
> 
> I've also produced that attached patch, which brings back cv_waiters.
> However, I'm not seeing any performance gain with it using build.sh,
> perhaps a specific benchmark would show a gain.  In theory there should
> be some gain as we don't have to lock the sleepq if it's empty, but it's
> probably lost in the noise of build.sh

Actually reviewing the patch again shows that the patch is broken
(although it works when used), cv_unsleep needs to decrement cv_waiters,
but doesn't have the callers mutex held, and so cv_waiter updates need
to be protected by the sleepq/lwp lock being held.

cv_waiters reads are safe without the sleepq held as the worst that
could happen is they read that there are workers, and cause a spurious
wakeup to happen.

Performance for build.sh seems to be on-par with the code without the patch.

Thanks,
Chris

Index: kern/kern_condvar.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_condvar.c,v
retrieving revision 1.23
diff -u -p -r1.23 kern_condvar.c
--- kern/kern_condvar.c 15 Jun 2008 09:56:18 -0000      1.23
+++ kern/kern_condvar.c 15 Jun 2008 14:46:48 -0000
@@ -96,6 +96,7 @@ cv_init(kcondvar_t *cv, const char *wmes
        KASSERT(wmesg != NULL);
        cv->cv_wmesg = wmesg;
        sleepq_init(CV_SLEEPQ(cv));
+       cv->cv_waiters = 0;
 }
 
 /*
@@ -111,6 +112,7 @@ cv_destroy(kcondvar_t *cv)
 #ifdef DIAGNOSTIC
        KASSERT(cv_is_valid(cv));
        cv->cv_wmesg = deadcv;
+       cv->cv_waiters = -3;
 #endif
 }
 
@@ -134,6 +136,7 @@ cv_enter(kcondvar_t *cv, kmutex_t *mtx, 
        l->l_kpriority = true;
        (void)sleeptab_lookup(&sleeptab, cv, &mp);
        sq = CV_SLEEPQ(cv);
+       cv->cv_waiters++;
        sleepq_enter(sq, l, mp);
        sleepq_enqueue(sq, cv, cv->cv_wmesg, &cv_syncobj);
        mutex_exit(mtx);
@@ -183,6 +186,8 @@ cv_unsleep(lwp_t *l, bool cleanup)
        KASSERT(cv_is_valid(cv));
        KASSERT(!TAILQ_EMPTY(CV_SLEEPQ(cv)));
 
+       cv->cv_waiters--;
+
        return sleepq_unsleep(l, cleanup);
 }
 
@@ -278,8 +283,8 @@ cv_signal(kcondvar_t *cv)
 
        /* LOCKDEBUG_WAKEUP(CV_DEBUG_P(cv), cv, CV_RA); */
        KASSERT(cv_is_valid(cv));
-
-       cv_wakeup_one(cv);
+       if (__predict_false(cv->cv_waiters > 0))
+               cv_wakeup_one(cv);
 }
 
 static void __noinline
@@ -299,6 +304,7 @@ cv_wakeup_one(kcondvar_t *cv)
                mutex_spin_exit(mp);
                return;
        }
+       cv->cv_waiters--;
        KASSERT(l->l_sleepq == sq);
        KASSERT(l->l_mutex == mp);
        KASSERT(l->l_wchan == cv);
@@ -328,7 +334,8 @@ cv_broadcast(kcondvar_t *cv)
        /* LOCKDEBUG_WAKEUP(CV_DEBUG_P(cv), cv, CV_RA); */
        KASSERT(cv_is_valid(cv));
 
-       cv_wakeup_all(cv);
+       if (__predict_false(cv->cv_waiters > 0))
+               cv_wakeup_all(cv);
 }
 
 static void __noinline
@@ -351,6 +358,7 @@ cv_wakeup_all(kcondvar_t *cv)
                next = TAILQ_NEXT(l, l_sleepchain);
                swapin |= sleepq_remove(sq, l);
        }
+       cv->cv_waiters = 0;
        mutex_spin_exit(mp);
 
        /*
@@ -387,18 +395,7 @@ cv_wakeup(kcondvar_t *cv)
 bool
 cv_has_waiters(kcondvar_t *cv)
 {
-       bool result;
-       kmutex_t *mp;
-       sleepq_t *sq;
-
-       sq = CV_SLEEPQ(cv);
-       (void)sleeptab_lookup(&sleeptab, cv, &mp);
-
-       /* we can only get a valid result with the sleepq locked */
-       result = !TAILQ_EMPTY(sq);
-
-       mutex_spin_exit(mp);
-       return result;
+       return (cv->cv_waiters > 0);
 }
 
 /*
@@ -411,5 +408,11 @@ bool
 cv_is_valid(kcondvar_t *cv)
 {
 
-       return cv->cv_wmesg != deadcv && cv->cv_wmesg != NULL;
+       if (cv->cv_wmesg == deadcv || cv->cv_wmesg == NULL)
+               return false;
+
+       if (cv->cv_waiters < 0)
+               return false;
+
+       return true;
 }
Index: sys/condvar.h
===================================================================
RCS file: /cvsroot/src/sys/sys/condvar.h,v
retrieving revision 1.10
diff -u -p -r1.10 condvar.h
--- sys/condvar.h       31 May 2008 13:36:25 -0000      1.10
+++ sys/condvar.h       15 Jun 2008 14:46:49 -0000
@@ -44,6 +44,7 @@
 typedef struct kcondvar {
        void            *cv_opaque[2];  /* sleep queue */
        const char      *cv_wmesg;      /* description for /bin/ps */
+       int             cv_waiters;     /* number of waiters */
 } kcondvar_t;
 
 #ifdef _KERNEL


Home | Main Index | Thread Index | Old Index