]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
dtrace: vtimestamp implementation
authorKris Van Hees <kris.van.hees@oracle.com>
Tue, 17 Dec 2013 23:08:17 +0000 (18:08 -0500)
committerNick Alcock <nick.alcock@oracle.com>
Tue, 21 Jul 2015 14:29:26 +0000 (15:29 +0100)
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 <dan.duval@oracle.com>
Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com>
Conflicts:
include/linux/ktime.h
kernel/sched/core.c

fs/exec.c
include/linux/dtrace_os.h
include/linux/ktime.h
kernel/dtrace/dtrace_os.c
kernel/sched/core.c

index 98144eb184fdfec9289adfa8a26d364f661e81c0..a30cdfb0e7c0c624c94de091f3fc01e5d797e617 100644 (file)
--- 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;
index 26d67e50b26cc2eba4172b1bb21e545eb66f2387..b2a92573b2cd837e5a187769ec324ad9fc9f37a9 100644 (file)
@@ -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 *);
index 2b6a204bd8d40cfb74db80e19bec216795366e33..f392c4a9ba9f34a589896f3e1867e71c72385f1e 100644 (file)
@@ -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);
index 4a371c867302886b1409aa0c121ff8455b399184..a15d36a2a9d927683048068376994f77ef35edf1 100644 (file)
@@ -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))
index 801a275d5d0e68f29ab1c7db9f98037d338d6355..8c1c58a9c62c8606b6d1bd9c35fca00c236fabb7 100644 (file)
@@ -74,6 +74,7 @@
 #include <linux/binfmts.h>
 #include <linux/context_tracking.h>
 #include <linux/compiler.h>
+#include <linux/dtrace_os.h>
 
 #include <asm/switch_to.h>
 #include <asm/tlb.h>
@@ -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