From: Ruslan Soloviev Date: Thu, 27 Nov 2014 07:12:42 +0000 (+0300) Subject: [FEATURE] Add web profiling X-Git-Tag: submit/tizen/20151123.110932~113 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4f2786f1a867477f9083641e96c379514846bd3c;p=kernel%2Fswap-modules.git [FEATURE] Add web profiling Setup probes (probe type 3): ewk_context_inspector_server_start JSC::ProfileGenerator::willExecute JSC::ProfileGenerator::didExecute Change-Id: I65534ea544685b55d805df910d85b6a31eae2a93 Signed-off-by: Ruslan Soloviev --- diff --git a/Kbuild b/Kbuild index 40b8f27..54f3c3e 100644 --- a/Kbuild +++ b/Kbuild @@ -12,4 +12,5 @@ obj-m := buffer/ \ sampler/ \ energy/ \ parser/ \ - retprobe/ + retprobe/ \ + webprobe/ diff --git a/build.sh b/build.sh index e824400..3d21d97 100755 --- a/build.sh +++ b/build.sh @@ -35,6 +35,7 @@ sampler_dir=${modules_dir}/sampler energy_dir=${modules_dir}/energy parser_dir=${modules_dir}/parser retprobe_dir=${modules_dir}/retprobe +webprobe_dir=${modules_dir}/webprobe buffer_module_name=swap_buffer.ko driver_module_name=swap_driver.ko @@ -49,6 +50,7 @@ energy_module_name=swap_energy.ko parser_module_name=swap_message_parser.ko ksyms_module_name=swap_ksyms.ko retprobe_module_name=swap_retprobe.ko +webprobe_module_name=swap_webprobe.ko install_dir="/opt/swap/sdk" @@ -72,7 +74,8 @@ ${sampler_dir}/${sampler_module_name} \ ${energy_dir}/${energy_module_name} \ ${parser_dir}/${parser_module_name} \ ${ksyms_dir}/${ksyms_module_name} \ -${retprobe_dir}/${retprobe_module_name}" +${retprobe_dir}/${retprobe_module_name} \ +${webprobe_dir}/${webprobe_module_name}" for m in ${modules} ; do ${cross_compile}strip -x -g $m diff --git a/packaging/swap-modules.spec b/packaging/swap-modules.spec index 7d2ad40..9a2c030 100755 --- a/packaging/swap-modules.spec +++ b/packaging/swap-modules.spec @@ -53,6 +53,7 @@ install -m 666 sampler/swap_sampler.ko -t %{buildroot}/opt/swap/sdk install -m 666 energy/swap_energy.ko -t %{buildroot}/opt/swap/sdk install -m 666 parser/swap_message_parser.ko -t %{buildroot}/opt/swap/sdk install -m 666 retprobe/swap_retprobe.ko -t %{buildroot}/opt/swap/sdk +install -m 666 webprobe/swap_webprobe.ko -t %{buildroot}/opt/swap/sdk %files %defattr(-,root,root) @@ -69,3 +70,4 @@ install -m 666 retprobe/swap_retprobe.ko -t %{buildroot}/opt/swap/sdk /opt/swap/sdk/swap_energy.ko /opt/swap/sdk/swap_message_parser.ko /opt/swap/sdk/swap_retprobe.ko +/opt/swap/sdk/swap_webprobe.ko diff --git a/parser/msg_cmd.c b/parser/msg_cmd.c index b516a21..fa890f9 100644 --- a/parser/msg_cmd.c +++ b/parser/msg_cmd.c @@ -29,6 +29,7 @@ #include +#include #include #include "msg_parser.h" #include "msg_buf.h" @@ -37,6 +38,8 @@ #include "us_inst.h" #include +static int wrt_launcher_port = 0; + static int set_config(struct conf_data *conf) { int ret; @@ -237,6 +240,31 @@ free_us_inst: return ret; } +void set_wrt_launcher_port(int port) +{ + wrt_launcher_port = port; +} +EXPORT_SYMBOL_GPL(set_wrt_launcher_port); + +#define GET_PORT_DELAY 100 /* msec */ +#define GET_PORT_TIMEOUT 10000 /* msec */ + +int get_wrt_launcher_port(void) +{ + int port; + int timeout = GET_PORT_TIMEOUT; + + do { + port = wrt_launcher_port; + timeout -= GET_PORT_DELAY; + mdelay(GET_PORT_DELAY); + } while (!port && timeout > 0); + + set_wrt_launcher_port(0); + + return port; +} + /** * @brief Initializes commands handling. * diff --git a/parser/msg_cmd.h b/parser/msg_cmd.h index 16132ca..e444997 100644 --- a/parser/msg_cmd.h +++ b/parser/msg_cmd.h @@ -41,5 +41,7 @@ int msg_stop(struct msg_buf *mb); int msg_config(struct msg_buf *mb); int msg_swap_inst_add(struct msg_buf *mb); int msg_swap_inst_remove(struct msg_buf *mb); +int get_wrt_launcher_port(void); +void set_wrt_launcher_port(int port); #endif /* _MSG_CMD_H */ diff --git a/parser/msg_parser.c b/parser/msg_parser.c index 63315a6..6e12886 100644 --- a/parser/msg_parser.c +++ b/parser/msg_parser.c @@ -304,6 +304,21 @@ free_args: } /** + * @brief Gets webprobe data and puts it to the probe_info struct. + * + * @param mb Pointer to the message buffer. + * @param pi Pointer to the probe_info struct. + * @return 0 on success, error code on error. + */ +int get_webprobe(struct msg_buf *mb, struct probe_info *pi) +{ + pi->probe_type = SWAP_WEBPROBE; + pi->size = 0; + + return 0; +} + +/** * @brief Retprobe data cleanup. * * @param pi Pointer to the probe_info comprising retprobe. @@ -361,6 +376,10 @@ struct func_inst_data *create_func_inst_data(struct msg_buf *mb) if (get_retprobe(mb, &(fi->probe_i)) != 0) goto free_func_inst; break; + case SWAP_WEBPROBE: + if (get_webprobe(mb, &(fi->probe_i)) != 0) + goto free_func_inst; + break; default: printk(KERN_WARNING "SWAP PARSER: Wrong probe type %d!\n", type); goto free_func_inst; @@ -386,6 +405,8 @@ void destroy_func_inst_data(struct func_inst_data *fi) case SWAP_RETPROBE: put_retprobe(&(fi->probe_i)); break; + case SWAP_WEBPROBE: + break; default: printk(KERN_WARNING "SWAP PARSER: Wrong probe type %d!\n", fi->probe_i.probe_type); diff --git a/parser/swap_msg_parser.c b/parser/swap_msg_parser.c index f1071e2..dca2999 100644 --- a/parser/swap_msg_parser.c +++ b/parser/swap_msg_parser.c @@ -47,12 +47,13 @@ * @brief Message IDs. */ enum MSG_ID { - MSG_KEEP_ALIVE = 0x0001, /**< Keep alive message. */ - MSG_START = 0x0002, /**< Start message. */ - MSG_STOP = 0x0003, /**< Stop message. */ - MSG_CONFIG = 0x0004, /**< Config message. */ - MSG_SWAP_INST_ADD = 0x0008, /**< Swap inst add message. */ - MSG_SWAP_INST_REMOVE = 0x0009 /**< Swap inst remove message. */ + MSG_KEEP_ALIVE = 0x0001, /**< Keep alive message. */ + MSG_START = 0x0002, /**< Start message. */ + MSG_STOP = 0x0003, /**< Stop message. */ + MSG_CONFIG = 0x0004, /**< Config message. */ + MSG_SWAP_INST_ADD = 0x0008, /**< Swap inst add message. */ + MSG_SWAP_INST_REMOVE = 0x0009, /**< Swap inst remove message. */ + MSG_WRT_LAUNCHER_PORT = 0x8001 /**< WRT launcher port. */ }; /** @@ -128,6 +129,18 @@ static int msg_handler(void __user *msg) print_parse_debug("MSG_SWAP_INST_REMOVE. size=%d\n", size); ret = msg_swap_inst_remove(&mb); break; + case MSG_WRT_LAUNCHER_PORT: { + /* TODO: discuss wrt-launcher port transfer */ + int port; + print_parse_debug("MSG_WRT_LAUNCHER_PORT. size=%d\n", size); + port = get_wrt_launcher_port(); + if (copy_to_user(payload, &port, sizeof(port))) { + ret = -EIO; + break; + } + ret = port ? 0 : -EINVAL; + break; + } default: print_err("incorrect message ID [%u]. size=%d\n", msg_id, size); ret = -EINVAL; diff --git a/us_manager/probes/probes.h b/us_manager/probes/probes.h index 4ba8111..d83f1cb 100644 --- a/us_manager/probes/probes.h +++ b/us_manager/probes/probes.h @@ -37,6 +37,7 @@ */ enum probe_t { SWAP_RETPROBE = 0, /* Retprobe */ + SWAP_WEBPROBE = 3, /* Webprobe */ SWAP_PROBE_MAX_VAL /* Probes max value. */ }; diff --git a/webprobe/Kbuild b/webprobe/Kbuild new file mode 100644 index 0000000..c79cb10 --- /dev/null +++ b/webprobe/Kbuild @@ -0,0 +1,4 @@ +EXTRA_CFLAGS := $(extra_cflags) + +obj-m := swap_webprobe.o +swap_webprobe-y := webprobe.o diff --git a/webprobe/webprobe.c b/webprobe/webprobe.c new file mode 100644 index 0000000..d4bc268 --- /dev/null +++ b/webprobe/webprobe.c @@ -0,0 +1,168 @@ +/** + * webprobe/webprobe.c + * @author Ruslan Soloviev + * + * @section LICENSE + * + * 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. + * + * @section COPYRIGHT + * + * Copyright (C) Samsung Electronics, 2014 + * + * @section DESCRIPTION + * + * Web application profiling + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +static int webprobe_copy(struct probe_info *dest, + const struct probe_info *source) +{ + memcpy(dest, source, sizeof(*source)); + + return 0; +} + +static void webprobe_cleanup(struct probe_info *probe_i) +{ +} + +static struct uprobe *webprobe_get_uprobe(struct us_ip *ip) +{ + return &ip->retprobe.up; +} + +static int webprobe_register_probe(struct us_ip *ip) +{ + return swap_register_uretprobe(&ip->retprobe); +} + +static void webprobe_unregister_probe(struct us_ip *ip, int disarm) +{ + __swap_unregister_uretprobe(&ip->retprobe, disarm); +} + +static int entry_web_handler(struct uretprobe_instance *ri, struct pt_regs *regs) +{ + struct uretprobe *rp = ri->rp; + + if (rp && get_quiet() == QT_OFF) { + struct us_ip *ip = container_of(rp, struct us_ip, retprobe); + unsigned long addr = (unsigned long)ip->orig_addr; + + entry_web_event(addr, regs); + } + + return 0; +} + +static int exit_web_handler(struct uretprobe_instance *ri, struct pt_regs *regs) +{ + struct uretprobe *rp = ri->rp; + + if (rp && get_quiet() == QT_OFF) { + struct us_ip *ip = container_of(rp, struct us_ip, retprobe); + unsigned long addr = (unsigned long)ip->orig_addr; + + exit_web_event(addr, regs); + } + + return 0; +} + +static int ret_web_handler(struct uretprobe_instance *ri, struct pt_regs *regs) +{ + set_wrt_launcher_port((int)regs_return_value(regs)); + + return 0; +} + +#define WEB_FUNC_INSPSERVSTART 0 +#define WEB_FUNC_WILLEXECUTE 1 +#define WEB_FUNC_DIDEXECUTE 2 + +static void webprobe_init(struct us_ip *ip) +{ + static int fcnt = 0; + + switch(fcnt++) { + case WEB_FUNC_INSPSERVSTART: + ip->retprobe.entry_handler = NULL; + ip->retprobe.handler = ret_web_handler; + printk("SWAP_WEBPROBE: web function ewk_view_inspector_server_start\n"); + break; + case WEB_FUNC_WILLEXECUTE: + /* TODO: use uprobe instead of uretprobe */ + ip->retprobe.entry_handler = entry_web_handler; + ip->retprobe.handler = NULL; + printk("SWAP_WEBPROBE: web function willExecute\n"); + break; + case WEB_FUNC_DIDEXECUTE: + /* TODO: use uprobe instead of uretprobe */ + ip->retprobe.entry_handler = exit_web_handler; + ip->retprobe.handler = NULL; + printk("SWAP_WEBPROBE: web function didExecute\n"); + /* FIXME: probes can be set more than once */ + fcnt = 0; + break; + default: + printk("SWAP_WEBPROBE: web functions more than necessary\n"); + } + + ip->retprobe.maxactive = 0; +} + +static void webprobe_uninit(struct us_ip *ip) +{ + webprobe_cleanup(&ip->probe_i); +} + + +static struct probe_iface webprobe_iface = { + .init = webprobe_init, + .uninit = webprobe_uninit, + .reg = webprobe_register_probe, + .unreg = webprobe_unregister_probe, + .get_uprobe = webprobe_get_uprobe, + .copy = webprobe_copy, + .cleanup = webprobe_cleanup +}; + +static int __init webprobe_module_init(void) +{ + return swap_register_probe_type(SWAP_WEBPROBE, &webprobe_iface); +} + +static void __exit webprobe_module_exit(void) +{ + swap_unregister_probe_type(SWAP_WEBPROBE); +} + +module_init(webprobe_module_init); +module_exit(webprobe_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SWAP webprobe"); +MODULE_AUTHOR("Ruslan Soloviev "); diff --git a/writer/swap_writer_module.c b/writer/swap_writer_module.c index 00e35c7..4162628 100644 --- a/writer/swap_writer_module.c +++ b/writer/swap_writer_module.c @@ -70,7 +70,9 @@ enum MSG_ID { MSG_CONTEXT_SWITCH_EXIT = 0x0011, /**< Context switch exit */ MSG_PROC_MAP = 0x0012, /**< Process map */ MSG_PROC_UNMAP = 0x0013, /**< Process unmap */ - MSG_PROC_COMM = 0x0014 /**< Process comm */ + MSG_PROC_COMM = 0x0014, /**< Process comm */ + MSG_WEB_FUNCTION_ENTRY = 0x0015, /**< Web function entry */ + MSG_WEB_FUNCTION_EXIT = 0x0016 /**< Web function exit */ }; static char *cpu_buf[NR_CPUS]; @@ -1240,6 +1242,7 @@ static int pack_custom_event(char *buf, int len, const char *fmt, va_list args) enum { max_str_len = 512 }; const char *p; char *buf_orig = buf; + int len_s = 0; for (p = fmt; *p != '\0'; p++) { char ch = *p; @@ -1252,6 +1255,13 @@ static int pack_custom_event(char *buf, int len, const char *fmt, va_list args) len -= 1; switch (ch) { + case '*': /* string length (without '\0') */ + /* usage: '*s' or '*S' */ + /* will not pack to buffer */ + len_s = va_arg(args, int); + buf -= 1; + len += 1; + break; case 'b': /* 1 byte(bool) */ if (len < 1) return -ENOMEM; @@ -1292,11 +1302,14 @@ static int pack_custom_event(char *buf, int len, const char *fmt, va_list args) case 's': /* userspace string with '\0' terminating byte */ { const char __user *str; - int len_s, n; + int n; str = va_arg(args, const char __user *); /* strnlen_user includes '\0' in its return value */ - len_s = strnlen_user(str, max_str_len); + if (len_s == 0) + len_s = strnlen_user(str, max_str_len); + else + len_s++; /* + '\0' */ if (len < len_s) return -ENOMEM; /* strncpy_from_user returns the length of the copied @@ -1308,15 +1321,16 @@ static int pack_custom_event(char *buf, int len, const char *fmt, va_list args) buf += n + 1; len -= n + 1; + len_s = 0; break; } case 'S': /* kernelspace string with '\0' terminating byte */ { const char *str; - int len_s; str = va_arg(args, const char *); - len_s = strnlen(str, max_str_len); + if (len_s == 0) + len_s = strnlen(str, max_str_len); if (len < len_s + 1) /* + '\0' */ return -ENOMEM; strncpy(buf, str, len_s); @@ -1324,6 +1338,7 @@ static int pack_custom_event(char *buf, int len, const char *fmt, va_list args) buf += len_s + 1; len -= len_s + 1; + len_s = 0; break; } case 'a': /* userspace byte array (len + ptr) */ @@ -1374,6 +1389,18 @@ static int pack_custom_event(char *buf, int len, const char *fmt, va_list args) return buf - buf_orig; } +static int pack_custom_args(char *buf, int len, const char *fmt, ...) +{ + va_list vargs; + int ret; + + va_start(vargs, fmt); + ret = pack_custom_event(buf, len, fmt, vargs); + va_end(vargs); + + return ret; +} + enum { max_custom_event_size = 2048 }; /** @@ -1455,6 +1482,115 @@ put_buf: } EXPORT_SYMBOL_GPL(custom_exit_event); + + + +/* ============================================================================ + * = WEB APP EVENT = + * ============================================================================ + */ + +/* TODO: develop method for obtaining this data during build... */ +/* location: webkit2-efl-123997_0.11.113/Source/WTF/wtf/text/StringImpl.h:70 */ +struct MStringImpl { + unsigned m_refCount; + unsigned m_length; + union { + const unsigned char *m_data8; + const unsigned short *m_data16; + }; + union { + void* m_buffer; + struct MStringImpl *m_substringBuffer; + unsigned short *m_copyData16; + }; + unsigned m_hashAndFlags; +}; + +/* location: webkit2-efl-123997_0.11.113/Source/JavaScriptCore/profiler/ + * CallIdentifier.h:36 + */ +struct MCallIdentifier { + struct MStringImpl *m_name; + struct MStringImpl *m_url; + unsigned m_lineNumber; +}; + +int entry_web_event(unsigned long func_addr, struct pt_regs *regs) +{ + char *buf, *payload; + int ret, t; + struct MCallIdentifier *callIdentifier; + struct { + const char *str; + int len; + } m_name, m_url; + + if (!check_event(current)) + return 0; + + callIdentifier = (void *)swap_get_uarg(regs, 2); + + if (!(!get_user(t, (int *)&callIdentifier->m_name) && + !get_user(m_name.str, &((struct MStringImpl *)t)->m_data8) && + !get_user(m_name.len, &((struct MStringImpl *)t)->m_length) && + !get_user(t, (int *)&callIdentifier->m_url) && + !get_user(m_url.str, &((struct MStringImpl *)t)->m_data8) && + !get_user(m_url.len, &((struct MStringImpl *)t)->m_length))) { + printk("SWAP_WRITER: cannot read user memory\n"); + return 0; + } + + buf = get_current_buf(); + payload = pack_basic_msg_fmt(buf, MSG_WEB_FUNCTION_ENTRY); + payload = pack_msg_func_entry(payload, "ssd", func_addr, regs, PT_US, + PST_NONE); + payload += pack_custom_args(payload, 1024, "*s*sd", m_name.len, + m_name.str, m_url.len, m_url.str, + callIdentifier->m_lineNumber); + set_len_msg(buf, payload); + ret = write_to_buffer(buf); + put_current_buf(); + + return ret; +} +EXPORT_SYMBOL_GPL(entry_web_event); + +int exit_web_event(unsigned long func_addr, struct pt_regs *regs) +{ + char *buf, *payload; + int ret, t; + struct MCallIdentifier *callIdentifier; + struct { + const char *str; + int len; + } m_name; + + if (!check_event(current)) + return 0; + + callIdentifier = (void *)swap_get_uarg(regs, 2); + + if (!(!get_user(t, (int *)&callIdentifier->m_name) && + !get_user(m_name.str, &((struct MStringImpl *)t)->m_data8) && + !get_user(m_name.len, &((struct MStringImpl *)t)->m_length))) { + printk("SWAP_WRITER: cannot read user memory\n"); + return 0; + } + + buf = get_current_buf(); + payload = pack_basic_msg_fmt(buf, MSG_WEB_FUNCTION_EXIT); + payload = pack_msg_func_entry(payload, "s", func_addr, regs, PT_US, + PST_NONE); + payload += pack_custom_args(payload, 1024, "*s", m_name.len, m_name.str); + set_len_msg(buf, payload); + ret = write_to_buffer(buf); + put_current_buf(); + + return ret; +} +EXPORT_SYMBOL_GPL(exit_web_event); + static int __init swap_writer_module_init(void) { int ret; diff --git a/writer/swap_writer_module.h b/writer/swap_writer_module.h index c975a8e..38f2288 100644 --- a/writer/swap_writer_module.h +++ b/writer/swap_writer_module.h @@ -80,6 +80,9 @@ int entry_event(const char *fmt, unsigned long func_addr, struct pt_regs *regs, int exit_event(char ret_type, struct pt_regs *regs, int pt, int sub_type, unsigned long func_addr, unsigned long ret_addr); +int entry_web_event(unsigned long func_addr, struct pt_regs *regs); +int exit_web_event(unsigned long func_addr, struct pt_regs *regs); + int switch_entry(struct pt_regs *regs); int switch_exit(struct pt_regs *regs);