]> git.itanic.dy.fi Git - scan-pagemap/blobdiff - analyze.c
Correct the usage of linked lists
[scan-pagemap] / analyze.c
index 0cc630bfdf84f79a7b35526980275537f1c82605..18e95c49fba977f26928d20f13b155be082abd7c 100644 (file)
--- a/analyze.c
+++ b/analyze.c
@@ -5,11 +5,30 @@
 #include "utils.h"
 #include "bintree.h"
 
+#define SI_k   1024ll
+#define SI_M   (SI_k * SI_k)
+#define SI_G   (SI_M * SI_k)
+
+#define PRETTY_THRESH  100
+#define NICE_DIV(a)                                                    \
+       ((a) < SI_k * PRETTY_THRESH ? (a) :                             \
+               (a < SI_M * PRETTY_THRESH ? ((a) / SI_k) :              \
+                       (a < SI_G * PRETTY_THRESH ? ((a) / SI_M) :      \
+                               ((a) / SI_G))))
+
+#define NICE_UNIT(a)                                                   \
+       ((a) < (SI_k * PRETTY_THRESH) ? " " :                           \
+               ((a) < (SI_M * PRETTY_THRESH) ? "k" :                   \
+                       ((a) < (SI_G * PRETTY_THRESH) ? "M" : "G")))
+
+#define PAGE_TO_NICE(a)                NICE_DIV((long long)a * PAGE_SIZE)
+#define PAGE_TO_NICE_UNIT(a)   NICE_UNIT((long long)a * PAGE_SIZE)
+
 struct analyze_frames {
        struct bintree_ops ops;
-       long int present_pages;
-       long int swapped_pages;
-       long int unused_pages;
+       long int pages_present;
+       long int pages_swapped;
+       int pid;
 };
 
 #define bintree_ops_to_af(bintree_ops)                         \
@@ -19,14 +38,24 @@ static void count_pages(struct bintree *b, struct bintree_ops *ops)
 {
        struct pageframe *pf = tree_to_pageframe(b);
        struct analyze_frames *af = bintree_ops_to_af(ops);
+       struct maps_list *ml;
 
-       if (pf->page_present) {
-               af->present_pages += pf->refcount;
-       } else if (pf->page_swapped) {
-               af->swapped_pages += pf->refcount;
-       } else {
-               af->unused_pages += pf->refcount;
+       if (af->pid) {
+               if (list_empty(&pf->ml.list)) {
+                       return;
+               }
+               list_for_each_entry(ml, &pf->ml.list, list) {
+                       if (ml->map->pid == af->pid)
+                               goto get_stats;
+               }
+               return;
        }
+
+get_stats:
+       if (pf->page_present)
+               af->pages_present++;
+       else if (pf->page_swapped)
+               af->pages_swapped++;
 }
 
 /*
@@ -35,18 +64,152 @@ static void count_pages(struct bintree *b, struct bintree_ops *ops)
 void print_page_stats(struct pageframe *pf)
 {
        struct analyze_frames af;
-       int count;
+       long count;
        memset(&af, 0, sizeof(af));
 
        af.ops.callback = count_pages;
 
        count = bintree_walk(&pf->tree, &af.ops);
-       printf("present pages: %ld\n"
-               "Swapped pages: %ld\n"
-               "Unused pages: %ld\n"
-               "Total %d physical pages\n",
-               af.present_pages,
-               af.swapped_pages,
-               af.unused_pages,
-               count);
+       printf("present pages: %ld, %lld %sB\n"
+               "Swapped pages: %ld, %lld %sB\n"
+               "Total %ld physical pages, %lld %sB\n",
+               af.pages_present,
+               PAGE_TO_NICE(af.pages_present),
+               PAGE_TO_NICE_UNIT(af.pages_present),
+               af.pages_swapped,
+               PAGE_TO_NICE(af.pages_swapped),
+               PAGE_TO_NICE_UNIT(af.pages_swapped),
+               count,
+               PAGE_TO_NICE(count),
+               PAGE_TO_NICE_UNIT(count));
+}
+
+void print_pid_stats(struct pageframe *pf, struct process *process_list,
+               struct parse_opts *opts)
+{
+       struct analyze_frames af;
+       struct process *ps;
+       long int swapped, present, total;
+       long int biggest = 0, second_biggest;
+       int count, processes = 0;
+
+       /*
+        * walk through all processes, find the one with most present
+        * pages
+        */
+       list_for_each_entry(ps, &process_list->list, list) {
+               memset(&af, 0, sizeof(af));
+               af.ops.callback = count_pages;
+               af.pid = ps->pid;
+
+               bintree_walk(&pf->tree, &af.ops);
+               ps->pages_present = af.pages_present;
+               ps->pages_swapped = af.pages_swapped;
+               biggest = MAX(biggest, ps->pages_present + ps->pages_swapped);
+       }
+
+       printf("  in ram  swapped    total   pid");
+       if (opts->with_threads)
+               printf("   tid");
+       printf(" name\n");
+
+restart:
+       second_biggest = 0;
+       count = 0;
+       list_for_each_entry(ps, &process_list->list, list) {
+
+               present = ps->pages_present;
+               swapped = ps->pages_swapped;
+               total = present + swapped;
+
+               second_biggest = (total < biggest) &&
+                       (second_biggest < total) ?
+                       total : second_biggest;
+
+               if (total != biggest)
+                       continue;
+
+               if (total == 0)
+                       continue;
+
+               printf("%5lld %sB %5lld %sB %5lld %sB %5d ",
+                       PAGE_TO_NICE(present), PAGE_TO_NICE_UNIT(present),
+                       PAGE_TO_NICE(swapped), PAGE_TO_NICE_UNIT(swapped),
+                       PAGE_TO_NICE(total), PAGE_TO_NICE_UNIT(total),
+                       ps->pid);
+
+               if (opts->with_threads)
+                       printf("%5d ", ps->tid);
+
+               printf("%s\n", ps->name);
+
+               count++;
+               processes++;
+       }
+
+       if (count > 0) {
+               biggest = second_biggest;
+               goto restart;
+       }
+
+       printf("Total %d processes\n", processes);
+}
+
+static void _dump_process_maps(struct process *ps)
+{
+       struct maps *map;
+       long int swapped, present, total;
+       long int biggest = 0, second_biggest;
+       int count, processes = 0;
+
+       list_for_each_entry(map, &ps->maps->list, list) {
+               biggest = MAX(biggest, map->pages_present + map->pages_swapped);
+       }
+
+       printf("process: [%d] %s\n", ps->pid, ps->name);
+       printf("    size   in ram  swapped    total name\n");
+restart:
+       second_biggest = 0;
+       count = 0;
+       list_for_each_entry(map, &ps->maps->list, list) {
+
+               present = map->pages_present;
+               swapped = map->pages_swapped;
+               total = present + swapped;
+
+               second_biggest = (total < biggest) &&
+                       (second_biggest < total) ?
+                       total : second_biggest;
+
+               if (total != biggest)
+                       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),
+                       PAGE_TO_NICE(swapped), PAGE_TO_NICE_UNIT(swapped),
+                       PAGE_TO_NICE(total), PAGE_TO_NICE_UNIT(total),
+                       map->name);
+
+               count++;
+               processes++;
+       }
+
+       if (count > 0 && biggest > 0) {
+               biggest = second_biggest;
+               goto restart;
+       }
+       printf("\n");
+}
+
+void dump_process_maps(struct process *process_list)
+{
+       struct process *ps;
+
+       if (list_empty(&process_list->list))
+               _dump_process_maps(process_list);
+
+       list_for_each_entry(ps, &process_list->list, list) {
+               _dump_process_maps(ps);
+       }
 }