4528743a1bc9f4e066fb8755d9f5a51658c1c875
[kernel/swap-modules.git] / sampler / swap_sampler_module.c
1 /**
2  * sampler/swap_sampler_module.c
3  * @author Andreev S.V.: SWAP Sampler implementation
4  * @author Alexander Aksenov <a.aksenov@samsung.com>: SWAP sampler porting
5  *
6  * @section LICENSE
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21  *
22  * @section COPYRIGHT
23  *
24  * Copyright (C) Samsung Electronics, 2013
25  *
26  * @section DESCRIPTION
27  *
28  * Timer-based sampling module.
29  */
30
31 #include <asm/ptrace.h>
32 #include <linux/jiffies.h>
33 #include <linux/sched.h>
34 #include <linux/notifier.h>
35 #include <linux/cpu.h>
36 #include <linux/module.h>
37
38 #include <writer/swap_writer_module.h>
39
40 #include "swap_sampler_module.h"
41 #include "swap_sampler_errors.h"
42 #include "kernel_operations.h"
43 #include "sampler_timers.h"
44
45
46 static BLOCKING_NOTIFIER_HEAD(swap_sampler_notifier_list);
47
48 static restart_ret swap_timer_restart(swap_timer *timer)
49 {
50         if (current)
51                 sample_msg(task_pt_regs(current));
52
53         return sampler_timers_restart(timer);
54 }
55
56 static int swap_timer_start(void)
57 {
58         get_online_cpus();
59         sampler_timers_set_run();
60
61         on_each_cpu(sampler_timers_start, swap_timer_restart, 1);
62         put_online_cpus();
63
64         return E_SS_SUCCESS;
65 }
66
67 static void swap_timer_stop(void)
68 {
69         int cpu;
70
71         get_online_cpus();
72
73         for_each_online_cpu(cpu)
74                 sampler_timers_stop(cpu);
75         sampler_timers_set_stop();
76         put_online_cpus();
77 }
78
79 static int __cpuinit swap_cpu_notify(struct notifier_block *self,
80                                     unsigned long action, void *hcpu)
81 {
82         long cpu = (long) hcpu;
83
84         switch (action) {
85         case CPU_ONLINE:
86         case CPU_ONLINE_FROZEN:
87                 smp_call_function_single(cpu, sampler_timers_start,
88                                  swap_timer_restart, 1);
89                 break;
90         case CPU_DEAD:
91         case CPU_DEAD_FROZEN:
92                 sampler_timers_stop(cpu);
93                 break;
94         }
95
96         return NOTIFY_OK;
97 }
98
99 static struct notifier_block __refdata swap_cpu_notifier = {
100         .notifier_call = swap_cpu_notify,
101 };
102
103 static int do_swap_sampler_start(unsigned int timer_quantum)
104 {
105         if (timer_quantum <= 0)
106                 return -EINVAL;
107
108         sampler_timers_set_quantum(timer_quantum);
109         swap_timer_start();
110
111         return 0;
112 }
113
114 static void do_swap_sampler_stop(void)
115 {
116         swap_timer_stop();
117 }
118
119 static DEFINE_MUTEX(mutex_run);
120 static int sampler_run = 0;
121
122
123 /**
124  * @brief Starts sampling with specified timer quantum.
125  *
126  * @param timer_quantum Timer quantum for sampling.
127  * @return 0 on success, error code on error.
128  */
129 int swap_sampler_start(unsigned int timer_quantum)
130 {
131         int ret = -EINVAL;
132
133         mutex_lock(&mutex_run);
134         if (sampler_run) {
135                 printk("sampler profiling is already run!\n");
136                 goto unlock;
137         }
138
139         ret = do_swap_sampler_start(timer_quantum);
140         if (ret == 0)
141                 sampler_run = 1;
142
143 unlock:
144         mutex_unlock(&mutex_run);
145
146         return ret;
147 }
148 EXPORT_SYMBOL_GPL(swap_sampler_start);
149
150
151 /**
152  * @brief Stops sampling.
153  *
154  * @return 0 on success, error code on error.
155  */
156 int swap_sampler_stop(void)
157 {
158         int ret = 0;
159
160         mutex_lock(&mutex_run);
161         if (sampler_run == 0) {
162                 printk("energy profiling is not running!\n");
163                 ret = -EINVAL;
164                 goto unlock;
165         }
166
167         do_swap_sampler_stop();
168
169         sampler_run = 0;
170 unlock:
171         mutex_unlock(&mutex_run);
172
173         return ret;
174 }
175 EXPORT_SYMBOL_GPL(swap_sampler_stop);
176
177 static int __init sampler_init(void)
178 {
179         int retval;
180
181         retval = register_hotcpu_notifier(&swap_cpu_notifier);
182         if (retval) {
183                 print_err("Error of register_hotcpu_notifier()\n");
184                 return retval;
185         }
186
187         print_msg("Sample ininitialization success\n");
188
189         return E_SS_SUCCESS;
190 }
191
192 static void __exit sampler_exit(void)
193 {
194         if (sampler_run)
195                 do_swap_sampler_stop();
196
197         unregister_hotcpu_notifier(&swap_cpu_notifier);
198
199         print_msg("Sampler uninitialized\n");
200 }
201
202 module_init(sampler_init);
203 module_exit(sampler_exit);
204
205 MODULE_LICENSE("GPL");
206 MODULE_DESCRIPTION("SWAP sampling module");
207 MODULE_AUTHOR("Andreev S.V., Aksenov A.S.");