Implemented new approach for sending profile into the kernel module.
authorNikita Kalyazin <n.kalyazin@samsung.com>
Thu, 18 Nov 2010 08:14:19 +0000 (11:14 +0300)
committerNikita Kalyazin <n.kalyazin@samsung.com>
Thu, 18 Nov 2010 11:42:44 +0000 (14:42 +0300)
CProfile is converted into some plain structure (called Bundle) and then sent to the kernel module at once. It allowes to reduce time consumption after pressing Start button in GUI.
Standalone mode and DynInst mode must be broken for a while.

driver/device_driver.c
driver/device_driver.h
driver/ec_ioctl.h
driver/storage.c
driver/storage.h

index 0ef4d1b..42ce789 100644 (file)
@@ -332,6 +332,71 @@ static int device_ioctl (struct inode *inode UNUSED, struct file *file UNUSED, u
 
                        break;
                }*/
+       case EC_IOCTL_SET_APPDEPS:
+       {
+               size_t size;
+               result = copy_from_user(&size, (void *)arg, sizeof(size_t));
+               if (result) {
+                       EPRINTF("Cannot copy deps size!\n");
+                       result = -1;
+                       break;
+               }
+               DPRINTF("Deps size has been copied (%d)\n", size);
+
+               deps = vmalloc(size);
+               if (deps == NULL) {
+                       EPRINTF("Cannot alloc mem for deps!\n");
+                       result = -1;
+                       break;
+               }
+               DPRINTF("Mem for deps has been alloced\n");
+
+               result = copy_from_user(deps, (void *)arg, size);
+               if (result) {
+                       EPRINTF("Cannot copy deps!\n");
+                       result = -1;
+                       break;
+               }
+               DPRINTF("Deps has been copied successfully\n");
+
+               break;
+       }
+       case EC_IOCTL_SET_PROFILEBUNDLE:
+       {
+               size_t size;
+
+               result = copy_from_user(&size, (void *)arg, sizeof(size_t));
+               if (result) {
+                       EPRINTF("Cannot copy bundle size!\n");
+                       result = -1;
+                       break;
+               }
+               DPRINTF("Bundle size has been copied\n");
+
+               bundle = vmalloc(size);
+               if (bundle == NULL) {
+                       EPRINTF("Cannot alloc mem for bundle!\n");
+                       result = -1;
+                       break;
+               }
+               DPRINTF("Mem for bundle has been alloced\n");
+
+               result = copy_from_user(bundle, (void *)arg, size);
+               if (result) {
+                       EPRINTF("Cannot copy bundle!\n");
+                       result = -1;
+                       break;
+               }
+               DPRINTF("Bundle has been copied successfully\n");
+
+               if (link_bundle() == -1) {
+                       EPRINTF("Cannot link profile bundle!\n");
+                       result = -1;
+                       break;
+               }
+
+               break;
+       }
        case EC_IOCTL_RESET_PROBES:
                {
                        result = reset_probes();
@@ -397,6 +462,7 @@ static int device_ioctl (struct inode *inode UNUSED, struct file *file UNUSED, u
                        result = -1;
                        break;
                }
+               vfree(bundle);
                result = 0;
                DPRINTF("Stop and Detach Probes");
                blocking_notifier_call_chain(&inperfa_notifier_list, EC_IOCTL_STOP_AND_DETACH, (void*)&gl_nNotifyTgid);
index 07cd467..aa22bc4 100644 (file)
@@ -27,5 +27,7 @@
 extern int device_init (void);
 extern void device_down (void);
 extern void notify_user (event_id_t event_id);
+extern char *deps;
+extern char *bundle;
 
 #endif /* !defined(device_driver_h) */
index 17c13e4..20ce90c 100644 (file)
@@ -36,6 +36,8 @@ typedef enum
        EC_IOCTL_DESELECT_PROBE,
        EC_IOCTL_GET_PROBE_INFO,
        EC_IOCTL_ADD_PROBE,
+       EC_IOCTL_SET_APPDEPS,
+       EC_IOCTL_SET_PROFILEBUNDLE,
        //EC_IOCTL_REMOVE_PROBE,
        EC_IOCTL_RESET_PROBES,
        EC_IOCTL_SET_COMPLEX_PROBES,
index c8fbe07..c66e73f 100644 (file)
@@ -28,6 +28,8 @@
 
 char *p_buffer = NULL;
 inst_us_proc_t us_proc_info;
+char *deps;
+char *bundle;
 struct hlist_head kernel_probes;
 int event_mask = 0L;
 struct cond cond_list;
@@ -963,6 +965,371 @@ int set_us_proc_inst_info (ioctl_inst_usr_space_proc_t * inst_info)
        return 0;
 }
 
+char *find_lib_path(const char *lib_name)
+{
+       char *p = deps + sizeof(size_t);
+       char *match;
+       size_t len;
+
+       while (*p != '\0') {
+               DPRINTF("p is at %s", p);
+               len = strlen(p) + 1;
+               match = strstr(p, lib_name);
+               p += len;
+               len = strlen(p) + 1; /* we are at path now */
+               if (!match) {
+                       p += len;
+               } else {
+                       DPRINTF("Found match: %s", match);
+                       return p;
+               }
+       }
+
+       return p;
+}
+
+void unlink_bundle(void)
+{
+       int i, k;
+       us_proc_lib_t *d_lib;
+       char *path;
+       struct list_head *pos;  //, *tmp;
+
+       path = us_proc_info.path;
+       us_proc_info.path = 0;
+
+       // first make sure "d_lib" is not used any more and only
+       // then release storage
+       if (us_proc_info.p_libs)
+       {
+               int count1 = us_proc_info.libs_count;
+               us_proc_info.libs_count = 0;
+               for (i = 0; i < count1; i++)
+               {
+                       d_lib = &us_proc_info.p_libs[i];
+                       if (d_lib->p_ips)
+                       {
+                               // first make sure "d_lib->p_ips" is not used any more and only
+                               // then release storage
+                               //int count2 = d_lib->ips_count;
+                               d_lib->ips_count = 0;
+                               /*for (k = 0; k < count2; k++)
+                                       kfree ((void *) d_lib->p_ips[k].name);*/
+                               vfree ((void *) d_lib->p_ips);
+                       }
+                       /* if (d_lib->p_vtps) */
+                       /* { */
+                       /*      // first make sure "d_lib->p_vtps" is not used any more and only */
+                       /*      // then release storage */
+                       /*      int count2 = d_lib->vtps_count; */
+                       /*      d_lib->vtps_count = 0; */
+                       /*      for (k = 0; k < count2; k++) */
+                       /*      { */
+                       /*              //list_for_each_safe_rcu(pos, tmp, &d_lib->p_vtps[k].list) { */
+                       /*              list_for_each_rcu (pos, &d_lib->p_vtps[k].list) */
+                       /*              { */
+                       /*                      us_proc_vtp_data_t *vtp = list_entry (pos, us_proc_vtp_data_t, list); */
+                       /*                      list_del_rcu (pos); */
+                       /*                      //kfree (vtp->name); */
+                       /*                      kfree (vtp); */
+                       /*              } */
+                       /*      } */
+                       /*      kfree ((void *) d_lib->p_vtps); */
+                       /* } */
+                       //kfree ((void *) d_lib->path);
+                       //putname(d_lib->path);
+               }
+               kfree ((void *) us_proc_info.p_libs);
+               us_proc_info.p_libs = 0;
+       }
+       /* if (path) */
+       /* { */
+       /*      kfree ((void *) path); */
+       /*      //putname(path); */
+       /* } */
+
+       us_proc_info.tgid = 0;
+}
+
+int link_bundle()
+{
+       inst_us_proc_t *my_uprobes_info;
+       inst_us_proc_t empty_uprobes_info =
+       {
+               .libs_count = 0,
+               .p_libs = NULL,
+       };
+       char *p = bundle; /* read pointer for bundle */
+       int nr_kern_probes;
+       int i, l, k;
+       int len;
+       us_proc_lib_t *d_lib, *pd_lib;
+       struct nameidata nd;
+       int is_app = 0;
+       char *ptr;
+       us_proc_ip_t *d_ip;
+
+       /* Get user-defined us handlers (if they are provided) */
+       my_uprobes_info = (inst_us_proc_t *)lookup_name("my_uprobes_info");
+       if (my_uprobes_info == 0)
+               my_uprobes_info = &empty_uprobes_info;
+
+       DPRINTF("Going to release us_proc_info");
+       if (us_proc_info.path)
+               unlink_bundle();
+
+       /* Skip size - it has been used before */
+       p += sizeof(u_int32_t);
+
+       /* Set mode */
+       if (SetECMode(*(u_int32_t *)p) == -1) {
+               EPRINTF("Cannot set mode!\n");
+               return -1;
+       }
+       p += sizeof(u_int32_t);
+
+       /* Buffer size */
+       if (SetBufferSize(*(u_int32_t *)p) == -1) {
+               EPRINTF("Cannot set buffer size!\n");
+               return -1;
+       }
+       p += sizeof(u_int32_t);
+
+       /* Kernel probes */
+       nr_kern_probes = *(u_int32_t *)p;
+       p += sizeof(u_int32_t);
+       for (i = 0; i < nr_kern_probes; i++) {
+               if (add_probe(*(u_int32_t *)p)) {
+                       EPRINTF("Cannot add kernel probe at 0x%x!\n", *(u_int32_t *)p);
+                       return -1;
+               }
+               p += sizeof(u_int32_t);
+       }
+
+       /* Us probes */
+       len = *(u_int32_t *)p; /* App path len */
+       p += sizeof(u_int32_t);
+       us_proc_info.path = (char *)p;
+       DPRINTF("app path = %s", us_proc_info.path);
+       p += len;
+       if (strcmp(us_proc_info.path, "*")) {
+           if (path_lookup(us_proc_info.path, LOOKUP_FOLLOW, &nd) != 0) {
+                       EPRINTF("failed to lookup dentry for path %s!", us_proc_info.path);
+                       return -1;
+               }
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
+           us_proc_info.m_f_dentry = nd.dentry;
+           path_release(&nd);
+#else
+           us_proc_info.m_f_dentry = nd.path.dentry;
+           path_put(&nd.path);
+#endif
+       } else {
+           us_proc_info.m_f_dentry = NULL;
+       }
+       us_proc_info.libs_count = *(u_int32_t *)p;
+       DPRINTF("nr of libs = %d", us_proc_info.libs_count);
+       p += sizeof(u_int32_t);
+       us_proc_info.p_libs =
+               kmalloc(us_proc_info.libs_count * sizeof(us_proc_lib_t), GFP_KERNEL);
+       if (!us_proc_info.p_libs) {
+               EPRINTF("Cannot alloc p_libs!");
+               return -1;
+       }
+       memset(us_proc_info.p_libs, 0,
+                  us_proc_info.libs_count * sizeof(us_proc_lib_t));
+
+       for (i = 0; i < us_proc_info.libs_count; i++) {
+               d_lib = &us_proc_info.p_libs[i];
+               int lib_name_len = *(u_int32_t *)p;
+               p += sizeof(u_int32_t);
+               d_lib->path = (char *)p;
+               DPRINTF("d_lib->path = %s", d_lib->path);
+
+               if (strcmp(us_proc_info.path, d_lib->path) == 0)
+                       is_app = 1;
+               else {
+                       is_app = 0;
+                       DPRINTF("Searching path for lib %s", d_lib->path);
+                       d_lib->path = find_lib_path(d_lib->path);
+                       if (!d_lib->path) {
+                               EPRINTF("Cannot find path!");
+                               return -1;
+                       }
+               }
+
+               if (path_lookup(d_lib->path, LOOKUP_FOLLOW, &nd) != 0) {
+                       EPRINTF ("failed to lookup dentry for path %s!", d_lib->path);
+                       continue;
+               }
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
+               d_lib->m_f_dentry = nd.dentry;
+               path_release(&nd);
+#else
+               d_lib->m_f_dentry = nd.path.dentry;
+               path_put(&nd.path);
+#endif
+               p += lib_name_len;
+               d_lib->ips_count = *(u_int32_t *)p;
+               p += sizeof(u_int32_t);
+
+               pd_lib = NULL;
+               ptr = strrchr(d_lib->path, '/');
+               if (ptr)
+                       ptr++;
+               else
+                       ptr = d_lib->path;
+               for (l = 0; l < my_uprobes_info->libs_count; l++) {
+                       if ((strcmp(ptr, my_uprobes_info->p_libs[l].path) == 0) ||
+                               (is_app && *(my_uprobes_info->p_libs[l].path) == '\0')) {
+                               pd_lib = &my_uprobes_info->p_libs[l];
+                               break;
+                       }
+               }
+
+               if (d_lib->ips_count > 0) {
+                       us_proc_info.unres_ips_count += d_lib->ips_count;
+                       d_lib->p_ips = vmalloc(d_lib->ips_count * sizeof(us_proc_ip_t));
+                       DPRINTF("d_lib[%i]->p_ips=%p/%u [%s]", i, d_lib->p_ips,
+                                       us_proc_info.unres_ips_count, d_lib->path);
+                       if (!d_lib->p_ips) {
+                               EPRINTF("Cannot alloc p_ips!\n");
+                               return -1;
+                       }
+                       memset (d_lib->p_ips, 0, d_lib->ips_count * sizeof(us_proc_ip_t));
+                       for (k = 0; k < d_lib->ips_count; k++) {
+                               d_ip = &d_lib->p_ips[k];
+                               d_ip->offset = *(u_int32_t *)p;
+                               p += sizeof(u_int32_t);
+                               p += sizeof(u_int32_t); /* Skip inst type */
+
+                               if (pd_lib) {
+                                       for (l = 0; l < pd_lib->ips_count; l++) {
+                                               if (d_ip->offset == pd_lib->p_ips[l].offset) {
+                                                       DPRINTF("predefined probe %s in %s at %lx",
+                                                                       pd_lib->p_ips[l].name, pd_lib->path,
+                                                                       pd_lib->p_ips[l].offset);
+                                                       d_ip->jprobe.pre_entry =
+                                                               pd_lib->p_ips[l].jprobe.pre_entry;
+                                                       d_ip->jprobe.entry =
+                                                               pd_lib->p_ips[l].jprobe.entry;
+                                                       d_ip->retprobe.handler =
+                                                               pd_lib->p_ips[l].retprobe.handler;
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+               }
+/*             if (s_lib.vtps_count > 0) */
+/*             { */
+/*                     unsigned long ucount = 1, pre_addr; */
+/*                     // array containing elements like (addr, index) */
+/*                     unsigned long *addrs = kmalloc (s_lib.vtps_count * 2 * sizeof (unsigned long), GFP_KERNEL); */
+/* //                  DPRINTF ("addrs=%p/%u", addrs, s_lib.vtps_count); */
+/*                     if (!addrs) */
+/*                     { */
+/*                             //note: storage will released next time or at clean-up moment */
+/*                             return -ENOMEM; */
+/*                     } */
+/*                     memset (addrs, 0, s_lib.vtps_count * 2 * sizeof (unsigned long)); */
+/*                     // fill the array in */
+/*                     for (k = 0; k < s_lib.vtps_count; k++) */
+/*                     { */
+/*                             if (copy_from_user ((void *) &s_vtp, &s_lib.p_vtps[k], sizeof (ioctl_usr_space_vtp_t))) */
+/*                             { */
+/*                                     //note: storage will released next time or at clean-up moment */
+/*                                     EPRINTF ("copy_from_user VTP failed %p", &s_lib.p_vtps[k]); */
+/*                                     kfree (addrs); */
+/*                                     return -EFAULT; */
+/*                             } */
+/*                             addrs[2 * k] = s_vtp.addr; */
+/*                             addrs[2 * k + 1] = k; */
+/*                     } */
+/*                     // sort by VTP addresses, i.e. make VTPs with the same addresses adjacent; */
+/*                     // organize them into bundles */
+/*                     sort (addrs, s_lib.vtps_count, 2 * sizeof (unsigned long), addr_cmp, generic_swap); */
+
+/*                     // calc number of VTPs with unique addresses  */
+/*                     for (k = 1, pre_addr = addrs[0]; k < s_lib.vtps_count; k++) */
+/*                     { */
+/*                             if (addrs[2 * k] != pre_addr) */
+/*                                     ucount++;       // count different only */
+/*                             pre_addr = addrs[2 * k]; */
+/*                     } */
+/*                     us_proc_info.unres_vtps_count += ucount; */
+/*                     d_lib->vtps_count = ucount; */
+/*                     d_lib->p_vtps = kmalloc (ucount * sizeof (us_proc_vtp_t), GFP_KERNEL); */
+/*                     DPRINTF ("d_lib[%i]->p_vtps=%p/%lu", i, d_lib->p_vtps, ucount); //, d_lib->path); */
+/*                     if (!d_lib->p_vtps) */
+/*                     { */
+/*                             //note: storage will released next time or at clean-up moment */
+/*                             kfree (addrs); */
+/*                             return -ENOMEM; */
+/*                     } */
+/*                     memset (d_lib->p_vtps, 0, d_lib->vtps_count * sizeof (us_proc_vtp_t)); */
+/*                     // go through sorted VTPS. */
+/*                     for (k = 0, j = 0, pre_addr = 0, mvtp = NULL; k < s_lib.vtps_count; k++) */
+/*                     { */
+/*                             us_proc_vtp_data_t *vtp_data; */
+/*                             // copy VTP data */
+/*                             if (copy_from_user ((void *) &s_vtp, &s_lib.p_vtps[addrs[2 * k + 1]], sizeof (ioctl_usr_space_vtp_t))) */
+/*                             { */
+/*                                     //note: storage will released next time or at clean-up moment */
+/*                                     EPRINTF ("copy_from_user VTP failed %p", &s_lib.p_vtps[addrs[2 * k + 1]]); */
+/*                                     kfree (addrs); */
+/*                                     return -EFAULT; */
+/*                             } */
+/*                             // if this is the first VTP in bundle (master VTP) */
+/*                             if (addrs[2 * k] != pre_addr) */
+/*                             { */
+/*                                     // data are in the array of master VTPs */
+/*                                     mvtp = &d_lib->p_vtps[j++]; */
+/*                                     mvtp->addr = s_vtp.addr; */
+/*                                     INIT_LIST_HEAD (&mvtp->list); */
+/*                             } */
+/*                             // data are in the list of slave VTPs */
+/*                             vtp_data = kmalloc (sizeof (us_proc_vtp_data_t), GFP_KERNEL); */
+/*                             if (!vtp_data) */
+/*                             { */
+/*                                     //note: storage will released next time or at clean-up moment */
+/*                                     kfree (addrs); */
+/*                                     return -ENOMEM; */
+/*                             } */
+
+/*                             /\*len = strlen_user (s_vtp.name); */
+/*                             vtp_data->name = kmalloc (len, GFP_KERNEL); */
+/*                             if (!vtp_data->name) */
+/*                             { */
+/*                                     //note: storage will released next time or at clean-up moment */
+/*                                     kfree (vtp_data); */
+/*                                     kfree (addrs); */
+/*                                     return -ENOMEM; */
+/*                             } */
+/*                             if (strncpy_from_user (vtp_data->name, s_vtp.name, len) != (len-1)) */
+/*                             { */
+/*                                     //note: storage will released next time or at clean-up moment */
+/*                                     EPRINTF ("strncpy_from_user VTP name failed %p (%ld)", vtp_data->name, len); */
+/*                                     kfree (vtp_data->name); */
+/*                                     kfree (vtp_data); */
+/*                                     kfree (addrs); */
+/*                                     return -EFAULT; */
+/*                             } */
+/*                             //vtp_data->name[len] = 0;*\/ */
+/*                             vtp_data->type = s_vtp.type; */
+/*                             vtp_data->size = s_vtp.size; */
+/*                             vtp_data->reg = s_vtp.reg; */
+/*                             vtp_data->off = s_vtp.off; */
+/*                             list_add_tail_rcu (&vtp_data->list, &mvtp->list); */
+/*                             pre_addr = addrs[2 * k]; */
+/*                     } */
+/*                     kfree (addrs); */
+/*             } */
+       }
+
+       return 0;
+}
+
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27)
 #define list_for_each_rcu(pos, head) __list_for_each_rcu(pos, head)
 #endif
index c185c75..e028a60 100644 (file)
@@ -65,6 +65,12 @@ extern void pack_event_info (probe_id_t probe_id, record_type_t record_type, con
 */
 extern int set_us_proc_inst_info (ioctl_inst_usr_space_proc_t * inst_info);
 
+/* Set most links from us_proc_info to data in the bundle */
+int link_bundle();
+
+/* Undo the actions of link_bundle() */
+void unlink_bundle();
+
 /*
     Function "release_us_proc_inst_info()" destroys instrumentation info for user space process.
 */