98e54a0f2399e3a02d3d6012f50a638831278f31
[platform/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 "swap_sampler_module.h"
39 #include "swap_sampler_errors.h"
40 #include "kernel_operations.h"
41 #include "sampler_timers.h"
42
43
44 static BLOCKING_NOTIFIER_HEAD(swap_sampler_notifier_list);
45 static swap_sample_cb_t sampler_cb;
46
47 static restart_ret swap_timer_restart(swap_timer *timer)
48 {
49         sampler_cb(task_pt_regs(current));
50
51         return sampler_timers_restart(timer);
52 }
53
54 static int swap_timer_start(void)
55 {
56         get_online_cpus();
57         sampler_timers_set_run();
58
59         on_each_cpu(sampler_timers_start, swap_timer_restart, 1);
60         put_online_cpus();
61
62         return E_SS_SUCCESS;
63 }
64
65 static void swap_timer_stop(void)
66 {
67         int cpu;
68
69         get_online_cpus();
70
71         for_each_online_cpu(cpu)
72                 sampler_timers_stop(cpu);
73         sampler_timers_set_stop();
74         put_online_cpus();
75 }
76
77 static int __cpuinit swap_cpu_notify(struct notifier_block *self,
78                                     unsigned long action, void *hcpu)
79 {
80         long cpu = (long) hcpu;
81
82         switch (action) {
83         case CPU_ONLINE:
84         case CPU_ONLINE_FROZEN:
85                 smp_call_function_single(cpu, sampler_timers_start,
86                                  swap_timer_restart, 1);
87                 break;
88         case CPU_DEAD:
89         case CPU_DEAD_FROZEN:
90                 sampler_timers_stop(cpu);
91                 break;
92         }
93
94         return NOTIFY_OK;
95 }
96
97 static struct notifier_block __refdata swap_cpu_notifier = {
98         .notifier_call = swap_cpu_notify,
99 };
100
101 static int do_swap_sampler_start(unsigned int timer_quantum)
102 {
103         if (timer_quantum <= 0)
104                 return -EINVAL;
105
106         sampler_timers_set_quantum(timer_quantum);
107         swap_timer_start();
108
109         return 0;
110 }
111
112 static void do_swap_sampler_stop(void)
113 {
114         swap_timer_stop();
115 }
116
117 static DEFINE_MUTEX(mutex_run);
118 static int sampler_run;
119
120
121 /**
122  * @brief Starts sampling with specified timer quantum.
123  *
124  * @param timer_quantum Timer quantum for sampling.
125  * @return 0 on success, error code on error.
126  */
127 int swap_sampler_start(unsigned int timer_quantum, swap_sample_cb_t cb)
128 {
129         int ret = -EINVAL;
130
131         mutex_lock(&mutex_run);
132         if (sampler_run) {
133                 printk(KERN_INFO "sampler profiling is already run!\n");
134                 goto unlock;
135         }
136
137         sampler_cb = cb;
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(KERN_INFO "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.");