ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / kernel / profile.c
1 /*
2  *  linux/kernel/profile.c
3  */
4
5 #include <linux/config.h>
6 #include <linux/module.h>
7 #include <linux/profile.h>
8 #include <linux/bootmem.h>
9 #include <linux/notifier.h>
10 #include <linux/mm.h>
11 #include <asm/sections.h>
12
13 unsigned int * prof_buffer;
14 unsigned long prof_len;
15 unsigned long prof_shift;
16 int prof_on;
17
18 int __init profile_setup(char * str)
19 {
20         int par;
21         if (get_option(&str,&par)) {
22                 prof_shift = par;
23                 prof_on = 1;
24                 printk(KERN_INFO "kernel profiling enabled\n");
25         }
26         return 1;
27 }
28
29
30 void __init profile_init(void)
31 {
32         unsigned int size;
33  
34         if (!prof_on) 
35                 return;
36  
37         /* only text is profiled */
38         prof_len = _etext - _stext;
39         prof_len >>= prof_shift;
40                 
41         size = prof_len * sizeof(unsigned int) + PAGE_SIZE - 1;
42         prof_buffer = (unsigned int *) alloc_bootmem(size);
43 }
44
45 /* Profile event notifications */
46  
47 #ifdef CONFIG_PROFILING
48  
49 static DECLARE_RWSEM(profile_rwsem);
50 static struct notifier_block * exit_task_notifier;
51 static struct notifier_block * exit_mmap_notifier;
52 static struct notifier_block * exec_unmap_notifier;
53  
54 void profile_exit_task(struct task_struct * task)
55 {
56         down_read(&profile_rwsem);
57         notifier_call_chain(&exit_task_notifier, 0, task);
58         up_read(&profile_rwsem);
59 }
60  
61 void profile_exit_mmap(struct mm_struct * mm)
62 {
63         down_read(&profile_rwsem);
64         notifier_call_chain(&exit_mmap_notifier, 0, mm);
65         up_read(&profile_rwsem);
66 }
67
68 void profile_exec_unmap(struct mm_struct * mm)
69 {
70         down_read(&profile_rwsem);
71         notifier_call_chain(&exec_unmap_notifier, 0, mm);
72         up_read(&profile_rwsem);
73 }
74
75 int profile_event_register(enum profile_type type, struct notifier_block * n)
76 {
77         int err = -EINVAL;
78  
79         down_write(&profile_rwsem);
80  
81         switch (type) {
82                 case EXIT_TASK:
83                         err = notifier_chain_register(&exit_task_notifier, n);
84                         break;
85                 case EXIT_MMAP:
86                         err = notifier_chain_register(&exit_mmap_notifier, n);
87                         break;
88                 case EXEC_UNMAP:
89                         err = notifier_chain_register(&exec_unmap_notifier, n);
90                         break;
91         }
92  
93         up_write(&profile_rwsem);
94  
95         return err;
96 }
97
98  
99 int profile_event_unregister(enum profile_type type, struct notifier_block * n)
100 {
101         int err = -EINVAL;
102  
103         down_write(&profile_rwsem);
104  
105         switch (type) {
106                 case EXIT_TASK:
107                         err = notifier_chain_unregister(&exit_task_notifier, n);
108                         break;
109                 case EXIT_MMAP:
110                         err = notifier_chain_unregister(&exit_mmap_notifier, n);
111                         break;
112                 case EXEC_UNMAP:
113                         err = notifier_chain_unregister(&exec_unmap_notifier, n);
114                         break;
115         }
116
117         up_write(&profile_rwsem);
118         return err;
119 }
120
121 static struct notifier_block * profile_listeners;
122 static rwlock_t profile_lock = RW_LOCK_UNLOCKED;
123  
124 int register_profile_notifier(struct notifier_block * nb)
125 {
126         int err;
127         write_lock_irq(&profile_lock);
128         err = notifier_chain_register(&profile_listeners, nb);
129         write_unlock_irq(&profile_lock);
130         return err;
131 }
132
133
134 int unregister_profile_notifier(struct notifier_block * nb)
135 {
136         int err;
137         write_lock_irq(&profile_lock);
138         err = notifier_chain_unregister(&profile_listeners, nb);
139         write_unlock_irq(&profile_lock);
140         return err;
141 }
142
143
144 void profile_hook(struct pt_regs * regs)
145 {
146         read_lock(&profile_lock);
147         notifier_call_chain(&profile_listeners, 0, regs);
148         read_unlock(&profile_lock);
149 }
150
151 EXPORT_SYMBOL_GPL(register_profile_notifier);
152 EXPORT_SYMBOL_GPL(unregister_profile_notifier);
153
154 #endif /* CONFIG_PROFILING */
155
156 EXPORT_SYMBOL_GPL(profile_event_register);
157 EXPORT_SYMBOL_GPL(profile_event_unregister);