#define SI_M (SI_k * SI_k)
#define SI_G (SI_M * SI_k)
-#define PRETTY_THRESH 100
+#define PRETTY_THRESH 98
#define NICE_DIV(a) \
- ((a) < SI_k * PRETTY_THRESH ? (a) : \
+ ((a) < SI_k * 4 ? (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_G * PRETTY_THRESH) ? "k" : \
+ ((a) < (SI_k * 4) ? " " : \
+ ((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)
struct analyze_frames {
struct bintree_ops ops;
- long int present_pages;
- long int swapped_pages;
- long int unused_pages;
+
+ int pid;
+
+ struct list_head *pidlist;
+ struct maps *map;
+ int pids;
+
+ long int pages_present;
+ long int pages_swapped;
+ long int pages_unique;
};
#define bintree_ops_to_af(bintree_ops) \
{
struct pageframe *pf = tree_to_pageframe(b);
struct analyze_frames *af = bintree_ops_to_af(ops);
+ 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;
+ } 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;
- 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;
+ /*
+ * 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:
+ if (page_present(pf))
+ af->pages_present++;
+ else if (page_swapped(pf))
+ af->pages_swapped++;
+ if (pf->refcount == 1)
+ af->pages_unique++;
}
/*
count = bintree_walk(&pf->tree, &af.ops);
printf("present pages: %ld, %lld %sB\n"
"Swapped pages: %ld, %lld %sB\n"
- "Unused pages: %ld, %lld %sB\n"
+ "Unique pages: %ld, %lld %sB\n"
"Total %ld physical pages, %lld %sB\n",
- af.present_pages,
- PAGE_TO_NICE(af.present_pages),
- PAGE_TO_NICE_UNIT(af.present_pages),
- af.swapped_pages,
- PAGE_TO_NICE(af.swapped_pages),
- PAGE_TO_NICE_UNIT(af.swapped_pages),
- af.unused_pages,
- PAGE_TO_NICE(af.unused_pages),
- PAGE_TO_NICE_UNIT(af.unused_pages),
+ 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),
+ af.pages_unique,
+ PAGE_TO_NICE(af.pages_unique),
+ PAGE_TO_NICE_UNIT(af.pages_unique),
count,
PAGE_TO_NICE(count),
PAGE_TO_NICE_UNIT(count));
}
-void print_pid_stats(struct pageframe *pf, struct process *process_list)
+void print_pid_stats(struct pageframe *pf, struct process *process_list,
+ struct parse_opts *opts)
{
+ struct analyze_frames af;
struct process *ps;
- struct maps *map;
- long int swapped, present;
+ 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;
- printf(" in ram swapped pid name\n");
+ 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) {
- swapped = present = 0;
- if (ps->maps)
- list_for_each_entry(map, &ps->maps->list, list) {
- present += map->pages_present;
- swapped += map->pages_swapped;
- }
+ present = ps->pages_present;
+ swapped = ps->pages_swapped;
+ total = present + swapped;
+
+ second_biggest = (total < biggest) &&
+ (second_biggest < total) ?
+ total : second_biggest;
- if ((swapped + present) == 0)
+ if (total != biggest)
continue;
- printf("% 6lld %sB % 6lld %sB % 5d %s\n",
+ 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),
- ps->pid, ps->name);
+ PAGE_TO_NICE(total), PAGE_TO_NICE_UNIT(total),
+ ps->pid);
+
+ if (opts->with_threads)
+ printf("%5d ", ps->tid);
+
+ printf("%c %s\n",
+ ps->is_initial_pid ? '*' : ' ',
+ ps->name);
+
+ count++;
+ processes++;
+ }
+
+ if (count > 0) {
+ biggest = second_biggest;
+ goto restart;
+ }
+
+ printf("Total %d processes\n", processes);
+}
+
+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;
+ 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) {
+ 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);
+ }
+
+ 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;
+
+ /*
+ * 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),
+ 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 pageframe *pf, struct process *process_list,
+ struct parse_opts *opts)
+{
+ struct process *ps;
+
+ list_for_each_entry(ps, &process_list->list, list) {
+ _dump_process_maps(pf, ps, opts);
}
}