From mboxrd@z Thu Jan 1 00:00:00 1970 From: jbaron@redhat.com (Jason Baron) Date: Mon, 8 Dec 2008 14:49:48 -0500 Subject: [ltt-dev] [patch] add tracepoints to trace activate/deactivate task Message-ID: <20081208194948.GC27166@redhat.com> hi, I thought it would be useful to track when a task is 'activated/deactivated'. This case is different from wakeup/wait, in that task can be activated and deactivated, when the scheduler re-balances tasks, the allowable cpuset changes, or cpu hotplug occurs. Using these patches I can more precisely figure out when a task becomes runnable and why. Patch to add these tracepoints to the lttng tree is below. I'm also including a systemtap script, originally written by Oracle, but which I've modified to work with these new tracepoints. thanks, -Jason Signed-off-by: Jason Baron diff --git a/include/trace/sched.h b/include/trace/sched.h index fe4767d..d1fd8a3 100644 --- a/include/trace/sched.h +++ b/include/trace/sched.h @@ -4,6 +4,8 @@ #include #include +struct rq; + DECLARE_TRACE(sched_kthread_stop, TPPROTO(struct task_struct *t), TPARGS(t)); @@ -44,5 +46,13 @@ DECLARE_TRACE(sched_signal_send, DECLARE_TRACE(sched_kthread_create, TPPROTO(void *fn, int pid), TPARGS(fn, pid)); +DECLARE_TRACE(sched_activate_task, + TPPROTO(struct task_struct *p, struct rq *rq), + TPARGS(p, rq)); +DECLARE_TRACE(sched_deactivate_task, + TPPROTO(struct task_struct *p, struct rq *rq), + TPARGS(p, rq)); + + #endif diff --git a/kernel/sched.c b/kernel/sched.c index cc7f048..7b707cf 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -122,6 +122,8 @@ DEFINE_TRACE(sched_wakeup); DEFINE_TRACE(sched_wakeup_new); DEFINE_TRACE(sched_switch); DEFINE_TRACE(sched_migrate_task); +DEFINE_TRACE(sched_activate_task); +DEFINE_TRACE(sched_deactivate_task); #ifdef CONFIG_SMP /* @@ -1716,6 +1718,7 @@ static int effective_prio(struct task_struct *p) */ static void activate_task(struct rq *rq, struct task_struct *p, int wakeup) { + trace_sched_activate_task(p, rq); if (task_contributes_to_load(p)) rq->nr_uninterruptible--; @@ -1728,6 +1731,7 @@ static void activate_task(struct rq *rq, struct task_struct *p, int wakeup) */ static void deactivate_task(struct rq *rq, struct task_struct *p, int sleep) { + trace_sched_deactivate_task(p, rq); if (task_contributes_to_load(p)) rq->nr_uninterruptible++; @@ -2420,6 +2424,7 @@ void wake_up_new_task(struct task_struct *p, unsigned long clone_flags) * Let the scheduling class do new task startup * management (if any): */ + trace_sched_activate_task(p, rq); p->sched_class->task_new(rq, p); inc_nr_running(rq); } diff --git a/ltt/probes/kernel-trace.c b/ltt/probes/kernel-trace.c index e241499..c27e671 100644 --- a/ltt/probes/kernel-trace.c +++ b/ltt/probes/kernel-trace.c @@ -372,6 +372,19 @@ void probe_kernel_vprintk(unsigned long retaddr, char *buf, int len) } } +void probe_activate_task(struct task_struct *p, struct rq *rq) +{ + trace_mark_tp(kernel_activate_task, sched_activate_task, probe_activate_task, + "pid %d state %ld cpu_id %u", p->pid, p->state, task_cpu(p)); +} + +void probe_deactivate_task(struct task_struct *p, struct rq *rq) +{ + trace_mark_tp(kernel_deactivate_task, sched_deactivate_task, + probe_deactivate_task, "pid %d state %ld cpu_id %u", + p->pid, p->state, task_cpu(p)); +} + #ifdef CONFIG_MODULES void probe_kernel_module_free(struct module *mod) { #!/usr/bin/env stap # # Copyright (C) 2007 Oracle Corp. # # Trace state transition of one specified process # # GNU General Public License (GPL); either version 2, or (at your option) any # later version. # # Parameter 1: specified process id # # Usage: # ./proc_transition_by_pid.stp -gx 1234 # # Output: # Process 1234: TASK_RUNNING -> TASK_INTERRUPTIBLE # Process 1234: TASK_RUNNING -> TASK_STOP # ... # # Note: timestamp may be not exactly point to transition moment. Fix me! global id_state global traced_pid global task_name /*return task name according to process id*/ function __get_task_name: string (pid:long) %{ struct task_struct *p; pid_t pid; pid = (pid_t)(long)THIS->pid; rcu_read_lock(); p = find_task_by_vpid(pid); rcu_read_unlock(); if (p==NULL) strlcpy(THIS->__retvalue,"Unknown",MAXSTRINGLEN); else { strlcpy(THIS->__retvalue,p->comm,MAXSTRINGLEN); } CATCH_DEREF_FAULT(); %} function __get_task_struct: long (pid:long) %{ struct task_struct *p; pid_t pid; pid = (pid_t)(long)THIS->pid; rcu_read_lock(); p = find_task_by_vpid(pid); rcu_read_unlock(); if (p==NULL) THIS->__retvalue=(long)NULL; else { THIS->__retvalue=(long)p; } CATCH_DEREF_FAULT(); %} /* process added into runqueue : really running or well prepared */ probe kernel.mark("kernel_activate_task"){ if ($arg1==traced_pid) printf("[%d] %s(%d): %s --> TASK_RUNNING\n",get_cycles(),task_name,traced_pid,id_state[$arg2]); } /* process removed from runqueue : in wait queue or other state */ probe kernel.mark("kernel_deactivate_task") { if ($arg1==traced_pid) printf("[%d] %s(%d): TASK_RUNNING --> %s\n", get_cycles(),task_name,traced_pid, id_state[$arg2]); } /* process clean up */ probe kernel.mark("kernel_process_exit") { if ($arg1==traced_pid){ printf("[%d] %s(%d): %s --> Cleaned \n", get_cycles(),task_execname(__get_task_struct($arg1)),traced_pid,id_state[task_state(__get_task_struct($arg1))]); exit() } } /* accept one parameter as process id * if not in correct format, step1 parse reports error*/ probe begin { /*from sched.h*/ id_state[0] = "TASK_RUNNING" id_state[1] = "TASK_INTERRUPTIBLE" id_state[2] = "TASK_UNINTERRUPTIBLE" id_state[4] = "TASK_STOPPED" id_state[8] = "TASK_TRACED" /* exit_state id_state[16] = "EXIT_ZOMBIE" id_state[32] = "EXIT_DEAD" */ id_state[64] = "TASK_NONINTERACTIVE" id_state[128] = "TASK_DEAD" traced_pid = target(); task_name = __get_task_name(traced_pid); if (task_name!="Unknown") { printf("Now scanning the process...%s %d\n\n", task_name, traced_pid); } else { printf("No such process!\n"); exit(); } } probe end{ delete id_state; delete traced_pid; delete task_name; }