[ltt-dev] [patch] add tracepoints to trace activate/deactivate task
Jason Baron
jbaron at redhat.com
Mon Dec 8 14:49:48 EST 2008
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 <jbaron at redhat.com>
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 <linux/sched.h>
#include <linux/tracepoint.h>
+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;
}
More information about the lttng-dev
mailing list