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 <linux/spinlock.h>
33 #include <linux/net.h>
34 #include <linux/socket.h>
35 #include <linux/skbuff.h>
36 #include <linux/string.h>
38 #include <kprobe/swap_kprobes.h>
39 #include <ksyms/ksyms.h>
40 #include <us_manager/sspt/sspt_proc.h>
41 #include <us_manager/sspt/sspt_feature.h>
42 #include <linux/atomic.h>
44 #include "lcd/lcd_base.h"
48 /* ============================================================================
50 * ============================================================================
53 spinlock_t lock; /* for concurrent access */
54 struct tm_stat tm[NR_CPUS];
57 #define cpus_time_lock(ct, flags) spin_lock_irqsave(&(ct)->lock, flags)
58 #define cpus_time_unlock(ct, flags) spin_unlock_irqrestore(&(ct)->lock, flags)
60 static void cpus_time_init(struct cpus_time *ct, u64 time)
64 spin_lock_init(&ct->lock);
66 for (cpu = 0; cpu < NR_CPUS; ++cpu) {
67 tm_stat_init(&ct->tm[cpu]);
68 tm_stat_set_timestamp(&ct->tm[cpu], time);
72 static inline u64 cpu_time_get_running(struct cpus_time *ct, int cpu, u64 now)
74 return tm_stat_current_running(&ct->tm[cpu], now);
77 static void *cpus_time_get_running_all(struct cpus_time *ct, u64 *buf, u64 now)
81 for (cpu = 0; cpu < NR_CPUS; ++cpu)
82 buf[cpu] = tm_stat_current_running(&ct->tm[cpu], now);
87 static void *cpus_time_sum_running_all(struct cpus_time *ct, u64 *buf, u64 now)
91 for (cpu = 0; cpu < NR_CPUS; ++cpu)
92 buf[cpu] += tm_stat_current_running(&ct->tm[cpu], now);
97 static void cpus_time_save_entry(struct cpus_time *ct, int cpu, u64 time)
99 struct tm_stat *tm = &ct->tm[cpu];
101 if (unlikely(tm_stat_timestamp(tm))) /* should never happen */
102 printk(KERN_INFO "XXX %s[%d/%d]: WARNING tmstamp(%p) set on cpu(%d)\n",
103 current->comm, current->tgid, current->pid, tm, cpu);
104 tm_stat_set_timestamp(&ct->tm[cpu], time);
107 static void cpus_time_update_running(struct cpus_time *ct, int cpu, u64 now,
110 struct tm_stat *tm = &ct->tm[cpu];
112 if (unlikely(tm_stat_timestamp(tm) == 0)) {
113 /* not initialized. should happen only once per cpu/task */
114 printk(KERN_INFO "XXX %s[%d/%d]: nnitializing tmstamp(%p) "
116 current->comm, current->tgid, current->pid, tm, cpu);
117 tm_stat_set_timestamp(tm, start_time);
120 tm_stat_update(tm, now);
121 tm_stat_set_timestamp(tm, 0); /* set timestamp to 0 */
129 /* for __switch_to */
133 atomic64_t bytes_read;
136 atomic64_t bytes_written;
139 atomic64_t bytes_recv;
142 atomic64_t bytes_send;
145 static sspt_feature_id_t feature_id = SSPT_FEATURE_ID_BAD;
147 static void init_ed(struct energy_data *ed)
149 /* instead of get_ntime(), CPU time is initialized to 0 here. Timestamp
150 * value will be properly set when the corresponding __switch_to event
152 cpus_time_init(&ed->ct, 0);
153 atomic64_set(&ed->bytes_read, 0);
154 atomic64_set(&ed->bytes_written, 0);
155 atomic64_set(&ed->bytes_recv, 0);
156 atomic64_set(&ed->bytes_send, 0);
159 static void uninit_ed(struct energy_data *ed)
161 cpus_time_init(&ed->ct, 0);
162 atomic64_set(&ed->bytes_read, 0);
163 atomic64_set(&ed->bytes_written, 0);
164 atomic64_set(&ed->bytes_recv, 0);
165 atomic64_set(&ed->bytes_send, 0);
168 static void *create_ed(void)
170 struct energy_data *ed;
172 ed = kmalloc(sizeof(*ed), GFP_ATOMIC);
179 static void destroy_ed(void *data)
181 struct energy_data *ed = (struct energy_data *)data;
186 static int init_feature(void)
188 feature_id = sspt_register_feature(create_ed, destroy_ed);
190 if (feature_id == SSPT_FEATURE_ID_BAD)
196 static void uninit_feature(void)
198 sspt_unregister_feature(feature_id);
199 feature_id = SSPT_FEATURE_ID_BAD;
202 static struct energy_data *get_energy_data(struct task_struct *task)
205 struct sspt_proc *proc;
207 proc = sspt_proc_get_by_task(task);
209 data = sspt_get_feature_data(proc->feature, feature_id);
211 return (struct energy_data *)data;
214 static int check_fs(unsigned long magic)
217 case EXT2_SUPER_MAGIC: /* == EXT3_SUPER_MAGIC == EXT4_SUPER_MAGIC */
218 case MSDOS_SUPER_MAGIC:
225 static int check_ftype(int fd)
230 err = vfs_fstat(fd, &kstat);
231 if (err == 0 && S_ISREG(kstat.mode))
237 static int check_file(int fd)
244 if (file->f_dentry && file->f_dentry->d_sb)
245 magic = file->f_dentry->d_sb->s_magic;
249 if (check_fs(magic) && check_ftype(fd))
256 static unsigned long get_arg0(struct pt_regs *regs)
258 #if defined(CONFIG_ARM)
260 #elif defined(CONFIG_X86_32)
263 #error "this architecture is not supported"
264 #endif /* CONFIG_arch */
271 static struct cpus_time ct_idle;
272 static struct energy_data ed_system;
273 static u64 start_time;
275 static void init_data_energy(void)
277 start_time = get_ntime();
279 cpus_time_init(&ct_idle, 0);
282 static void uninit_data_energy(void)
285 uninit_ed(&ed_system);
286 cpus_time_init(&ct_idle, 0);
293 /* ============================================================================
295 * ============================================================================
297 static int entry_handler_switch(struct kretprobe_instance *ri,
298 struct pt_regs *regs)
301 struct cpus_time *ct;
302 struct energy_data *ed;
305 cpu = smp_processor_id();
307 ct = current->tgid ? &ed_system.ct : &ct_idle;
308 cpus_time_lock(ct, flags);
309 cpus_time_update_running(ct, cpu, get_ntime(), start_time);
310 cpus_time_unlock(ct, flags);
312 ed = get_energy_data(current);
315 cpus_time_lock(ct, flags);
316 cpus_time_update_running(ct, cpu, get_ntime(), start_time);
317 cpus_time_unlock(ct, flags);
323 static int ret_handler_switch(struct kretprobe_instance *ri,
324 struct pt_regs *regs)
327 struct cpus_time *ct;
328 struct energy_data *ed;
331 cpu = smp_processor_id();
333 ct = current->tgid ? &ed_system.ct : &ct_idle;
334 cpus_time_lock(ct, flags);
335 cpus_time_save_entry(ct, cpu, get_ntime());
336 cpus_time_unlock(ct, flags);
338 ed = get_energy_data(current);
341 cpus_time_lock(ct, flags);
342 cpus_time_save_entry(ct, cpu, get_ntime());
343 cpus_time_unlock(ct, flags);
349 static struct kretprobe switch_to_krp = {
350 .entry_handler = entry_handler_switch,
351 .handler = ret_handler_switch,
358 /* ============================================================================
360 * ============================================================================
362 struct sys_read_data {
366 static int entry_handler_sys_read(struct kretprobe_instance *ri,
367 struct pt_regs *regs)
369 struct sys_read_data *srd = (struct sys_read_data *)ri->data;
371 srd->fd = (int)get_arg0(regs);
376 static int ret_handler_sys_read(struct kretprobe_instance *ri,
377 struct pt_regs *regs)
379 int ret = regs_return_value(regs);
382 struct sys_read_data *srd;
384 srd = (struct sys_read_data *)ri->data;
385 if (check_file(srd->fd)) {
386 struct energy_data *ed;
388 ed = get_energy_data(current);
390 atomic64_add(ret, &ed->bytes_read);
392 atomic64_add(ret, &ed_system.bytes_read);
399 static struct kretprobe sys_read_krp = {
400 .entry_handler = entry_handler_sys_read,
401 .handler = ret_handler_sys_read,
402 .data_size = sizeof(struct sys_read_data)
409 /* ============================================================================
411 * ============================================================================
413 static int entry_handler_sys_write(struct kretprobe_instance *ri,
414 struct pt_regs *regs)
416 struct sys_read_data *srd = (struct sys_read_data *)ri->data;
418 srd->fd = (int)get_arg0(regs);
423 static int ret_handler_sys_write(struct kretprobe_instance *ri,
424 struct pt_regs *regs)
426 int ret = regs_return_value(regs);
429 struct sys_read_data *srd;
431 srd = (struct sys_read_data *)ri->data;
432 if (check_file(srd->fd)) {
433 struct energy_data *ed;
435 ed = get_energy_data(current);
437 atomic64_add(ret, &ed->bytes_written);
439 atomic64_add(ret, &ed_system.bytes_written);
446 static struct kretprobe sys_write_krp = {
447 .entry_handler = entry_handler_sys_write,
448 .handler = ret_handler_sys_write,
449 .data_size = sizeof(struct sys_read_data)
456 /* ============================================================================
458 * ============================================================================
460 static bool check_wlan0(struct socket *sock)
462 /* FIXME: hardcode interface */
463 const char *name_intrf = "wlan0";
465 if (sock->sk->sk_dst_cache &&
466 sock->sk->sk_dst_cache->dev &&
467 !strcmp(sock->sk->sk_dst_cache->dev->name, name_intrf))
473 static int entry_handler_wf_sock(struct kretprobe_instance *ri,
474 struct pt_regs *regs)
476 bool *ok = (bool *)ri->data;
477 struct socket *socket = (struct socket *)swap_get_karg(regs, 0);
479 *ok = check_wlan0(socket);
484 static int ret_handler_wf_sock_recv(struct kretprobe_instance *ri,
485 struct pt_regs *regs)
487 int ret = regs_return_value(regs);
490 bool ok = *(bool *)ri->data;
493 struct energy_data *ed;
495 ed = get_energy_data(current);
497 atomic64_add(ret, &ed->bytes_recv);
498 atomic64_add(ret, &ed_system.bytes_recv);
505 static int ret_handler_wf_sock_send(struct kretprobe_instance *ri,
506 struct pt_regs *regs)
508 int ret = regs_return_value(regs);
511 bool ok = *(bool *)ri->data;
514 struct energy_data *ed;
516 ed = get_energy_data(current);
518 atomic64_add(ret, &ed->bytes_send);
519 atomic64_add(ret, &ed_system.bytes_send);
526 static struct kretprobe sock_recv_krp = {
527 .entry_handler = entry_handler_wf_sock,
528 .handler = ret_handler_wf_sock_recv,
529 .data_size = sizeof(bool)
532 static struct kretprobe sock_send_krp = {
533 .entry_handler = entry_handler_wf_sock,
534 .handler = ret_handler_wf_sock_send,
535 .data_size = sizeof(bool)
538 static int energy_wifi_once(void)
542 sym = "sock_recvmsg";
543 sock_recv_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
544 if (sock_recv_krp.kp.addr == NULL)
547 sym = "sock_sendmsg";
548 sock_send_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
549 if (sock_send_krp.kp.addr == NULL)
555 printk(KERN_INFO "ERROR: symbol '%s' not found\n", sym);
559 static int energy_wifi_flag = 0;
561 static int energy_wifi_set(void)
565 ret = swap_register_kretprobe(&sock_recv_krp);
567 pr_err("swap_register_kretprobe(sock_recv_krp) ret=%d\n" ,ret);
571 ret = swap_register_kretprobe(&sock_send_krp);
573 pr_err("swap_register_kretprobe(sock_send_krp) ret=%d\n" ,ret);
574 swap_unregister_kretprobe(&sock_recv_krp);
577 energy_wifi_flag = 1;
582 static void energy_wifi_unset(void)
584 if (energy_wifi_flag == 0)
587 swap_unregister_kretprobe(&sock_send_krp);
588 swap_unregister_kretprobe(&sock_recv_krp);
590 energy_wifi_flag = 0;
597 enum parameter_type {
606 enum parameter_type pt;
611 static void callback_for_proc(struct sspt_proc *proc, void *data)
613 void *f_data = sspt_get_feature_data(proc->feature, feature_id);
614 struct energy_data *ed = (struct energy_data *)f_data;
618 struct cmd_pt *cmdp = (struct cmd_pt *)data;
619 u64 *val = cmdp->buf;
623 cpus_time_lock(&ed->ct, flags);
624 cpus_time_sum_running_all(&ed->ct, val, get_ntime());
625 cpus_time_unlock(&ed->ct, flags);
628 *val += atomic64_read(&ed->bytes_read);
631 *val += atomic64_read(&ed->bytes_written);
634 *val += atomic64_read(&ed->bytes_recv);
637 *val += atomic64_read(&ed->bytes_send);
645 static int current_parameter_apps(enum parameter_type pt, void *buf, int sz)
653 on_each_proc(callback_for_proc, (void *)&cmdp);
659 * @brief Get energy parameter
661 * @param pe Type of energy parameter
663 * @param sz Buffer size
666 int get_parameter_energy(enum parameter_energy pe, void *buf, size_t sz)
669 u64 *val = buf; /* currently all parameters are u64 vals */
674 cpus_time_lock(&ct_idle, flags);
675 /* for the moment we consider only CPU[0] idle time */
676 *val = cpu_time_get_running(&ct_idle, 0, get_ntime());
677 cpus_time_unlock(&ct_idle, flags);
680 cpus_time_lock(&ed_system.ct, flags);
681 cpus_time_get_running_all(&ed_system.ct, val, get_ntime());
682 cpus_time_unlock(&ed_system.ct, flags);
685 current_parameter_apps(PT_CPU, buf, sz);
688 *val = atomic64_read(&ed_system.bytes_read);
690 case PE_WRITE_SYSTEM:
691 *val = atomic64_read(&ed_system.bytes_written);
693 case PE_WF_RECV_SYSTEM:
694 *val = atomic64_read(&ed_system.bytes_recv);
696 case PE_WF_SEND_SYSTEM:
697 *val = atomic64_read(&ed_system.bytes_send);
700 current_parameter_apps(PT_READ, buf, sz);
703 current_parameter_apps(PT_WRITE, buf, sz);
705 case PE_WF_RECV_APPS:
706 current_parameter_apps(PT_WF_RECV, buf, sz);
708 case PE_WF_SEND_APPS:
709 current_parameter_apps(PT_WF_SEND, buf, sz);
719 int do_set_energy(void)
725 ret = swap_register_kretprobe(&sys_read_krp);
727 printk(KERN_INFO "swap_register_kretprobe(sys_read) "
728 "result=%d!\n", ret);
732 ret = swap_register_kretprobe(&sys_write_krp);
734 printk(KERN_INFO "swap_register_kretprobe(sys_write) "
735 "result=%d!\n", ret);
736 goto unregister_sys_read;
739 ret = swap_register_kretprobe(&switch_to_krp);
741 printk(KERN_INFO "swap_register_kretprobe(__switch_to) "
744 goto unregister_sys_write;
749 /* TODO: check return value */
755 swap_unregister_kretprobe(&sys_read_krp);
757 unregister_sys_write:
758 swap_unregister_kretprobe(&sys_write_krp);
763 void do_unset_energy(void)
768 swap_unregister_kretprobe(&switch_to_krp);
769 swap_unregister_kretprobe(&sys_write_krp);
770 swap_unregister_kretprobe(&sys_read_krp);
772 uninit_data_energy();
775 static DEFINE_MUTEX(mutex_enable);
776 static int energy_enable;
779 * @brief Start measuring the energy consumption
787 mutex_lock(&mutex_enable);
789 printk(KERN_INFO "energy profiling is already run!\n");
793 ret = do_set_energy();
798 mutex_unlock(&mutex_enable);
802 EXPORT_SYMBOL_GPL(set_energy);
805 * @brief Stop measuring the energy consumption
809 int unset_energy(void)
813 mutex_lock(&mutex_enable);
814 if (energy_enable == 0) {
815 printk(KERN_INFO "energy profiling is not running!\n");
824 mutex_unlock(&mutex_enable);
828 EXPORT_SYMBOL_GPL(unset_energy);
830 int energy_once(void)
835 switch_to_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
836 if (switch_to_krp.kp.addr == NULL)
840 sys_read_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
841 if (sys_read_krp.kp.addr == NULL)
845 sys_write_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
846 if (sys_write_krp.kp.addr == NULL)
854 printk(KERN_INFO "ERROR: symbol '%s' not found\n", sym);
859 * @brief Initialization energy
863 int energy_init(void)
867 ret = init_feature();
869 printk(KERN_INFO "Cannot init feature\n");
875 * @brief Deinitialization energy
879 void energy_uninit(void)