From: Kris Van Hees Date: Tue, 17 Dec 2013 23:08:17 +0000 (-0500) Subject: dtrace: vtimestamp implementation X-Git-Tag: v4.1.12-92~313^2~49 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=afc27cb58e90875f574f5910a77420cbde9be16b;p=users%2Fjedix%2Flinux-maple.git dtrace: vtimestamp implementation This commit adds DTrace vtimestamp support. It keeps track of how much time a task has spent actually processing on a CPU. The time is set to zero at task creation, and is updated whenever the task leaves a CPU (gets scheduled off), and when the dtrace_probe() function is entered, to enusre that the most recent value of consumed time is reported. Some code got moved around for consistency of the implementation. Orabug: 17741477 Reviewed-by: Dan Duval Signed-off-by: Kris Van Hees Conflicts: include/linux/ktime.h kernel/sched/core.c --- diff --git a/fs/exec.c b/fs/exec.c index 98144eb184fd..a30cdfb0e7c0 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1591,7 +1591,7 @@ static int do_execveat_common(int fd, struct filename *filename, /* execve succeeded */ #ifdef CONFIG_DTRACE dtrace_task_cleanup(current); /* get rid of probes from old ... */ - dtrace_task_init(current); /* ... be ready for probes from new */ + dtrace_task_reinit(current); /* ... be ready for probes from new */ current->dtrace_psinfo = dtrace_psinfo_alloc(current); #endif current->fs->in_exec = 0; diff --git a/include/linux/dtrace_os.h b/include/linux/dtrace_os.h index 26d67e50b26c..b2a92573b2cd 100644 --- a/include/linux/dtrace_os.h +++ b/include/linux/dtrace_os.h @@ -29,6 +29,20 @@ extern void dtrace_os_exit(void); extern void dtrace_enable(void); extern void dtrace_disable(void); +extern ktime_t dtrace_gethrtime(void); +extern ktime_t dtrace_getwalltime(void); + +typedef enum dtrace_vtime_state { + DTRACE_VTIME_INACTIVE = 0, + DTRACE_VTIME_ACTIVE +} dtrace_vtime_state_t; + +extern dtrace_vtime_state_t dtrace_vtime_active; + +extern void dtrace_vtime_enable(void); +extern void dtrace_vtime_disable(void); +extern void dtrace_vtime_switch(struct task_struct *, struct task_struct *); + extern int dtrace_invop_add(uint8_t (*func)(struct pt_regs *)); extern void dtrace_invop_remove(uint8_t (*func)(struct pt_regs *)); @@ -77,6 +91,7 @@ extern void dtrace_stacktrace(stacktrace_state_t *); extern struct task_struct *register_pid_provider(pid_t); extern void unregister_pid_provider(pid_t); +extern void dtrace_task_reinit(struct task_struct *); extern void dtrace_task_init(struct task_struct *); extern void dtrace_task_fork(struct task_struct *, struct task_struct *); extern void dtrace_task_cleanup(struct task_struct *); diff --git a/include/linux/ktime.h b/include/linux/ktime.h index 2b6a204bd8d4..f392c4a9ba9f 100644 --- a/include/linux/ktime.h +++ b/include/linux/ktime.h @@ -196,6 +196,14 @@ static inline s64 ktime_divns(const ktime_t kt, s64 div) } #endif +/* + * ktime_nz - Check whether a ktime_v variable is non-zero + */ +static inline int ktime_nz(const ktime_t kt) +{ + return kt.tv64 != 0LL; +} + static inline s64 ktime_to_us(const ktime_t kt) { return ktime_divns(kt, NSEC_PER_USEC); diff --git a/kernel/dtrace/dtrace_os.c b/kernel/dtrace/dtrace_os.c index 4a371c867302..a15d36a2a9d9 100644 --- a/kernel/dtrace/dtrace_os.c +++ b/kernel/dtrace/dtrace_os.c @@ -251,8 +251,10 @@ void dtrace_psinfo_free(dtrace_psinfo_t *psinfo) } /*---------------------------------------------------------------------------*\ -(* TIME QUERIES *) +(* TIME SUPPORT FUNCTIONS *) \*---------------------------------------------------------------------------*/ +dtrace_vtime_state_t dtrace_vtime_active = 0; + /* * Return a high resolution timer value that is guaranteed to always increase. */ @@ -277,6 +279,52 @@ ktime_t dtrace_getwalltime(void) } EXPORT_SYMBOL(dtrace_getwalltime); +void dtrace_vtime_enable(void) +{ + dtrace_vtime_state_t old, new; + + do { + old = dtrace_vtime_active; + if (old == DTRACE_VTIME_ACTIVE) { + pr_warn_once("DTrace virtual time already enabled"); + return; + } + + new = DTRACE_VTIME_ACTIVE; + } while (cmpxchg(&dtrace_vtime_active, old, new) != old); +} +EXPORT_SYMBOL(dtrace_vtime_enable); + +void dtrace_vtime_disable(void) +{ + int old, new; + + do { + old = dtrace_vtime_active; + if (old == DTRACE_VTIME_INACTIVE) { + pr_warn_once("DTrace virtual time already disabled"); + return; + } + + new = DTRACE_VTIME_INACTIVE; + } while (cmpxchg(&dtrace_vtime_active, old, new) != old); +} +EXPORT_SYMBOL(dtrace_vtime_disable); + +void dtrace_vtime_switch(struct task_struct *prev, struct task_struct *next) +{ + ktime_t now = dtrace_gethrtime(); + + if (ktime_nz(prev->dtrace_start)) { + prev->dtrace_vtime = ktime_add(prev->dtrace_vtime, + ktime_sub(now, + prev->dtrace_start)); + prev->dtrace_start = ktime_set(0, 0); + } + + next->dtrace_start = now; +} + /*---------------------------------------------------------------------------*\ (* STACK TRACES *) \*---------------------------------------------------------------------------*/ @@ -917,11 +965,9 @@ EXPORT_SYMBOL(dtrace_helpers_fork); int (*dtrace_tracepoint_hit)(fasttrap_machtp_t *, struct pt_regs *); EXPORT_SYMBOL(dtrace_tracepoint_hit); -void dtrace_task_init(struct task_struct *tsk) +void dtrace_task_reinit(struct task_struct *tsk) { tsk->predcache = 0; - tsk->dtrace_vtime = ktime_set(0, 0); - tsk->dtrace_start = ktime_set(0, 0); tsk->dtrace_stop = 0; tsk->dtrace_sig = 0; @@ -930,6 +976,14 @@ void dtrace_task_init(struct task_struct *tsk) tsk->dtrace_tp_count = 0; } +void dtrace_task_init(struct task_struct *tsk) +{ + dtrace_task_reinit(tsk); + + tsk->dtrace_vtime = ktime_set(0, 0); + tsk->dtrace_start = ktime_set(0, 0); +} + void dtrace_task_fork(struct task_struct *tsk, struct task_struct *child) { if (likely(dtrace_helpers_fork == NULL)) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 801a275d5d0e..8c1c58a9c62c 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -74,6 +74,7 @@ #include #include #include +#include #include #include @@ -2220,6 +2221,11 @@ static struct rq *finish_task_switch(struct task_struct *prev) rq->prev_mm = NULL; +#ifdef CONFIG_DTRACE + if (dtrace_vtime_active) + dtrace_vtime_switch(prev, current); +#endif + /* * A task struct has one reference for the use as "current". * If a task dies, then it sets TASK_DEAD in tsk->state and calls