[IMPROVE] Driver: implement kernel -> user connect
[kernel/swap-modules.git] / energy / energy.c
1 /*
2  *  Dynamic Binary Instrumentation Module based on KProbes
3  *  modules/energy/swap_energy.c
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  *
19  * Copyright (C) Samsung Electronics, 2013
20  *
21  * 2013         Vasiliy Ulyanov <v.ulyanov@samsung.com>
22  *              Vyacheslav Cherkashin <v.cherkashin@samsung.com>
23  *
24  */
25
26
27 #include <linux/module.h>
28 #include <linux/file.h>
29 #include <linux/spinlock.h>
30 #include <linux/magic.h>
31 #include <linux/slab.h>
32 #include <kprobe/dbi_kprobes.h>
33 #include <ksyms/ksyms.h>
34 #include <us_manager/sspt/sspt_proc.h>
35 #include <us_manager/sspt/sspt_feature.h>
36 #include <linux/atomic.h>
37 #include "energy.h"
38 #include "lcd/lcd_base.h"
39 #include "tm_stat.h"
40
41
42 /* ============================================================================
43  * =                              CPUS_TIME                                   =
44  * ============================================================================
45  */
46 struct cpus_time {
47         struct tm_stat tm[NR_CPUS];
48 };
49
50 static void cpus_time_init(struct cpus_time *ct, u64 time)
51 {
52         int cpu;
53
54         for (cpu = 0; cpu < NR_CPUS; ++cpu) {
55                 tm_stat_init(&ct->tm[cpu]);
56                 tm_stat_set_timestamp(&ct->tm[cpu], time);
57         }
58 }
59
60 static u64 cpus_time_get_running_all(struct cpus_time *ct)
61 {
62         u64 time = 0;
63         int cpu;
64
65         for (cpu = 0; cpu < NR_CPUS; ++cpu)
66                 time += tm_stat_running(&ct->tm[cpu]);
67
68         return time;
69 }
70
71 static void cpus_time_save_entry(struct cpus_time *ct, int cpu, u64 time)
72 {
73         tm_stat_set_timestamp(&ct->tm[cpu], time);
74 }
75
76 static void cpus_time_update_running(struct cpus_time *ct, int cpu, u64 time)
77 {
78         tm_stat_update(&ct->tm[cpu], time);
79 }
80
81
82
83
84
85 struct energy_data {
86         /* for __switch_to */
87         struct cpus_time ct;
88
89         /* for sys_read */
90         atomic64_t bytes_read;
91
92         /*for sys_write */
93         atomic64_t bytes_written;
94
95 };
96
97 static sspt_feature_id_t feature_id = SSPT_FEATURE_ID_BAD;
98
99 static void init_ed(struct energy_data *ed)
100 {
101         cpus_time_init(&ed->ct, get_ntime());
102         atomic64_set(&ed->bytes_read, 0);
103         atomic64_set(&ed->bytes_written, 0);
104 }
105
106 static void uninit_ed(struct energy_data *ed)
107 {
108         cpus_time_init(&ed->ct, 0);
109         atomic64_set(&ed->bytes_read, 0);
110         atomic64_set(&ed->bytes_written, 0);
111 }
112
113 static void *create_ed(void)
114 {
115         struct energy_data *ed;
116
117         ed = kmalloc(sizeof(*ed), GFP_ATOMIC);
118         if (ed)
119                 init_ed(ed);
120
121         return (void *)ed;
122 }
123
124 static void destroy_ed(void *data)
125 {
126         struct energy_data *ed = (struct energy_data *)data;
127         kfree(ed);
128 }
129
130
131 static int init_feature(void)
132 {
133         feature_id = sspt_register_feature(create_ed, destroy_ed);
134
135         if (feature_id == SSPT_FEATURE_ID_BAD)
136                 return -EPERM;
137
138         return 0;
139 }
140
141 static void uninit_feature(void)
142 {
143         sspt_unregister_feature(feature_id);
144         feature_id = SSPT_FEATURE_ID_BAD;
145 }
146
147 static struct energy_data *get_energy_data(struct task_struct *task)
148 {
149         void *data = NULL;
150         struct sspt_proc *proc;
151
152         proc = sspt_proc_get_by_task(task);
153         if (proc)
154                 data = sspt_get_feature_data(proc->feature, feature_id);
155
156         return (struct energy_data *)data;
157 }
158
159 static int check_fs(unsigned long magic)
160 {
161         switch (magic) {
162         case EXT2_SUPER_MAGIC: /* == EXT3_SUPER_MAGIC == EXT4_SUPER_MAGIC */
163         case MSDOS_SUPER_MAGIC:
164                 return 1;
165         }
166
167         return 0;
168 }
169
170 static int check_ftype(int fd)
171 {
172         int err, ret = 0;
173         struct kstat kstat;
174
175         err = vfs_fstat(fd, &kstat);
176         if (err == 0 && S_ISREG(kstat.mode))
177                 ret = 1;
178
179         return ret;
180 }
181
182 static int check_file(int fd)
183 {
184         struct file *file;
185
186         file = fget(fd);
187         if (file) {
188                 int magic = 0;
189                 if (file->f_dentry && file->f_dentry->d_sb)
190                         magic = file->f_dentry->d_sb->s_magic;
191
192                 fput(file);
193
194                 if (check_fs(magic) && check_ftype(fd))
195                         return 1;
196         }
197
198         return 0;
199 }
200
201 static unsigned long get_arg0(struct pt_regs *regs)
202 {
203 #if defined(CONFIG_ARM)
204         return regs->ARM_r0;
205 #elif defined(CONFIG_X86_32)
206         return regs->bx;
207 #else
208         #error "this architecture is not supported"
209 #endif /* CONFIG_arch */
210 }
211
212
213
214
215
216 static struct cpus_time ct_idle;
217 static struct energy_data ed_system;
218
219 static void init_data_energy(void)
220 {
221         init_ed(&ed_system);
222         cpus_time_init(&ct_idle, get_ntime());
223 }
224
225 static void uninit_data_energy(void)
226 {
227         uninit_ed(&ed_system);
228         cpus_time_init(&ct_idle, 0);
229 }
230
231
232
233
234
235 /* ============================================================================
236  * =                             __switch_to                                  =
237  * ============================================================================
238  */
239 static int entry_handler_switch(struct kretprobe_instance *ri, struct pt_regs *regs)
240 {
241         int cpu;
242         u64 time;
243         struct cpus_time* ct;
244         struct energy_data *ed;
245
246         cpu = smp_processor_id();
247         time = get_ntime();
248         ct = current->tgid ? &ed_system.ct : &ct_idle;
249         cpus_time_update_running(ct, cpu, time);
250
251         ed = get_energy_data(current);
252         if (ed)
253                 cpus_time_update_running(&ed->ct, cpu, time);
254
255         return 0;
256 }
257
258 static int ret_handler_switch(struct kretprobe_instance *ri, struct pt_regs *regs)
259 {
260         int cpu;
261         u64 time;
262         struct cpus_time* ct;
263         struct energy_data *ed;
264
265         cpu = smp_processor_id();
266         time = get_ntime();
267         ct = current->tgid ? &ed_system.ct : &ct_idle;
268         cpus_time_save_entry(ct, cpu, time);
269
270         ed = get_energy_data(current);
271         if (ed)
272                 cpus_time_save_entry(&ed->ct, cpu, time);
273
274         return 0;
275 }
276
277 static struct kretprobe switch_to_krp = {
278         .entry_handler = entry_handler_switch,
279         .handler = ret_handler_switch,
280 };
281
282
283
284
285
286 /* ============================================================================
287  * =                                sys_read                                  =
288  * ============================================================================
289  */
290 struct sys_read_data {
291         int fd;
292 };
293
294 static int entry_handler_sys_read(struct kretprobe_instance *ri, struct pt_regs *regs)
295 {
296         struct sys_read_data *srd = (struct sys_read_data *)ri->data;
297
298         srd->fd = (int)get_arg0(regs);
299
300         return 0;
301 }
302
303 static int ret_handler_sys_read(struct kretprobe_instance *ri,
304                                 struct pt_regs *regs)
305 {
306         int ret = regs_return_value(regs);
307
308         if (ret > 0) {
309                 struct sys_read_data *srd;
310
311                 srd = (struct sys_read_data *)ri->data;
312                 if (check_file(srd->fd)) {
313                         struct energy_data *ed;
314
315                         ed = get_energy_data(current);
316                         if (ed)
317                                 atomic64_add(ret, &ed->bytes_read);
318
319                         atomic64_add(ret, &ed_system.bytes_read);
320                 }
321         }
322
323         return 0;
324 }
325
326 static struct kretprobe sys_read_krp = {
327         .entry_handler = entry_handler_sys_read,
328         .handler = ret_handler_sys_read,
329         .data_size = sizeof(struct sys_read_data)
330 };
331
332
333
334
335
336 /* ============================================================================
337  * =                               sys_write                                  =
338  * ============================================================================
339  */
340 static int entry_handler_sys_write(struct kretprobe_instance *ri, struct pt_regs *regs)
341 {
342         struct sys_read_data *srd = (struct sys_read_data *)ri->data;
343
344         srd->fd = (int)get_arg0(regs);
345
346         return 0;
347 }
348
349 static int ret_handler_sys_write(struct kretprobe_instance *ri, struct pt_regs *regs)
350 {
351         int ret = regs_return_value(regs);
352
353         if (ret > 0) {
354                 struct sys_read_data *srd;
355
356                 srd = (struct sys_read_data *)ri->data;
357                 if (check_file(srd->fd)) {
358                         struct energy_data *ed;
359
360                         ed = get_energy_data(current);
361                         if (ed)
362                                 atomic64_add(ret, &ed->bytes_written);
363
364                         atomic64_add(ret, &ed_system.bytes_written);
365                 }
366         }
367
368         return 0;
369 }
370
371 static struct kretprobe sys_write_krp = {
372         .entry_handler = entry_handler_sys_write,
373         .handler = ret_handler_sys_write,
374         .data_size = sizeof(struct sys_read_data)
375 };
376
377
378
379
380
381 enum parameter_type {
382         PT_CPU,
383         PT_READ,
384         PT_WRITE
385 };
386
387 struct cmd_pt {
388         enum parameter_type pt;
389         u64 val;
390 };
391
392 static void callback_for_proc(struct sspt_proc *proc, void *data)
393 {
394         void *f_data = sspt_get_feature_data(proc->feature, feature_id);
395         struct energy_data *ed = (struct energy_data *)f_data;
396
397         if (ed) {
398                 struct cmd_pt *cmdp = (struct cmd_pt *)data;
399
400                 switch (cmdp->pt) {
401                 case PT_CPU:
402                         cmdp->val += cpus_time_get_running_all(&ed->ct);
403                         break;
404                 case PT_READ:
405                         cmdp->val += atomic64_read(&ed->bytes_read);
406                         break;
407                 case PT_WRITE:
408                         cmdp->val += atomic64_read(&ed->bytes_written);
409                         break;
410                 default:
411                         break;
412                 }
413         }
414 }
415
416 static u64 current_parameter_apps(enum parameter_type pt)
417 {
418         struct cmd_pt cmdp;
419
420         cmdp.pt = pt;
421         cmdp.val = 0;
422
423         on_each_proc(callback_for_proc, (void *)&cmdp);
424
425         return cmdp.val;
426 }
427
428 u64 get_parameter_energy(enum parameter_energy pe)
429 {
430         u64 val = 0;
431
432         switch (pe) {
433         case PE_TIME_IDLE:
434                 val = cpus_time_get_running_all(&ct_idle);
435                 break;
436         case PE_TIME_SYSTEM:
437                 val = cpus_time_get_running_all(&ed_system.ct);
438                 break;
439         case PE_TIME_APPS:
440                 val = current_parameter_apps(PT_CPU);
441                 break;
442         case PE_READ_SYSTEM:
443                 val = atomic64_read(&ed_system.bytes_read);
444                 break;
445         case PE_WRITE_SYSTEM:
446                 val = atomic64_read(&ed_system.bytes_written);
447                 break;
448         case PE_READ_APPS:
449                 val = current_parameter_apps(PT_READ);
450                 break;
451         case PE_WRITE_APPS:
452                 val = current_parameter_apps(PT_WRITE);
453                 break;
454         default:
455                 break;
456         }
457
458         return val;
459 }
460
461 int do_set_energy(void)
462 {
463         int ret = 0;
464
465         init_data_energy();
466
467         ret = dbi_register_kretprobe(&sys_read_krp);
468         if (ret) {
469                 printk("dbi_register_kretprobe(sys_read) result=%d!\n", ret);
470                 return ret;
471         }
472
473         ret = dbi_register_kretprobe(&sys_write_krp);
474         if (ret != 0) {
475                 printk("dbi_register_kretprobe(sys_write) result=%d!\n", ret);
476                 goto unregister_sys_read;
477         }
478
479         ret = dbi_register_kretprobe(&switch_to_krp);
480         if (ret) {
481                 printk("dbi_register_kretprobe(__switch_to) result=%d!\n", ret);
482                 goto unregister_sys_write;
483         }
484
485         /* TODO: check return value */
486         lcd_set_energy();
487
488         return ret;
489
490 unregister_sys_read:
491         dbi_unregister_kretprobe(&sys_read_krp);
492
493 unregister_sys_write:
494         dbi_unregister_kretprobe(&sys_write_krp);
495
496         return ret;
497 }
498
499 void do_unset_energy(void)
500 {
501         lcd_unset_energy();
502
503         dbi_unregister_kretprobe(&switch_to_krp);
504         dbi_unregister_kretprobe(&sys_write_krp);
505         dbi_unregister_kretprobe(&sys_read_krp);
506
507         uninit_data_energy();
508 }
509
510 static DEFINE_MUTEX(mutex_enable);
511 static int energy_enable = 0;
512
513 int set_energy(void)
514 {
515         int ret = -EINVAL;
516
517         mutex_lock(&mutex_enable);
518         if (energy_enable) {
519                 printk("energy profiling is already run!\n");
520                 goto unlock;
521         }
522
523         ret = do_set_energy();
524         if (ret == 0)
525                 energy_enable = 1;
526
527 unlock:
528         mutex_unlock(&mutex_enable);
529
530         return ret;
531 }
532 EXPORT_SYMBOL_GPL(set_energy);
533
534 int unset_energy(void)
535 {
536         int ret = 0;
537
538         mutex_lock(&mutex_enable);
539         if (energy_enable == 0) {
540                 printk("energy profiling is not running!\n");
541                 ret = -EINVAL;
542                 goto unlock;
543         }
544
545         do_unset_energy();
546
547         energy_enable = 0;
548 unlock:
549         mutex_unlock(&mutex_enable);
550
551         return ret;
552 }
553 EXPORT_SYMBOL_GPL(unset_energy);
554
555 int energy_init(void)
556 {
557         int ret;
558         unsigned long addr;
559
560         addr = swap_ksyms("__switch_to");
561         if (addr == 0) {
562                 printk("Cannot find address for __switch_to function!\n");
563                 return -EINVAL;
564         }
565         switch_to_krp.kp.addr = (kprobe_opcode_t *)addr;
566
567         addr = swap_ksyms("sys_read");
568         if (addr == 0) {
569                 printk("Cannot find address for sys_read function!\n");
570                 return -EINVAL;
571         }
572         sys_read_krp.kp.addr = (kprobe_opcode_t *)addr;
573
574         addr = swap_ksyms("sys_write");
575         if (addr == 0) {
576                 printk("Cannot find address for sys_write function!\n");
577                 return -EINVAL;
578         }
579         sys_write_krp.kp.addr = (kprobe_opcode_t *)addr;
580
581         ret = init_feature();
582         if (ret) {
583                 printk("Cannot init feature\n");
584                 return ret;
585         }
586
587         ret = lcd_init();
588         if (ret) {
589                 printk("Cannot init LCD\n");
590                 uninit_feature();
591         }
592
593         return ret;
594 }
595
596 void energy_uninit(void)
597 {
598         lcd_exit();
599         uninit_feature();
600
601         if (energy_enable)
602                 do_unset_energy();
603 }