From 649512d96117cb73d756dbaea6fef24e28354e2e Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=B8ren=20Sandmann=20Pedersen?= Date: Thu, 29 Apr 2004 17:29:09 +0000 Subject: [PATCH] better disk profiling --- binfile.c | 18 ++--- binfile.h | 1 - process.c | 31 ++++++--- sysprof-module.c | 195 +++++++++++++++++++++++++++++++++++++++++++++++++------ sysprof.c | 6 +- 5 files changed, 208 insertions(+), 43 deletions(-) diff --git a/binfile.c b/binfile.c index 64a5b33..295773f 100644 --- 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) diff --git a/binfile.h b/binfile.h index 4d2a282..782d639 100644 --- 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 diff --git a/process.c b/process.c index cdd2e1d..f1dc5d4 100644 --- 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; } diff --git a/sysprof-module.c b/sysprof-module.c index cfb2c1b..75e36eb 100644 --- a/sysprof-module.c +++ b/sysprof-module.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #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); diff --git a/sysprof.c b/sysprof.c index e2a7ffc..1d801e7 100644 --- 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, -- 2.7.4