diff options
author | Steven Rostedt <rostedt@goodmis.org> | 2008-08-14 15:45:08 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-14 04:34:44 -0400 |
commit | 68bf21aa15c85d2e9b623dcda2b1ed8893275fa1 (patch) | |
tree | 54d4d4f7e8311b77f3166a8807a635347d479081 /kernel | |
parent | 8da3821ba5634497da63d58a69e24a97697c4a2b (diff) |
ftrace: mcount call site on boot nops core
This is the infrastructure to the converting the mcount call sites
recorded by the __mcount_loc section into nops on boot. It also allows
for using these sites to enable tracing as normal. When the __mcount_loc
section is used, the "ftraced" kernel thread is disabled.
This uses the current infrastructure to record the mcount call sites
as well as convert them to nops. The mcount function is kept as a stub
on boot up and not converted to the ftrace_record_ip function. We use the
ftrace_record_ip to only record from the table.
This patch does not handle modules. That comes with a later patch.
Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/trace/ftrace.c | 148 |
1 files changed, 105 insertions, 43 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index f6e3af31b403..df96d5990c04 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -792,47 +792,7 @@ static int ftrace_update_code(void) | |||
792 | return 1; | 792 | return 1; |
793 | } | 793 | } |
794 | 794 | ||
795 | static int ftraced(void *ignore) | 795 | static int __init ftrace_dyn_table_alloc(unsigned long num_to_init) |
796 | { | ||
797 | unsigned long usecs; | ||
798 | |||
799 | while (!kthread_should_stop()) { | ||
800 | |||
801 | set_current_state(TASK_INTERRUPTIBLE); | ||
802 | |||
803 | /* check once a second */ | ||
804 | schedule_timeout(HZ); | ||
805 | |||
806 | if (unlikely(ftrace_disabled)) | ||
807 | continue; | ||
808 | |||
809 | mutex_lock(&ftrace_sysctl_lock); | ||
810 | mutex_lock(&ftraced_lock); | ||
811 | if (!ftraced_suspend && !ftraced_stop && | ||
812 | ftrace_update_code()) { | ||
813 | usecs = nsecs_to_usecs(ftrace_update_time); | ||
814 | if (ftrace_update_tot_cnt > 100000) { | ||
815 | ftrace_update_tot_cnt = 0; | ||
816 | pr_info("hm, dftrace overflow: %lu change%s" | ||
817 | " (%lu total) in %lu usec%s\n", | ||
818 | ftrace_update_cnt, | ||
819 | ftrace_update_cnt != 1 ? "s" : "", | ||
820 | ftrace_update_tot_cnt, | ||
821 | usecs, usecs != 1 ? "s" : ""); | ||
822 | ftrace_disabled = 1; | ||
823 | WARN_ON_ONCE(1); | ||
824 | } | ||
825 | } | ||
826 | mutex_unlock(&ftraced_lock); | ||
827 | mutex_unlock(&ftrace_sysctl_lock); | ||
828 | |||
829 | ftrace_shutdown_replenish(); | ||
830 | } | ||
831 | __set_current_state(TASK_RUNNING); | ||
832 | return 0; | ||
833 | } | ||
834 | |||
835 | static int __init ftrace_dyn_table_alloc(void) | ||
836 | { | 796 | { |
837 | struct ftrace_page *pg; | 797 | struct ftrace_page *pg; |
838 | int cnt; | 798 | int cnt; |
@@ -859,7 +819,9 @@ static int __init ftrace_dyn_table_alloc(void) | |||
859 | 819 | ||
860 | pg = ftrace_pages = ftrace_pages_start; | 820 | pg = ftrace_pages = ftrace_pages_start; |
861 | 821 | ||
862 | cnt = NR_TO_INIT / ENTRIES_PER_PAGE; | 822 | cnt = num_to_init / ENTRIES_PER_PAGE; |
823 | pr_info("ftrace: allocating %ld hash entries in %d pages\n", | ||
824 | num_to_init, cnt); | ||
863 | 825 | ||
864 | for (i = 0; i < cnt; i++) { | 826 | for (i = 0; i < cnt; i++) { |
865 | pg->next = (void *)get_zeroed_page(GFP_KERNEL); | 827 | pg->next = (void *)get_zeroed_page(GFP_KERNEL); |
@@ -1556,6 +1518,104 @@ static __init int ftrace_init_debugfs(void) | |||
1556 | 1518 | ||
1557 | fs_initcall(ftrace_init_debugfs); | 1519 | fs_initcall(ftrace_init_debugfs); |
1558 | 1520 | ||
1521 | #ifdef CONFIG_FTRACE_MCOUNT_RECORD | ||
1522 | static int ftrace_convert_nops(unsigned long *start, | ||
1523 | unsigned long *end) | ||
1524 | { | ||
1525 | unsigned long *p; | ||
1526 | unsigned long addr; | ||
1527 | unsigned long flags; | ||
1528 | |||
1529 | p = start; | ||
1530 | while (p < end) { | ||
1531 | addr = ftrace_call_adjust(*p++); | ||
1532 | ftrace_record_ip(addr); | ||
1533 | ftrace_shutdown_replenish(); | ||
1534 | } | ||
1535 | |||
1536 | /* p is ignored */ | ||
1537 | local_irq_save(flags); | ||
1538 | __ftrace_update_code(p); | ||
1539 | local_irq_restore(flags); | ||
1540 | |||
1541 | return 0; | ||
1542 | } | ||
1543 | |||
1544 | extern unsigned long __start_mcount_loc[]; | ||
1545 | extern unsigned long __stop_mcount_loc[]; | ||
1546 | |||
1547 | void __init ftrace_init(void) | ||
1548 | { | ||
1549 | unsigned long count, addr, flags; | ||
1550 | int ret; | ||
1551 | |||
1552 | /* Keep the ftrace pointer to the stub */ | ||
1553 | addr = (unsigned long)ftrace_stub; | ||
1554 | |||
1555 | local_irq_save(flags); | ||
1556 | ftrace_dyn_arch_init(&addr); | ||
1557 | local_irq_restore(flags); | ||
1558 | |||
1559 | /* ftrace_dyn_arch_init places the return code in addr */ | ||
1560 | if (addr) | ||
1561 | goto failed; | ||
1562 | |||
1563 | count = __stop_mcount_loc - __start_mcount_loc; | ||
1564 | |||
1565 | ret = ftrace_dyn_table_alloc(count); | ||
1566 | if (ret) | ||
1567 | goto failed; | ||
1568 | |||
1569 | last_ftrace_enabled = ftrace_enabled = 1; | ||
1570 | |||
1571 | ret = ftrace_convert_nops(__start_mcount_loc, | ||
1572 | __stop_mcount_loc); | ||
1573 | |||
1574 | return; | ||
1575 | failed: | ||
1576 | ftrace_disabled = 1; | ||
1577 | } | ||
1578 | #else /* CONFIG_FTRACE_MCOUNT_RECORD */ | ||
1579 | static int ftraced(void *ignore) | ||
1580 | { | ||
1581 | unsigned long usecs; | ||
1582 | |||
1583 | while (!kthread_should_stop()) { | ||
1584 | |||
1585 | set_current_state(TASK_INTERRUPTIBLE); | ||
1586 | |||
1587 | /* check once a second */ | ||
1588 | schedule_timeout(HZ); | ||
1589 | |||
1590 | if (unlikely(ftrace_disabled)) | ||
1591 | continue; | ||
1592 | |||
1593 | mutex_lock(&ftrace_sysctl_lock); | ||
1594 | mutex_lock(&ftraced_lock); | ||
1595 | if (!ftraced_suspend && !ftraced_stop && | ||
1596 | ftrace_update_code()) { | ||
1597 | usecs = nsecs_to_usecs(ftrace_update_time); | ||
1598 | if (ftrace_update_tot_cnt > 100000) { | ||
1599 | ftrace_update_tot_cnt = 0; | ||
1600 | pr_info("hm, dftrace overflow: %lu change%s" | ||
1601 | " (%lu total) in %lu usec%s\n", | ||
1602 | ftrace_update_cnt, | ||
1603 | ftrace_update_cnt != 1 ? "s" : "", | ||
1604 | ftrace_update_tot_cnt, | ||
1605 | usecs, usecs != 1 ? "s" : ""); | ||
1606 | ftrace_disabled = 1; | ||
1607 | WARN_ON_ONCE(1); | ||
1608 | } | ||
1609 | } | ||
1610 | mutex_unlock(&ftraced_lock); | ||
1611 | mutex_unlock(&ftrace_sysctl_lock); | ||
1612 | |||
1613 | ftrace_shutdown_replenish(); | ||
1614 | } | ||
1615 | __set_current_state(TASK_RUNNING); | ||
1616 | return 0; | ||
1617 | } | ||
1618 | |||
1559 | static int __init ftrace_dynamic_init(void) | 1619 | static int __init ftrace_dynamic_init(void) |
1560 | { | 1620 | { |
1561 | struct task_struct *p; | 1621 | struct task_struct *p; |
@@ -1572,7 +1632,7 @@ static int __init ftrace_dynamic_init(void) | |||
1572 | goto failed; | 1632 | goto failed; |
1573 | } | 1633 | } |
1574 | 1634 | ||
1575 | ret = ftrace_dyn_table_alloc(); | 1635 | ret = ftrace_dyn_table_alloc(NR_TO_INIT); |
1576 | if (ret) | 1636 | if (ret) |
1577 | goto failed; | 1637 | goto failed; |
1578 | 1638 | ||
@@ -1593,6 +1653,8 @@ static int __init ftrace_dynamic_init(void) | |||
1593 | } | 1653 | } |
1594 | 1654 | ||
1595 | core_initcall(ftrace_dynamic_init); | 1655 | core_initcall(ftrace_dynamic_init); |
1656 | #endif /* CONFIG_FTRACE_MCOUNT_RECORD */ | ||
1657 | |||
1596 | #else | 1658 | #else |
1597 | # define ftrace_startup() do { } while (0) | 1659 | # define ftrace_startup() do { } while (0) |
1598 | # define ftrace_shutdown() do { } while (0) | 1660 | # define ftrace_shutdown() do { } while (0) |