[FIX] application wifi consumption estimation
authorVyacheslav Cherkashin <v.cherkashin@samsung.com>
Tue, 29 Dec 2015 07:46:06 +0000 (10:46 +0300)
committerVyacheslav Cherkashin <v.cherkashin@samsung.com>
Tue, 29 Dec 2015 15:48:14 +0000 (18:48 +0300)
 Obtain socket information within wifi send/recv functions
and search for application which has this socket.

Change-Id: I4a96f9bbe50d2800ac9800c77f266bf1f173dbb9
Signed-off-by: Vyacheslav Cherkashin <v.cherkashin@samsung.com>
energy/energy.c
master/Kbuild
master/swap_deps.c [new file with mode: 0644]
master/swap_deps.h [new file with mode: 0644]
master/swap_initializer.c
parser/swap_msg_parser.c
parser/usm_msg.c
parser/usm_msg.h

index 50eba3f..9dd3b89 100644 (file)
 #include <linux/socket.h>
 #include <linux/skbuff.h>
 #include <linux/string.h>
+#include <linux/fdtable.h>
 #include <net/sock.h>
 #include <kprobe/swap_kprobes.h>
 #include <ksyms/ksyms.h>
+#include <master/swap_deps.h>
 #include <us_manager/sspt/sspt_proc.h>
 #include <us_manager/sspt/sspt_feature.h>
 #include <linux/atomic.h>
 
 
 /* ============================================================================
+ * =                              ENERGY_XXX                                  =
+ * ============================================================================
+ */
+struct kern_probe {
+       const char *name;
+       struct kretprobe *rp;
+};
+
+static int energy_xxx_once(struct kern_probe p[], int size)
+{
+       int i;
+       const char *sym;
+
+       for (i = 0; i < size; ++i) {
+               struct kretprobe *rp = p[i].rp;
+
+               sym = p[i].name;
+               rp->kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
+               if (rp->kp.addr == NULL)
+                       goto not_found;
+       }
+
+       return 0;
+
+not_found:
+       printk(KERN_INFO "ERROR: symbol '%s' not found\n", sym);
+       return -ESRCH;
+}
+
+static int energy_xxx_set(struct kern_probe p[], int size, int *flag)
+{
+       int i, ret;
+
+       for (i = 0; i < size; ++i) {
+               ret = swap_register_kretprobe(p[i].rp);
+               if (ret)
+                       goto fail;
+       }
+
+       *flag = 1;
+       return 0;
+
+fail:
+       pr_err("swap_register_kretprobe(%s) ret=%d\n", p[i].name, ret);
+
+       for (--i; i != -1; --i)
+               swap_unregister_kretprobe(p[i].rp);
+
+       return ret;
+}
+
+static void energy_xxx_unset(struct kern_probe p[], int size, int *flag)
+{
+       int i;
+
+       if (*flag == 0)
+               return;
+
+       for (i = size - 1; i != -1; --i)
+               swap_unregister_kretprobe(p[i].rp);
+
+       *flag = 0;
+}
+
+
+
+
+
+/* ============================================================================
  * =                              CPUS_TIME                                   =
  * ============================================================================
  */
@@ -490,29 +561,72 @@ static bool check_wlan0(struct socket *sock)
        return false;
 }
 
-static int entry_handler_wf_sock(struct kretprobe_instance *ri,
-                                struct pt_regs *regs)
+static bool check_socket(struct task_struct *task, struct socket *socket)
+{
+       bool ret = false;
+       unsigned int fd;
+       struct files_struct *files;
+
+       files = swap_get_files_struct(task);
+       if (files == NULL)
+               return false;
+
+       rcu_read_lock();
+       for (fd = 0; fd < files_fdtable(files)->max_fds; ++fd) {
+               if (fcheck_files(files, fd) == socket->file) {
+                       ret = true;
+                       goto unlock;
+               }
+       }
+
+unlock:
+       rcu_read_unlock();
+       swap_put_files_struct(files);
+       return ret;
+}
+
+static struct energy_data *get_energy_data_by_socket(struct task_struct *task,
+                                                    struct socket *socket)
+{
+       struct energy_data *ed;
+
+       ed = get_energy_data(task);
+       if (ed)
+               ed = check_socket(task, socket) ? ed : NULL;
+
+       return ed;
+}
+
+static int wf_sock_eh(struct kretprobe_instance *ri, struct pt_regs *regs)
 {
-       bool *ok = (bool *)ri->data;
        struct socket *socket = (struct socket *)swap_get_karg(regs, 0);
 
-       *ok = check_wlan0(socket);
+       *(struct socket **)ri->data = check_wlan0(socket) ? socket : NULL;
 
        return 0;
 }
 
-static int ret_handler_wf_sock_recv(struct kretprobe_instance *ri,
-                                   struct pt_regs *regs)
+static int wf_sock_aio_eh(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct kiocb *iocb = (struct kiocb *)swap_get_karg(regs, 0);
+       struct socket *socket = iocb->ki_filp->private_data;
+
+       *(struct socket **)ri->data = check_wlan0(socket) ? socket : NULL;
+
+       return 0;
+}
+
+static int wf_sock_recv_rh(struct kretprobe_instance *ri, struct pt_regs *regs)
 {
        int ret = regs_return_value(regs);
 
        if (ret > 0) {
-               bool ok = *(bool *)ri->data;
+               struct socket *socket = *(struct socket **)ri->data;
 
-               if (ok) {
+               if (socket) {
                        struct energy_data *ed;
 
-                       ed = get_energy_data(current);
+                       ed = get_energy_data_by_socket(current, socket);
                        if (ed)
                                atomic64_add(ret, &ed->bytes_recv);
                        atomic64_add(ret, &ed_system.bytes_recv);
@@ -522,18 +636,17 @@ static int ret_handler_wf_sock_recv(struct kretprobe_instance *ri,
        return 0;
 }
 
-static int ret_handler_wf_sock_send(struct kretprobe_instance *ri,
-                                   struct pt_regs *regs)
+static int wf_sock_send_rh(struct kretprobe_instance *ri, struct pt_regs *regs)
 {
        int ret = regs_return_value(regs);
 
        if (ret > 0) {
-               bool ok = *(bool *)ri->data;
+               struct socket *socket = *(struct socket **)ri->data;
 
-               if (ok) {
+               if (socket) {
                        struct energy_data *ed;
 
-                       ed = get_energy_data(current);
+                       ed = get_energy_data_by_socket(current, socket);
                        if (ed)
                                atomic64_add(ret, &ed->bytes_send);
                        atomic64_add(ret, &ed_system.bytes_send);
@@ -544,71 +657,50 @@ static int ret_handler_wf_sock_send(struct kretprobe_instance *ri,
 }
 
 static struct kretprobe sock_recv_krp = {
-       .entry_handler = entry_handler_wf_sock,
-       .handler = ret_handler_wf_sock_recv,
-       .data_size = sizeof(bool)
+       .entry_handler = wf_sock_eh,
+       .handler = wf_sock_recv_rh,
+       .data_size = sizeof(struct socket *)
 };
 
 static struct kretprobe sock_send_krp = {
-       .entry_handler = entry_handler_wf_sock,
-       .handler = ret_handler_wf_sock_send,
-       .data_size = sizeof(bool)
+       .entry_handler = wf_sock_eh,
+       .handler = wf_sock_send_rh,
+       .data_size = sizeof(struct socket *)
 };
 
-static int energy_wifi_once(void)
-{
-       const char *sym;
-
-       sym = "sock_recvmsg";
-       sock_recv_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
-       if (sock_recv_krp.kp.addr == NULL)
-               goto not_found;
-
-       sym = "sock_sendmsg";
-       sock_send_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
-       if (sock_send_krp.kp.addr == NULL)
-               goto  not_found;
-
-       return 0;
-
-not_found:
-       printk(KERN_INFO "ERROR: symbol '%s' not found\n", sym);
-       return -ESRCH;
-}
-
-static int energy_wifi_flag = 0;
-
-static int energy_wifi_set(void)
-{
-       int ret;
+static struct kretprobe sock_aio_read_krp = {
+       .entry_handler = wf_sock_aio_eh,
+       .handler = wf_sock_recv_rh,
+       .data_size = sizeof(struct socket *)
+};
 
-       ret = swap_register_kretprobe(&sock_recv_krp);
-       if (ret) {
-               pr_err("swap_register_kretprobe(sock_recv_krp) ret=%d\n" ,ret);
-               return ret;
-       }
+static struct kretprobe sock_aio_write_krp = {
+       .entry_handler = wf_sock_aio_eh,
+       .handler = wf_sock_send_rh,
+       .data_size = sizeof(struct socket *)
+};
 
-       ret = swap_register_kretprobe(&sock_send_krp);
-       if (ret) {
-               pr_err("swap_register_kretprobe(sock_send_krp) ret=%d\n" ,ret);
-               swap_unregister_kretprobe(&sock_recv_krp);
+static struct kern_probe wifi_probes[] = {
+       {
+               .name = "sock_recvmsg",
+               .rp = &sock_recv_krp,
+       },
+       {
+               .name = "sock_sendmsg",
+               .rp = &sock_send_krp,
+       },
+       {
+               .name = "sock_aio_read",
+               .rp = &sock_aio_read_krp,
+       },
+       {
+               .name = "sock_aio_write",
+               .rp = &sock_aio_write_krp,
        }
+};
 
-       energy_wifi_flag = 1;
-
-       return ret;
-}
-
-static void energy_wifi_unset(void)
-{
-       if (energy_wifi_flag == 0)
-               return;
-
-       swap_unregister_kretprobe(&sock_send_krp);
-       swap_unregister_kretprobe(&sock_recv_krp);
-
-       energy_wifi_flag = 0;
-}
+enum { wifi_probes_cnt = ARRAY_SIZE(wifi_probes) };
+static int wifi_flag = 0;
 
 
 
@@ -959,7 +1051,7 @@ int do_set_energy(void)
        }
 
        energy_bt_set();
-       energy_wifi_set();
+       energy_xxx_set(wifi_probes, wifi_probes_cnt, &wifi_flag);
 
        /* TODO: check return value */
        lcd_set_energy();
@@ -978,7 +1070,7 @@ unregister_sys_write:
 void do_unset_energy(void)
 {
        lcd_unset_energy();
-       energy_wifi_unset();
+       energy_xxx_unset(wifi_probes, wifi_probes_cnt, &wifi_flag);
        energy_bt_unset();
 
        swap_unregister_kretprobe(&switch_to_krp);
@@ -1063,7 +1155,7 @@ int energy_once(void)
                goto not_found;
 
        energy_bt_once();
-       energy_wifi_once();
+       energy_xxx_once(wifi_probes, wifi_probes_cnt);
 
        return 0;
 
index 83733a7..cd1b1c5 100644 (file)
@@ -3,4 +3,5 @@ EXTRA_CFLAGS := $(extra_cflags)
 obj-m := swap_master.o
 swap_master-y := master_module.o \
                  swap_debugfs.o \
-                 swap_initializer.o
+                 swap_initializer.o \
+                 swap_deps.o
diff --git a/master/swap_deps.c b/master/swap_deps.c
new file mode 100644 (file)
index 0000000..0c566c1
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2015
+ *
+ * 2015         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/module.h>
+#include <ksyms/ksyms.h>
+#include "swap_deps.h"
+
+
+static struct files_struct *(*__get_files_struct)(struct task_struct *);
+static void (*__put_files_struct)(struct files_struct *fs);
+
+struct files_struct *swap_get_files_struct(struct task_struct *task)
+{
+       return __get_files_struct(task);
+}
+EXPORT_SYMBOL_GPL(swap_get_files_struct);
+
+void swap_put_files_struct(struct files_struct *fs)
+{
+       __put_files_struct(fs);
+}
+EXPORT_SYMBOL_GPL(swap_put_files_struct);
+
+
+int chef_once(void)
+{
+       const char *sym;
+       static unsigned once_flag = 0;
+
+       if (once_flag)
+               return 0;
+
+       sym = "get_files_struct";
+       __get_files_struct = (void *)swap_ksyms(sym);
+       if (__get_files_struct == NULL)
+               goto not_found;
+
+       sym = "put_files_struct";
+       __put_files_struct = (void *)swap_ksyms(sym);
+       if (__put_files_struct == NULL)
+               goto not_found;
+
+       once_flag = 1;
+       return 0;
+
+not_found:
+       printk("ERROR: symbol '%s' not found\n", sym);
+       return -ESRCH;
+}
+
diff --git a/master/swap_deps.h b/master/swap_deps.h
new file mode 100644 (file)
index 0000000..ca4c978
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2015
+ *
+ * 2015         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#ifndef _SWAP_DEPS_H
+#define _SWAP_DEPS_H
+
+
+struct task_struct;
+struct files_struct;
+
+
+struct files_struct *swap_get_files_struct(struct task_struct *task);
+void swap_put_files_struct(struct files_struct *fs);
+
+
+int chef_once(void);
+
+
+#endif /* _SWAP_DEPS_H */
index 16c39bb..a7ea8c3 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/types.h>
 #include <linux/spinlock.h>
 #include "swap_initializer.h"
+#include "swap_deps.h"
 
 
 enum init_level {
@@ -166,6 +167,10 @@ static int do_once(void)
        int ret;
        struct swap_init_struct *init;
 
+       ret = chef_once();
+       if (ret)
+               return ret;
+
        list_for_each_entry(init, &init_list, list) {
                ret = sis_once(init);
                if (ret)
index e5f929d..0f7e394 100644 (file)
@@ -170,10 +170,6 @@ static int once(void)
                return ret;
 
        ret = init_cpu_deps();
-       if (ret)
-               return ret;
-
-       ret = usm_msg_once();
 
        return ret;
 }
index 3fcd733..6abcaa5 100644 (file)
 #include <linux/dcache.h>
 #include <linux/fdtable.h>
 #include <writer/swap_msg.h>
+#include <master/swap_deps.h>
 #include <us_manager/sspt/sspt.h>      /* ... check_vma() */
 
 
 #define USM_PREFIX      KERN_INFO "[USM] "
 
 
-static struct files_struct *(*swap_get_files_struct)(struct task_struct *);
-static void (*swap_put_files_struct)(struct files_struct *fs);
-
-int usm_msg_once(void)
-{
-       const char *sym;
-
-       sym = "get_files_struct";
-       swap_get_files_struct = (void *)swap_ksyms(sym);
-       if (swap_get_files_struct == NULL)
-               goto not_found;
-
-       sym = "put_files_struct";
-       swap_put_files_struct = (void *)swap_ksyms(sym);
-       if (swap_put_files_struct == NULL)
-               goto not_found;
-
-       return 0;
-
-not_found:
-       printk("ERROR: symbol '%s' not found\n", sym);
-       return -ESRCH;
-}
-
-
-
-
-
 struct kmem_info {
        const char *name;
        unsigned long start;
index b151be5..6c9345d 100644 (file)
@@ -28,7 +28,6 @@ struct dentry;
 struct task_struct;
 struct vm_area_struct;
 
-int usm_msg_once(void);
 
 void usm_msg_info(struct task_struct *task, struct dentry *dentry);
 void usm_msg_term(struct task_struct *task);