runtime libraries application on schedule()
William Cohen
wcohen@redhat.com
Thu Mar 10 05:25:00 GMT 2005
Martin Hunt wrote:
>>Use a jprobe to instrument the entry to schedule().
>>Record the pid and the return address.
>
>
> pid is easy. I don't know of a way to get the return address.
> I assume some inline assembly to get ebp or rbp would do it. Something
> else to add to the runtime library.
In the case of normal calls gcc has a mechanism to get the return
address, __builtin_return_address(0). With the kprobe on the first
instruction of a function, for x86 it would be the location on the stack
( *(regs.esp)), and for ppc it would be stored in the link register
(regs.link).
>>The information could be analyzed in a sevral different ways:
>>
>>1) sum based on return address to find out which schedule points are
>>getting hit all the time
>>2) sum the counts by pid to figure out which pids are getting
>>rescheduled a lot
>
>
> That's easy enough.
>
> asmlinkage void __sched inst_schedule(void)
> {
> _stp_map_key_long (schedpid, current->pid);
> _stp_map_set_int64 (schedpid, _stp_map_get_int64(schedstr) + 1);
>
> jprobe_return();
> }
>
> I'll attach full source to a working probe.
>
>
>>3) find out pid hitting which schedule() points
>>4) find out schedule() point being encountered by which process
>
>
> I don't understand what you mean by these. What is a schedule point?
Assuming that the kernel isn't compiled with preemption, a thread in the
kernel runs until it yields the processor over to another thread. This
occurs when schedule() is called. Usually this is done when there is
nothing more to do on that thread, e.g. waiting for some resource to be
available or an operation to complete. Search for "schedule()" in the
kernel code and you can find many examples in the kernel sources.
Having the pid and address that schedul was called will give some
indication which processes and which areas of code are waiting for
resources to become available.
3 and 4 where just different ways of reducing/analyzing the data.
Imagine a 3D plot. X axis pid, y axis return address, and z axis the
number of times that combination is recorded. 3 would be look at a
particular y axis (schedule point location) and find all the counts for
it (pid). 4 would be look at a particular x axis (pid) and look at all
the schedule points it triggers. Could sum counts to find out which
schedule call locations are used most frequently (hint whether there is
a problem with a device driver).
For the kernel itself it should be fairly easy to map the addresses back
to the appropriate locations. However, would like to be able to do the
same for modules. Many of the device drivers uses schedule and they may
be loaded at various locations.
>
> Martin
>
>
>
> ------------------------------------------------------------------------
>
> #define HASH_TABLE_BITS 8
> #define HASH_TABLE_SIZE (1<<HASH_TABLE_BITS)
> #define BUCKETS 16 /* largest histogram width */
> #include "../../runtime.h"
>
> #include "../../io.c"
> #include "../../map.c"
>
>
> MODULE_PARM_DESC(stp, "\n");
>
> MAP schedpid, schedstr;
>
> asmlinkage void __sched inst_schedule(void)
> {
> _stp_map_key_str (schedstr, current->comm);
> _stp_map_key_long (schedpid, current->pid);
> _stp_map_set_int64 (schedstr, _stp_map_get_int64(schedpid) + 1);
> _stp_map_set_int64 (schedpid, _stp_map_get_int64(schedstr) + 1);
>
> jprobe_return();
> return;
> }
>
> static struct jprobe stp_probes[] = {
> {
> .kp.addr = (kprobe_opcode_t *)0xc0309408,
> .entry = (kprobe_opcode_t *) inst_schedule
> },
> };
>
> #define MAX_STP_ROUTINE (sizeof(stp_probes)/sizeof(struct jprobe))
>
> static int init_stp(void)
> {
> int i;
>
> schedpid = _stp_map_new (10000, INT64);
> schedstr = _stp_map_new (10000, INT64);
>
> for (i = 0; i < MAX_STP_ROUTINE; i++) {
> dlog("plant jprobe at %p, handler addr %p\n",
> stp_probes[i].kp.addr, stp_probes[i].entry);
> register_jprobe(&stp_probes[i]);
> }
> dlog("instrumentation is enabled...\n");
> return 0;
> }
>
> static void cleanup_stp(void)
> {
> int i;
> struct map_node_int64 *ptr;
>
> for (i = 0; i < MAX_STP_ROUTINE; i++)
> unregister_jprobe(&stp_probes[i]);
>
> foreach (schedpid, ptr)
> dlog ("pid %ld = %lld\n", key1int(ptr), ptr->val);
> dlog ("\n");
>
> foreach (schedstr, ptr)
> dlog ("process %s = %lld\n", key1str(ptr), ptr->val);
> dlog ("\n");
>
>
> _stp_map_del (schedpid);
> _stp_map_del (schedstr);
>
> dlog("EXIT\n");
> }
>
> module_init(init_stp);
> module_exit(cleanup_stp);
> MODULE_LICENSE("GPL");
>
More information about the Systemtap
mailing list