2 * Dynamic Binary Instrumentation Module based on KProbes
3 * modules/energy/swap_energy.c
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.
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.
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.
19 * Copyright (C) Samsung Electronics, 2013
21 * 2013 Vasiliy Ulyanov <v.ulyanov@samsung.com>
22 * Vyacheslav Cherkashin <v.cherkashin@samsung.com>
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>
38 #include "lcd/lcd_base.h"
42 /* ============================================================================
44 * ============================================================================
47 struct tm_stat tm[NR_CPUS];
50 static void cpus_time_init(struct cpus_time *ct, u64 time)
54 for (cpu = 0; cpu < NR_CPUS; ++cpu) {
55 tm_stat_init(&ct->tm[cpu]);
56 tm_stat_set_timestamp(&ct->tm[cpu], time);
60 static u64 cpus_time_get_running_all(struct cpus_time *ct)
65 for (cpu = 0; cpu < NR_CPUS; ++cpu)
66 time += tm_stat_running(&ct->tm[cpu]);
71 static void cpus_time_save_entry(struct cpus_time *ct, int cpu, u64 time)
73 tm_stat_set_timestamp(&ct->tm[cpu], time);
76 static void cpus_time_update_running(struct cpus_time *ct, int cpu, u64 time)
78 tm_stat_update(&ct->tm[cpu], time);
90 atomic64_t bytes_read;
93 atomic64_t bytes_written;
97 static sspt_feature_id_t feature_id = SSPT_FEATURE_ID_BAD;
99 static void init_ed(struct energy_data *ed)
101 cpus_time_init(&ed->ct, get_ntime());
102 atomic64_set(&ed->bytes_read, 0);
103 atomic64_set(&ed->bytes_written, 0);
106 static void uninit_ed(struct energy_data *ed)
108 cpus_time_init(&ed->ct, 0);
109 atomic64_set(&ed->bytes_read, 0);
110 atomic64_set(&ed->bytes_written, 0);
113 static void *create_ed(void)
115 struct energy_data *ed;
117 ed = kmalloc(sizeof(*ed), GFP_ATOMIC);
124 static void destroy_ed(void *data)
126 struct energy_data *ed = (struct energy_data *)data;
131 static int init_feature(void)
133 feature_id = sspt_register_feature(create_ed, destroy_ed);
135 if (feature_id == SSPT_FEATURE_ID_BAD)
141 static void uninit_feature(void)
143 sspt_unregister_feature(feature_id);
144 feature_id = SSPT_FEATURE_ID_BAD;
147 static struct energy_data *get_energy_data(struct task_struct *task)
150 struct sspt_proc *proc;
152 proc = sspt_proc_get_by_task(task);
154 data = sspt_get_feature_data(proc->feature, feature_id);
156 return (struct energy_data *)data;
159 static int check_fs(unsigned long magic)
162 case EXT2_SUPER_MAGIC: /* == EXT3_SUPER_MAGIC == EXT4_SUPER_MAGIC */
163 case MSDOS_SUPER_MAGIC:
170 static int check_ftype(int fd)
175 err = vfs_fstat(fd, &kstat);
176 if (err == 0 && S_ISREG(kstat.mode))
182 static int check_file(int fd)
189 if (file->f_dentry && file->f_dentry->d_sb)
190 magic = file->f_dentry->d_sb->s_magic;
194 if (check_fs(magic) && check_ftype(fd))
201 static unsigned long get_arg0(struct pt_regs *regs)
203 #if defined(CONFIG_ARM)
205 #elif defined(CONFIG_X86_32)
208 #error "this architecture is not supported"
209 #endif /* CONFIG_arch */
216 static struct cpus_time ct_idle;
217 static struct energy_data ed_system;
219 static void init_data_energy(void)
222 cpus_time_init(&ct_idle, get_ntime());
225 static void uninit_data_energy(void)
227 uninit_ed(&ed_system);
228 cpus_time_init(&ct_idle, 0);
235 /* ============================================================================
237 * ============================================================================
239 static int entry_handler_switch(struct kretprobe_instance *ri, struct pt_regs *regs)
243 struct cpus_time* ct;
244 struct energy_data *ed;
246 cpu = smp_processor_id();
248 ct = current->tgid ? &ed_system.ct : &ct_idle;
249 cpus_time_update_running(ct, cpu, time);
251 ed = get_energy_data(current);
253 cpus_time_update_running(&ed->ct, cpu, time);
258 static int ret_handler_switch(struct kretprobe_instance *ri, struct pt_regs *regs)
262 struct cpus_time* ct;
263 struct energy_data *ed;
265 cpu = smp_processor_id();
267 ct = current->tgid ? &ed_system.ct : &ct_idle;
268 cpus_time_save_entry(ct, cpu, time);
270 ed = get_energy_data(current);
272 cpus_time_save_entry(&ed->ct, cpu, time);
277 static struct kretprobe switch_to_krp = {
278 .entry_handler = entry_handler_switch,
279 .handler = ret_handler_switch,
286 /* ============================================================================
288 * ============================================================================
290 struct sys_read_data {
294 static int entry_handler_sys_read(struct kretprobe_instance *ri, struct pt_regs *regs)
296 struct sys_read_data *srd = (struct sys_read_data *)ri->data;
298 srd->fd = (int)get_arg0(regs);
303 static int ret_handler_sys_read(struct kretprobe_instance *ri,
304 struct pt_regs *regs)
306 int ret = regs_return_value(regs);
309 struct sys_read_data *srd;
311 srd = (struct sys_read_data *)ri->data;
312 if (check_file(srd->fd)) {
313 struct energy_data *ed;
315 ed = get_energy_data(current);
317 atomic64_add(ret, &ed->bytes_read);
319 atomic64_add(ret, &ed_system.bytes_read);
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)
336 /* ============================================================================
338 * ============================================================================
340 static int entry_handler_sys_write(struct kretprobe_instance *ri, struct pt_regs *regs)
342 struct sys_read_data *srd = (struct sys_read_data *)ri->data;
344 srd->fd = (int)get_arg0(regs);
349 static int ret_handler_sys_write(struct kretprobe_instance *ri, struct pt_regs *regs)
351 int ret = regs_return_value(regs);
354 struct sys_read_data *srd;
356 srd = (struct sys_read_data *)ri->data;
357 if (check_file(srd->fd)) {
358 struct energy_data *ed;
360 ed = get_energy_data(current);
362 atomic64_add(ret, &ed->bytes_written);
364 atomic64_add(ret, &ed_system.bytes_written);
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)
381 enum parameter_type {
388 enum parameter_type pt;
392 static void callback_for_proc(struct sspt_proc *proc, void *data)
394 void *f_data = sspt_get_feature_data(proc->feature, feature_id);
395 struct energy_data *ed = (struct energy_data *)f_data;
398 struct cmd_pt *cmdp = (struct cmd_pt *)data;
402 cmdp->val += cpus_time_get_running_all(&ed->ct);
405 cmdp->val += atomic64_read(&ed->bytes_read);
408 cmdp->val += atomic64_read(&ed->bytes_written);
416 static u64 current_parameter_apps(enum parameter_type pt)
423 on_each_proc(callback_for_proc, (void *)&cmdp);
428 u64 get_parameter_energy(enum parameter_energy pe)
434 val = cpus_time_get_running_all(&ct_idle);
437 val = cpus_time_get_running_all(&ed_system.ct);
440 val = current_parameter_apps(PT_CPU);
443 val = atomic64_read(&ed_system.bytes_read);
445 case PE_WRITE_SYSTEM:
446 val = atomic64_read(&ed_system.bytes_written);
449 val = current_parameter_apps(PT_READ);
452 val = current_parameter_apps(PT_WRITE);
461 int do_set_energy(void)
467 ret = dbi_register_kretprobe(&sys_read_krp);
469 printk("dbi_register_kretprobe(sys_read) result=%d!\n", ret);
473 ret = dbi_register_kretprobe(&sys_write_krp);
475 printk("dbi_register_kretprobe(sys_write) result=%d!\n", ret);
476 goto unregister_sys_read;
479 ret = dbi_register_kretprobe(&switch_to_krp);
481 printk("dbi_register_kretprobe(__switch_to) result=%d!\n", ret);
482 goto unregister_sys_write;
485 /* TODO: check return value */
491 dbi_unregister_kretprobe(&sys_read_krp);
493 unregister_sys_write:
494 dbi_unregister_kretprobe(&sys_write_krp);
499 void do_unset_energy(void)
503 dbi_unregister_kretprobe(&switch_to_krp);
504 dbi_unregister_kretprobe(&sys_write_krp);
505 dbi_unregister_kretprobe(&sys_read_krp);
507 uninit_data_energy();
510 static DEFINE_MUTEX(mutex_enable);
511 static int energy_enable = 0;
517 mutex_lock(&mutex_enable);
519 printk("energy profiling is already run!\n");
523 ret = do_set_energy();
528 mutex_unlock(&mutex_enable);
532 EXPORT_SYMBOL_GPL(set_energy);
534 int unset_energy(void)
538 mutex_lock(&mutex_enable);
539 if (energy_enable == 0) {
540 printk("energy profiling is not running!\n");
549 mutex_unlock(&mutex_enable);
553 EXPORT_SYMBOL_GPL(unset_energy);
555 int energy_init(void)
560 addr = swap_ksyms("__switch_to");
562 printk("Cannot find address for __switch_to function!\n");
565 switch_to_krp.kp.addr = (kprobe_opcode_t *)addr;
567 addr = swap_ksyms("sys_read");
569 printk("Cannot find address for sys_read function!\n");
572 sys_read_krp.kp.addr = (kprobe_opcode_t *)addr;
574 addr = swap_ksyms("sys_write");
576 printk("Cannot find address for sys_write function!\n");
579 sys_write_krp.kp.addr = (kprobe_opcode_t *)addr;
581 ret = init_feature();
583 printk("Cannot init feature\n");
589 printk("Cannot init LCD\n");
596 void energy_uninit(void)