Merge branch 'linus' into tracing/ftrace
authorIngo Molnar <mingo@elte.hu>
Thu, 30 Oct 2008 23:38:21 +0000 (00:38 +0100)
committerIngo Molnar <mingo@elte.hu>
Thu, 30 Oct 2008 23:38:21 +0000 (00:38 +0100)
include/linux/ftrace.h
kernel/sysctl.c
kernel/trace/trace.c
scripts/tracing/draw_functrace.py [new file with mode: 0644]

index 703eb53..899ec4b 100644 (file)
@@ -181,6 +181,8 @@ static inline void __ftrace_enabled_restore(int enabled)
 #endif
 
 #ifdef CONFIG_TRACING
+extern int ftrace_dump_on_oops;
+
 extern void
 ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3);
 
index 9d048fa..6b6b727 100644 (file)
@@ -484,6 +484,16 @@ static struct ctl_table kern_table[] = {
                .proc_handler   = &ftrace_enable_sysctl,
        },
 #endif
+#ifdef CONFIG_TRACING
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "ftrace_dump_on_opps",
+               .data           = &ftrace_dump_on_oops,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
+#endif
 #ifdef CONFIG_MODULES
        {
                .ctl_name       = KERN_MODPROBE,
index a610ca7..8741e5c 100644 (file)
@@ -64,6 +64,28 @@ static cpumask_t __read_mostly               tracing_buffer_mask;
 
 static int tracing_disabled = 1;
 
+/*
+ * ftrace_dump_on_oops - variable to dump ftrace buffer on oops
+ *
+ * If there is an oops (or kernel panic) and the ftrace_dump_on_oops
+ * is set, then ftrace_dump is called. This will output the contents
+ * of the ftrace buffers to the console.  This is very useful for
+ * capturing traces that lead to crashes and outputing it to a
+ * serial console.
+ *
+ * It is default off, but you can enable it with either specifying
+ * "ftrace_dump_on_oops" in the kernel command line, or setting
+ * /proc/sys/kernel/ftrace_dump_on_oops to true.
+ */
+int ftrace_dump_on_oops;
+
+static int __init set_ftrace_dump_on_oops(char *str)
+{
+       ftrace_dump_on_oops = 1;
+       return 1;
+}
+__setup("ftrace_dump_on_oops", set_ftrace_dump_on_oops);
+
 long
 ns2usecs(cycle_t nsec)
 {
@@ -3020,7 +3042,8 @@ EXPORT_SYMBOL_GPL(__ftrace_printk);
 static int trace_panic_handler(struct notifier_block *this,
                               unsigned long event, void *unused)
 {
-       ftrace_dump();
+       if (ftrace_dump_on_oops)
+               ftrace_dump();
        return NOTIFY_OK;
 }
 
@@ -3036,7 +3059,8 @@ static int trace_die_handler(struct notifier_block *self,
 {
        switch (val) {
        case DIE_OOPS:
-               ftrace_dump();
+               if (ftrace_dump_on_oops)
+                       ftrace_dump();
                break;
        default:
                break;
@@ -3077,7 +3101,6 @@ trace_printk_seq(struct trace_seq *s)
        trace_seq_reset(s);
 }
 
-
 void ftrace_dump(void)
 {
        static DEFINE_SPINLOCK(ftrace_dump_lock);
diff --git a/scripts/tracing/draw_functrace.py b/scripts/tracing/draw_functrace.py
new file mode 100644 (file)
index 0000000..902f9a9
--- /dev/null
@@ -0,0 +1,130 @@
+#!/usr/bin/python
+
+"""
+Copyright 2008 (c) Frederic Weisbecker <fweisbec@gmail.com>
+Licensed under the terms of the GNU GPL License version 2
+
+This script parses a trace provided by the function tracer in
+kernel/trace/trace_functions.c
+The resulted trace is processed into a tree to produce a more human
+view of the call stack by drawing textual but hierarchical tree of
+calls. Only the functions's names and the the call time are provided.
+
+Usage:
+       Be sure that you have CONFIG_FUNCTION_TRACER
+       # mkdir /debugfs
+       # mount -t debug debug /debug
+       # echo function > /debug/tracing/current_tracer
+       $ cat /debug/tracing/trace_pipe > ~/raw_trace_func
+       Wait some times but not too much, the script is a bit slow.
+       Break the pipe (Ctrl + Z)
+       $ scripts/draw_functrace.py < raw_trace_func > draw_functrace
+       Then you have your drawn trace in draw_functrace
+"""
+
+
+import sys, re
+
+class CallTree:
+       """ This class provides a tree representation of the functions
+               call stack. If a function has no parent in the kernel (interrupt,
+               syscall, kernel thread...) then it is attached to a virtual parent
+               called ROOT.
+       """
+       ROOT = None
+
+       def __init__(self, func, time = None, parent = None):
+               self._func = func
+               self._time = time
+               if parent is None:
+                       self._parent = CallTree.ROOT
+               else:
+                       self._parent = parent
+               self._children = []
+
+       def calls(self, func, calltime):
+               """ If a function calls another one, call this method to insert it
+                       into the tree at the appropriate place.
+                       @return: A reference to the newly created child node.
+               """
+               child = CallTree(func, calltime, self)
+               self._children.append(child)
+               return child
+
+       def getParent(self, func):
+               """ Retrieve the last parent of the current node that
+                       has the name given by func. If this function is not
+                       on a parent, then create it as new child of root
+                       @return: A reference to the parent.
+               """
+               tree = self
+               while tree != CallTree.ROOT and tree._func != func:
+                       tree = tree._parent
+               if tree == CallTree.ROOT:
+                       child = CallTree.ROOT.calls(func, None)
+                       return child
+               return tree
+
+       def __repr__(self):
+               return self.__toString("", True)
+
+       def __toString(self, branch, lastChild):
+               if self._time is not None:
+                       s = "%s----%s (%s)\n" % (branch, self._func, self._time)
+               else:
+                       s = "%s----%s\n" % (branch, self._func)
+
+               i = 0
+               if lastChild:
+                       branch = branch[:-1] + " "
+               while i < len(self._children):
+                       if i != len(self._children) - 1:
+                               s += "%s" % self._children[i].__toString(branch +\
+                                                               "    |", False)
+                       else:
+                               s += "%s" % self._children[i].__toString(branch +\
+                                                               "    |", True)
+                       i += 1
+               return s
+
+class BrokenLineException(Exception):
+       """If the last line is not complete because of the pipe breakage,
+          we want to stop the processing and ignore this line.
+       """
+       pass
+
+class CommentLineException(Exception):
+       """ If the line is a comment (as in the beginning of the trace file),
+           just ignore it.
+       """
+       pass
+
+
+def parseLine(line):
+       line = line.strip()
+       if line.startswith("#"):
+               raise CommentLineException
+       m = re.match("[^]]+?\\] +([0-9.]+): (\\w+) <-(\\w+)", line)
+       if m is None:
+               raise BrokenLineException
+       return (m.group(1), m.group(2), m.group(3))
+
+
+def main():
+       CallTree.ROOT = CallTree("Root (Nowhere)", None, None)
+       tree = CallTree.ROOT
+
+       for line in sys.stdin:
+               try:
+                       calltime, callee, caller = parseLine(line)
+               except BrokenLineException:
+                       break
+               except CommentLineException:
+                       continue
+               tree = tree.getParent(caller)
+               tree = tree.calls(callee, calltime)
+
+       print CallTree.ROOT
+
+if __name__ == "__main__":
+       main()