better disk profiling
authorSøren Sandmann Pedersen <ssp@src.gnome.org>
Thu, 29 Apr 2004 17:29:09 +0000 (17:29 +0000)
committerSøren Sandmann Pedersen <ssp@src.gnome.org>
Thu, 29 Apr 2004 17:29:09 +0000 (17:29 +0000)
binfile.c
binfile.h
process.c
sysprof-module.c
sysprof.c

index 64a5b33..295773f 100644 (file)
--- a/binfile.c
+++ b/binfile.c
@@ -24,7 +24,6 @@ struct BinFile
     int         n_symbols;
     Symbol     *symbols;
     Symbol     undefined;
-    gulong      address;
 };
 
 static bfd *
@@ -279,6 +278,7 @@ read_symbols (BinFile *bf)
     bfd *bfd;
     GArray *symbols;
     asection *sec;
+    ulong load_address;
 
     bf->symbols = NULL;
     bf->n_symbols = 0;
@@ -301,13 +301,13 @@ read_symbols (BinFile *bf)
     if (!bfd_symbols)
        return;
     
-    bf->address = 0xffffffff;
+    load_address = 0xffffffff;
     for (sec = bfd->sections; sec != NULL; sec = sec->next)
     {
        if (sec->flags & SEC_LOAD)
        {
-           if ((gulong)sec->vma < bf->address)
-               bf->address = sec->vma & ~4095;
+           if ((gulong)sec->vma < load_address)
+             load_address = sec->vma & ~4095;
        }
     }
 
@@ -317,6 +317,8 @@ read_symbols (BinFile *bf)
 
     symbols = g_array_new (FALSE, FALSE, sizeof (Symbol));
 
+/*     g_print ("%s: text vma: %x\n", bf->filename, text_section->vma); */
+
     for (i = 0; i < n_symbols; i++)
     {
        Symbol symbol;
@@ -326,7 +328,7 @@ read_symbols (BinFile *bf)
        {
            char *name;
            
-           symbol.address = bfd_asymbol_value (bfd_symbols[i]);
+           symbol.address = bfd_asymbol_value (bfd_symbols[i]) - load_address;
            name = demangle (bfd, bfd_asymbol_name (bfd_symbols[i]));
            symbol.name = g_strdup (name);
            free (name);
@@ -374,12 +376,6 @@ bin_file_free (BinFile *bf)
     g_free (bf);
 }
 
-gulong
-bin_file_get_load_address (BinFile *bf)
-{
-  return bf->address;
-}
-
 const Symbol *
 bin_file_lookup_symbol (BinFile    *bf,
                        gulong     address)
index 4d2a282..782d639 100644 (file)
--- a/binfile.h
+++ b/binfile.h
@@ -12,7 +12,6 @@ BinFile *     bin_file_new           (const char *filename);
 void          bin_file_free          (BinFile    *bin_file);
 const Symbol *bin_file_lookup_symbol (BinFile    *bin_file,
                                      gulong      address);
-gulong        bin_file_get_load_address (BinFile *bf);
 
 /* Symbol */
 struct Symbol
index cdd2e1d..f1dc5d4 100644 (file)
--- a/process.c
+++ b/process.c
@@ -22,6 +22,7 @@ struct Map
     char *     filename;
     gulong     start;
     gulong     end;
+  gulong      offset;
     gboolean   do_offset;
     
     BinFile *  bin_file;
@@ -97,10 +98,12 @@ read_maps (int pid)
        int count;
        guint start;
        guint end;
+       guint offset;
        
        count = sscanf (
-           buffer, "%x-%x %*15s %*x %*u:%*u %*u %255s", &start, &end, file);
-       if (count == 3)
+           buffer, "%x-%x %*15s %x %*u:%*u %*u %255s", 
+           &start, &end, &offset, file);
+       if (count == 4)
        {
            Map *map;
            
@@ -110,7 +113,7 @@ read_maps (int pid)
            map->start = start;
            map->end = end;
            
-           map->do_offset = check_do_offset (map, pid);
+           map->offset = offset; //check_do_offset (map, pid);
            
            map->bin_file = NULL;
            
@@ -257,6 +260,8 @@ process_lookup_symbol (Process *process, gulong address)
     static Symbol undefined;
     const Symbol *result;
     Map *map = process_locate_map (process, address);
+
+/*     g_print ("addr: %x\n", address); */
     
     if (!map)
     {
@@ -268,9 +273,11 @@ process_lookup_symbol (Process *process, gulong address)
        return &undefined;
     }
     
-    /* if (map->do_offset)
-       address -= map->start;
-    */
+/*     if (map->do_offset) */
+/*       address -= map->start; */
+
+    address -= map->start;
+    address += map->offset;
 
     if (!map->bin_file)
        map->bin_file = bin_file_new (map->filename);
@@ -278,10 +285,18 @@ process_lookup_symbol (Process *process, gulong address)
     /* FIXME - this seems to work with prelinked binaries, but is
      * it correct? IE., will normal binaries always have a preferred_addres of 0?
      */
-    address -= map->start;
-    address += bin_file_get_load_address (map->bin_file);
+/*     address = address - map->start + map->offset + bin_file_get_load_address (map->bin_file); */
+/*     address -= map->start; */
+/*     address += map->offset; */
+/*     address += bin_file_get_load_address (map->bin_file); */
+
+/*     g_print ("%s: start: %p, load: %p\n", */
+/*          map->filename, map->start, bin_file_get_load_address (map->bin_file)); */
 
     result = bin_file_lookup_symbol (map->bin_file, address);
+
+/*     g_print ("(%x) %x %x name; %s\n", address, map->start, map->offset, result->name); */
+
     return result;
 }
 
index cfb2c1b..75e36eb 100644 (file)
@@ -10,6 +10,8 @@
 #include <linux/proc_fs.h>
 #include <asm/uaccess.h>
 #include <linux/poll.h>
+#include <asm/unistd.h>
+#include <linux/pagemap.h>
 
 #include "sysprof-module.h"
 
@@ -18,7 +20,7 @@ MODULE_AUTHOR("Soeren Sandmann (sandmann@daimi.au.dk)");
 
 #define SAMPLES_PER_SECOND 50   /* must divide HZ */
 
-static const int cpu_profiler = 1; /* 0: page faults, 1: cpu */
+static const int cpu_profiler = 0; /* 0: page faults, 1: cpu */
 
 static void on_timer_interrupt (void *);
 
@@ -96,26 +98,70 @@ generate_stack_trace (struct task_struct *task,
        trace->truncated = 0;
 }
 
+static int
+disk_access (struct vm_area_struct *area,
+            unsigned long address)
+{
+    struct file *file = area->vm_file;
+    struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
+    struct inode *inode = mapping->host;
+    struct page *page, **hash;
+    unsigned long size, pgoff, endoff;
+    int disk_access = 1;
+    
+    pgoff = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff;
+    endoff = ((area->vm_end - area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff;
+    
+    /*
+     * An external ptracer can access pages that normally aren't
+     * accessible..
+     */
+    size = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+    if ((pgoff >= size) && (area->vm_mm == current->mm))
+       return 0;
+    
+    /* The "size" of the file, as far as mmap is concerned, isn't bigger than the mapping */
+    if (size > endoff)
+       size = endoff;
+    
+    /*
+     * Do we have something in the page cache already?
+     */
+    hash = page_hash(mapping, pgoff);
+    
+    page = __find_get_page(mapping, pgoff, hash);
+    if (page)
+       /*
+        * Ok, found a page in the page cache, now we need to check
+        * that it's up-to-date.
+        */
+       if (Page_Uptodate(page))
+           disk_access = 0;
+
+    return disk_access;
+}
+
 struct page *
 hijacked_nopage (struct vm_area_struct * area,
                 unsigned long address,
                 int unused)
 {
-    if (current && current->pid != 0)
+    struct page *result;
+    int disk;
+
+    disk = disk_access (area, address);
+
+    printk (KERN_ALERT "disk access: %d\n", disk);
+    
+    result = filemap_nopage (area, address, unused);
+
+    if (current && current->pid != 0 && disk)
     {
-#if 0
        generate_stack_trace (current, head);
-       if (head++ == &stack_traces[N_TRACES - 1])
-           head = &stack_traces[0];
 
-       wake_up (&wait_for_trace);
-#endif
-       memset (head, 0, sizeof (SysprofStackTrace));
-
-       head->n_addresses = 1;
-       head->pid = current->pid;
-       head->addresses[0] = (void *)address;
-       head->truncated = 0;
+/*     head->pid = current->pid; */
+/*     head->addresses[0] = (void *)address; */
+/*     head->truncated = 0; */
 
        if (area->vm_file)
        {
@@ -141,8 +187,15 @@ hijacked_nopage (struct vm_area_struct * area,
 
        wake_up (&wait_for_trace);
     }
-    
-    return filemap_nopage (area, address, unused);   
+
+    return result;
+}
+
+static void
+hijack_nopage (struct vm_area_struct *vma)
+{
+    if (vma->vm_ops && vma->vm_ops->nopage == filemap_nopage)
+       vma->vm_ops->nopage = hijacked_nopage;
 }
 
 static void
@@ -155,10 +208,7 @@ hijack_nopages (struct task_struct *task)
        return;
 
     for (vma = mm->mmap; vma != NULL; vma = vma->vm_next)
-    {
-       if (vma->vm_ops && vma->vm_ops->nopage == filemap_nopage)
-           vma->vm_ops->nopage = hijacked_nopage;
-    }
+       hijack_nopage (vma);
 }
 
 static void
@@ -183,6 +233,93 @@ clean_hijacked_nopages (void)
     }
 }
 
+struct mmap_arg_struct {
+       unsigned long addr;
+       unsigned long len;
+       unsigned long prot;
+       unsigned long flags;
+       unsigned long fd;
+       unsigned long offset;
+};
+
+typedef asmlinkage int (* old_mmap_func) (struct mmap_arg_struct *arg);
+typedef asmlinkage long (* mmap2_func) (
+    unsigned long addr, unsigned long len,
+    unsigned long prot, unsigned long flags,
+    unsigned long fd, unsigned long pgoff);
+
+static mmap2_func orig_mmap2;
+static old_mmap_func orig_mmap;
+
+static void
+after_mmap (long res, unsigned long len)
+{
+    struct vm_area_struct *vma;
+    unsigned long start;
+
+    if (res == -1 || !current || current->pid == 0)
+       return;
+
+    start = res;
+    
+    vma = find_vma (current->mm, start);
+
+    if (vma && vma->vm_end >= start + len)
+       hijack_nopage (vma);
+#if 0
+    else if (vma)
+    {
+       printk (KERN_ALERT "nope: vm_start: %x, vm_end: %x\n"
+               "start: %p, len: %x, start + len: %x\n",
+               vma->vm_start, vma->vm_end, start, len, start + len);
+    }
+    else
+       printk (KERN_ALERT "no vma\n");
+#endif
+    
+}
+
+static long
+new_mmap2 (unsigned long addr, unsigned long len,
+          unsigned long prot, unsigned long flags,
+          unsigned long fd,   unsigned long pgoff)
+{
+    int res = orig_mmap2 (addr, len, prot, flags, fd, pgoff);
+
+    after_mmap (res, len);
+
+    return res;
+}
+
+static int
+new_mmap (struct mmap_arg_struct *arg)
+{
+    int res = orig_mmap (arg);
+
+    after_mmap (res, arg->len);
+
+    return res;
+}
+
+void **sys_call_table = (void **)0xc0347df0;
+
+static void
+hijack_mmaps (void)
+{
+    orig_mmap2 = sys_call_table[__NR_mmap2];
+    sys_call_table[__NR_mmap2] = new_mmap2;
+    
+    orig_mmap = sys_call_table[__NR_mmap];
+    sys_call_table[__NR_mmap] = new_mmap;
+}
+
+static void
+restore_mmaps (void)
+{
+    sys_call_table[__NR_mmap2] = orig_mmap2;
+    sys_call_table[__NR_mmap] = orig_mmap;
+}
+
 static void
 on_timer_interrupt (void *data)
 {
@@ -190,7 +327,12 @@ on_timer_interrupt (void *data)
     
     if (exiting)
     {
-       clean_hijacked_nopages ();
+       if (!cpu_profiler)
+       {
+           restore_mmaps();
+           
+           clean_hijacked_nopages ();
+       }
        wake_up (&wait_for_exit);
        return;
     }
@@ -211,7 +353,9 @@ on_timer_interrupt (void *data)
        }
        else
        {
+#if 0
            hijack_nopages (current);
+#endif
        }
     }
     
@@ -258,6 +402,7 @@ procfile_poll (struct file *filp, poll_table *poll_table)
 int
 init_module (void)
 {
+    struct task_struct *task;
     trace_proc_file =
        create_proc_entry ("sysprof-trace", S_IFREG | S_IRUGO, &proc_root);
     
@@ -267,6 +412,16 @@ init_module (void)
     trace_proc_file->read_proc = procfile_read;
     trace_proc_file->proc_fops->poll = procfile_poll;
     trace_proc_file->size = sizeof (SysprofStackTrace);
+
+    if (!cpu_profiler)
+    {
+       hijack_mmaps ();
+       
+       for_each_process (task)
+           {
+               hijack_nopages (task);
+           }
+    }
     
     queue_task(&timer_task, &tq_timer);
     
index e2a7ffc..1d801e7 100644 (file)
--- a/sysprof.c
+++ b/sysprof.c
@@ -113,10 +113,10 @@ on_read (gpointer data)
     {
        Process *process = process_get_from_pid (trace.pid);
        int i;
-       char *filename = NULL;
+/*     char *filename = NULL; */
 
-       if (*trace.filename)
-           filename = trace.filename;
+/*     if (*trace.filename) */
+/*         filename = trace.filename; */
        
        for (i = 0; i < trace.n_addresses; ++i)
            process_ensure_map (process, trace.pid,