]> git.itanic.dy.fi Git - scan-pagemap/commitdiff
Add support for listing mappings that are shared between processes
authorTimo Kokkonen <kaapeli@itanic.dy.fi>
Sat, 21 Aug 2010 10:42:54 +0000 (13:42 +0300)
committerTimo Kokkonen <kaapeli@itanic.dy.fi>
Sat, 21 Aug 2010 10:42:54 +0000 (13:42 +0300)
This counts the amoutn of pages that are being shared among the list
of given processes for each mapping the process has.

Signed-off-by: Timo Kokkonen <kaapeli@itanic.dy.fi>
analyze.c
analyze.h
main.c
pagemap.h

index 309043179c97c4fb321b0e1f63c874aed7278388..7a67fb47cc0370b71008fdf7c149b6692c15597e 100644 (file)
--- a/analyze.c
+++ b/analyze.c
 
 struct analyze_frames {
        struct bintree_ops ops;
 
 struct analyze_frames {
        struct bintree_ops ops;
+
+       int pid;
+
+       struct list_head *pidlist;
+       struct maps *map;
+       int pids;
+
        long int pages_present;
        long int pages_swapped;
        long int pages_unique;
        long int pages_present;
        long int pages_swapped;
        long int pages_unique;
-       int pid;
 };
 
 #define bintree_ops_to_af(bintree_ops)                         \
 };
 
 #define bintree_ops_to_af(bintree_ops)                         \
@@ -42,11 +48,61 @@ static void count_pages(struct bintree *b, struct bintree_ops *ops)
        struct maps_list *ml;
 
        if (af->pid) {
        struct maps_list *ml;
 
        if (af->pid) {
+               /* Find pages which reference at least once a pid */
                list_for_each_entry(ml, &pf->ml, list) {
                        if (ml->map->pid == af->pid)
                                goto get_stats;
                }
                return;
                list_for_each_entry(ml, &pf->ml, list) {
                        if (ml->map->pid == af->pid)
                                goto get_stats;
                }
                return;
+       } else if (af->pidlist && af->map) {
+               /*
+                * Find pages that reference at least once all of the
+                * given pids and a given mapping
+                */
+               struct pidlist *pid;
+               int matches = 0;
+
+               /*
+                * Check that we reference the given mapping at least
+                * once
+                */
+               list_for_each_entry(ml, &pf->ml, list) {
+                       if (ml->map == af->map) {
+                               matches++;
+                               break;
+                       }
+               }
+
+               if (!matches)
+                       return;
+               matches = 0;
+
+               /*
+                * Check that we reference all of the given pids
+                * too. The order of the loops is important here. We
+                * must scan through all the references and test for a
+                * given pid. If we would iterate through the
+                * references in the outer loop, we might get
+                * duplicate matches for a pid since it is possible
+                * that a page is mapped multiple times in a process's
+                * addrses space.
+                */
+               list_for_each_entry(pid, af->pidlist, list) {
+                       list_for_each_entry(ml, &pf->ml, list) {
+                               if (ml->map->pid == pid->pid) {
+                                       matches++;
+                                       break;
+                               }
+                       }
+
+                       /*
+                        * If we have found as many matches as ther
+                        * are pids, we will count the stats
+                        */
+                       if (matches == af->pids)
+                               goto get_stats;
+               }
+               return;
        }
 
 get_stats:
        }
 
 get_stats:
@@ -161,14 +217,35 @@ restart:
        printf("Total %d processes\n", processes);
 }
 
        printf("Total %d processes\n", processes);
 }
 
-static void _dump_process_maps(struct process *ps)
+static void _dump_process_maps(struct pageframe *pf, struct process *ps,
+                       struct parse_opts *opts)
 {
        struct maps *map;
        long int swapped, present, total;
        long int biggest = 0, second_biggest;
 {
        struct maps *map;
        long int swapped, present, total;
        long int biggest = 0, second_biggest;
-       int count, processes = 0;
+       int count, processes = 0, pids = 0;
+
+       if (is_parse_option(opts, PARSE_SHARED_MAPPING)) {
+               struct pidlist *pid;
+               list_for_each_entry(pid, &opts->pidlist, list)
+                       pids++;
+       }
 
        list_for_each_entry(map, &ps->maps->list, list) {
 
        list_for_each_entry(map, &ps->maps->list, list) {
+               struct analyze_frames af;
+
+               if (is_parse_option(opts, PARSE_SHARED_MAPPING)) {
+                       memset(&af, 0, sizeof(af));
+                       af.ops.callback = count_pages;
+                       af.pidlist = &opts->pidlist;
+                       af.pids = pids;
+                       af.map = map;
+
+                       bintree_walk(&pf->tree, &af.ops);
+                       map->pages_present = af.pages_present;
+                       map->pages_swapped = af.pages_swapped;
+               }
+
                biggest = MAX(biggest, map->pages_present + map->pages_swapped);
        }
 
                biggest = MAX(biggest, map->pages_present + map->pages_swapped);
        }
 
@@ -190,6 +267,13 @@ restart:
                if (total != biggest)
                        continue;
 
                if (total != biggest)
                        continue;
 
+               /*
+                * Do not print zero sized mappings if
+                * --shared-mappings is enabled
+                */
+               if (is_parse_option(opts, PARSE_SHARED_MAPPING) && total == 0)
+                       continue;
+
                printf("%5lld %sB %5lld %sB %5lld %sB %5lld %sB %s\n",
                        NICE_DIV(map->size), NICE_UNIT(map->size),
                        PAGE_TO_NICE(present), PAGE_TO_NICE_UNIT(present),
                printf("%5lld %sB %5lld %sB %5lld %sB %5lld %sB %s\n",
                        NICE_DIV(map->size), NICE_UNIT(map->size),
                        PAGE_TO_NICE(present), PAGE_TO_NICE_UNIT(present),
@@ -208,11 +292,12 @@ restart:
        printf("\n");
 }
 
        printf("\n");
 }
 
-void dump_process_maps(struct process *process_list)
+void dump_process_maps(struct pageframe *pf, struct process *process_list,
+               struct parse_opts *opts)
 {
        struct process *ps;
 
        list_for_each_entry(ps, &process_list->list, list) {
 {
        struct process *ps;
 
        list_for_each_entry(ps, &process_list->list, list) {
-               _dump_process_maps(ps);
+               _dump_process_maps(pf, ps, opts);
        }
 }
        }
 }
index 2d5010c83d9506ab3eff8ae8c51fab444ae3589a..a80320956796ba4f9ebc2967ddf439e9af78892f 100644 (file)
--- a/analyze.h
+++ b/analyze.h
@@ -6,6 +6,7 @@
 void print_page_stats(struct pageframe *pf);
 void print_pid_stats(struct pageframe *pf, struct process *process_list,
                struct parse_opts *opts);
 void print_page_stats(struct pageframe *pf);
 void print_pid_stats(struct pageframe *pf, struct process *process_list,
                struct parse_opts *opts);
-void dump_process_maps(struct process *process_list);
+void dump_process_maps(struct pageframe *pf, struct process *process_list,
+               struct parse_opts *opts);
 
 #endif
 
 #endif
diff --git a/main.c b/main.c
index 9f9b5c54c7e1cbf90eeb56dc9ab982028718936c..c28ed2a8a7320b4c413a675b53162daf8a29f439 100644 (file)
--- a/main.c
+++ b/main.c
@@ -18,6 +18,7 @@ void print_help_and_die(char *name)
                "given name\n"
                "-m, --map=mapname      scan maps with given mapping name\n"
                "-d, --dump             dump process maps\n"
                "given name\n"
                "-m, --map=mapname      scan maps with given mapping name\n"
                "-d, --dump             dump process maps\n"
+               "-s, --shared-mappings  dump only shared mappings\n"
                "-h, --help             show this help\n",
                name);
 
                "-h, --help             show this help\n",
                name);
 
@@ -50,9 +51,10 @@ void read_args(int argc, char *argv[], struct parse_opts *opts)
                { .val = 'm', .name = "map", .has_arg = 1, },
                { .val = OPT_WITH_THREADS, .name = "with-threads" },
                { .val = 'd', .name = "dump", },
                { .val = 'm', .name = "map", .has_arg = 1, },
                { .val = OPT_WITH_THREADS, .name = "with-threads" },
                { .val = 'd', .name = "dump", },
+               { .val = 's', .name = "shared-mappings", },
                { .val = 'h', .name = "help", },
        };
                { .val = 'h', .name = "help", },
        };
-       char short_options[] = "p:P:m:dh";
+       char short_options[] = "p:P:m:sdh";
        opts->parse_mask = 0;
 
        while (1) {
        opts->parse_mask = 0;
 
        while (1) {
@@ -87,6 +89,9 @@ void read_args(int argc, char *argv[], struct parse_opts *opts)
                case OPT_WITH_THREADS:
                        opts->with_threads = 1;
                        break;
                case OPT_WITH_THREADS:
                        opts->with_threads = 1;
                        break;
+               case 's':
+                       opts->parse_mask |= PARSE_SHARED_MAPPING;
+                       /* implies --dump */
                case 'd':
                        opts->parse_mask |= PARSE_DUMP;
                        break;
                case 'd':
                        opts->parse_mask |= PARSE_DUMP;
                        break;
@@ -126,7 +131,7 @@ int main(int argc, char *argv[])
                return 1;
 
        if (opts.parse_mask & PARSE_DUMP)
                return 1;
 
        if (opts.parse_mask & PARSE_DUMP)
-               dump_process_maps(&process_list);
+               dump_process_maps(&pf, &process_list, &opts);
        else
                print_pid_stats(&pf, &process_list, &opts);
 
        else
                print_pid_stats(&pf, &process_list, &opts);
 
index 4bb1302d3bc7e563bb3ab24fb960e5600da5ecf6..43d34baa73a25f755642632c887c3f042d14f1c0 100644 (file)
--- a/pagemap.h
+++ b/pagemap.h
@@ -104,6 +104,7 @@ struct process {
 #define PARSE_MAP_NAME         0x2
 #define PARSE_DUMP             0x8
 #define PARSE_NOADD_TREE       0x10
 #define PARSE_MAP_NAME         0x2
 #define PARSE_DUMP             0x8
 #define PARSE_NOADD_TREE       0x10
+#define PARSE_SHARED_MAPPING   0x20
 
 struct pidlist {
        struct list_head list;
 
 struct pidlist {
        struct list_head list;