Eric Saxe wrote:
>> [snip]
>> The problem is somewhat obvious. There's no guarantee that the next
>> thread is the actual offender. It's very likely, but not guaranteed :(
>>
>> Any thoughts?
>>
> I think the apprach is probably ok. Like you said, the trick is to
> figure out what's causing the idle-state transition...and before I think
> we figured either:
> 1 device interrupt
> 2 "poke" because something became runnable on the local queue
> 3 "poke" because something became runnable on a remote queue that
> was already busy
> 4 xcall for some other reason
>
> - You might want to use the "sched::on-cpu" probe to catch the first
> thread that this CPU is now going to run (what if the next thread is a
> kernel service thread)? If that's the next probe to fire, it's probably
> scenario 2.
> - If the sched::dequeue probe fires before sched::on-cpu, it's probably
> scenario 3.
> - If an interrupt probe fires before the idle-state transition probe
> (which will happen since the CPU will awake to the interrupt handler),
> then it's probbaly scenario 1.
>
> Then I would be curious how much is left...which I assume would fall
> into the scenario 4 bucket. :)
I think I may have found a better alternative. Instead of chasing the
threads around, we could check the cpu_t->cpu_disp_flags field for the
processor state and only report the events that happen when a cpu is idle.
Here's the default event.c script with those changes. The values are
close to the number of calls to i86_mwait, so it seems to be working.
What do you think ?
thanks
Rafael
do_interrupt:entry
/`cpu[cpu]->cpu_disp_flags == 0x02/
{
self->interrupt = 1;
}
interrupt-complete
/arg0 != NULL && arg3 != 0 && self->interrupt/
{
this->devi = (struct dev_info *)arg0;
@interrupts[stringof(`devnamesp[this->devi->devi_major].dn_name),
this->devi->devi_instance] = count();
self->interrupt = 0;
}
sdt:::callout-start
/`cpu[cpu]->cpu_disp_flags == 0x02/
{
self->callout = 1;
}
sdt:::callout-start
/(caddr_t)((callout_t *)arg0)->c_func == (caddr_t)&`setrun && self->callout/
{
this->thr = (kthread_t *)(((callout_t *)arg0)->c_arg);
@events_u[stringof(this->thr->t_procp->p_user.u_comm)] = count();
self->callout = 0;
}
sdt:::callout-start
/(caddr_t)((callout_t *)arg0)->c_func != (caddr_t)&`setrun && self->callout/
{
@events_k[(caddr_t)((callout_t *)arg0)->c_func] = count();
self->callout = 0;
}
cyclic_expire:entry
/((cpu_t *)((cyc_cpu_t *)arg0)->cyp_cpu)->cpu_disp_flags == 0x02 &&
(caddr_t)((cyclic_t *)arg0)->cy_handler == (caddr_t)&`clock/
{
@events_k[(caddr_t)((cyclic_t *)arg0)->cy_handler] = count();
}
send_dirint:entry
/`cpu[arg0]->cpu_disp_flags == 0x02/
{
@events_x[execname] = count();
}
cpu_wakeup_mwait:entry
/((cpu_t *)arg0)->cpu_disp_flags == 0x02/
{
@a[execname] = count();
}