#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) \
{
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++;
}
/*
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);
+ }
}