Index: kern_synch.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_synch.c,v retrieving revision 1.239 diff -u -r1.239 kern_synch.c --- kern_synch.c 25 Jan 2004 07:49:45 -0000 1.239 +++ kern_synch.c 25 Jan 2004 09:15:56 -0000 @@ -453,7 +453,6 @@ void mi_switch(int flags) { - struct bintime new_switchtime; struct thread *td; struct proc *p; @@ -469,21 +468,6 @@ ("mi_switch: switch in a critical section")); KASSERT((flags & (SW_INVOL | SW_VOL)) != 0, ("mi_switch: switch must be voluntary or involuntary")); - - if (flags & SW_VOL) - p->p_stats->p_ru.ru_nvcsw++; - else - p->p_stats->p_ru.ru_nivcsw++; - /* - * Compute the amount of time during which the current - * process was running, and add that to its total so far. - */ - binuptime(&new_switchtime); - bintime_add(&p->p_runtime, &new_switchtime); - bintime_sub(&p->p_runtime, PCPU_PTR(switchtime)); - - td->td_generation++; /* bump preempt-detect counter */ - #ifdef DDB /* * Don't perform context switches from the debugger. @@ -494,23 +478,42 @@ db_error("Context switches not allowed in the debugger"); } #endif - /* - * Check if the process exceeds its cpu resource allocation. If - * over max, arrange to kill the process in ast(). + * Compute rusage information. This is skipped for kthreads to avoid + * the cost of the timer operations. We clear switchticks to let the + * incoming thread know that switchtime and switchticks are not valid. */ - if (p->p_cpulimit != RLIM_INFINITY && - p->p_runtime.sec > p->p_cpulimit) { - p->p_sflag |= PS_XCPU; - td->td_flags |= TDF_ASTPENDING; - } + if ((p->p_flag & P_KTHREAD) == 0) { + struct bintime new_switchtime; + if (flags & SW_VOL) + p->p_stats->p_ru.ru_nvcsw++; + else + p->p_stats->p_ru.ru_nivcsw++; + /* + * Compute the amount of time during which the current + * process was running, and add that to its total so far. + */ + binuptime(&new_switchtime); + bintime_add(&p->p_runtime, &new_switchtime); + bintime_sub(&p->p_runtime, PCPU_PTR(switchtime)); + PCPU_SET(switchtime, new_switchtime); + /* + * Check if the process exceeds its cpu resource allocation. + * If over max, arrange to kill the process in ast(). + */ + if (p->p_cpulimit != RLIM_INFINITY && + p->p_runtime.sec > p->p_cpulimit) { + p->p_sflag |= PS_XCPU; + td->td_flags |= TDF_ASTPENDING; + } + } else + PCPU_SET(switchticks, 0); /* * Finish up stats for outgoing thread. */ + td->td_generation++; /* bump preempt-detect counter */ cnt.v_swtch++; - PCPU_SET(switchtime, new_switchtime); - PCPU_SET(switchticks, ticks); CTR3(KTR_PROC, "mi_switch: old thread %p (pid %d, %s)", td, p->p_pid, p->p_comm); if (td->td_proc->p_flag & P_SA) @@ -519,6 +522,19 @@ CTR3(KTR_PROC, "mi_switch: new thread %p (pid %d, %s)", td, p->p_pid, p->p_comm); + + /* + * If the incoming thread is not a kthread and the last thread didn't + * update switchtime, we must set it here to keep accurate rusage + * statistics. + */ + if ((p->p_flag & P_KTHREAD) == 0 && + PCPU_GET(switchticks) == 0) { + struct bintime new_switchtime; + binuptime(&new_switchtime); + PCPU_SET(switchtime, new_switchtime); + } + PCPU_SET(switchticks, ticks); /* * If the last thread was exiting, finish cleaning it up.