#include #include #include "analyze.h" #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 pages_present; long int pages_swapped; int pid; }; #define bintree_ops_to_af(bintree_ops) \ container_of((bintree_ops), struct analyze_frames, ops) 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 (af->pid) { if (!pf->ml) return; if (list_empty(&pf->ml->list)) { ml = list_to_maps_list(&pf->ml->list); if (ml->map->pid == af->pid) goto get_stats; } 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++; } /* * print_page_stats - Prints system wide page stats */ void print_page_stats(struct pageframe *pf) { struct analyze_frames af; long count; memset(&af, 0, sizeof(af)); af.ops.callback = count_pages; count = bintree_walk(&pf->tree, &af.ops); 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("%6lld %sB %6lld %sB %6lld %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); }