8 struct kpageflag_str kpageflag_str[] = {
9 { .flag = LOCKED, .str = "locked", },
10 { .flag = ERROR, .str = "error", },
11 { .flag = REFERENCED, .str = "referenced", },
12 { .flag = UPTODATE, .str = "uptodate", },
13 { .flag = DIRTY, .str = "dirty", },
14 { .flag = LRU, .str = "lru", },
15 { .flag = ACTIVE, .str = "active", },
16 { .flag = SLAB, .str = "slab", },
17 { .flag = WRITEBACK, .str = "writeback", },
18 { .flag = RECLAIM, .str = "reclaim", },
19 { .flag = BUDDY, .str = "buddy", },
20 { .flag = MMAP, .str = "mmap", },
21 { .flag = ANON, .str = "anon", },
22 { .flag = SWAPCACHE, .str = "swapcache", },
23 { .flag = SWAPBACKED, .str = "swapbacked", },
24 { .flag = COMPOUND_HEAD, .str = "compound_head", },
25 { .flag = COMPOUND_TAIL, .str = "compound_tail", },
26 { .flag = HUGE, .str = "huge", },
27 { .flag = UNEVICTABLE, .str = "unevictable", },
28 { .flag = HWPOISON, .str = "hwpoison", },
29 { .flag = NOPAGE, .str = "nopage", },
30 { .flag = KSM, .str = "ksm", },
34 #define SI_M (SI_k * SI_k)
35 #define SI_G (SI_M * SI_k)
37 #define PRETTY_THRESH 98
39 ((a) < SI_k * 4 ? (a) : \
40 (a < SI_M * PRETTY_THRESH ? ((a) / SI_k) : \
41 (a < SI_G * PRETTY_THRESH ? ((a) / SI_M) : \
44 #define NICE_UNIT(a) \
45 ((a) < (SI_k * 4) ? " " : \
46 ((a) < (SI_M * PRETTY_THRESH) ? "k" : \
47 ((a) < (SI_G * PRETTY_THRESH) ? "M" : "G")))
49 #define PAGE_TO_NICE(a) NICE_DIV((long long)a * PAGE_SIZE)
50 #define PAGE_TO_NICE_UNIT(a) NICE_UNIT((long long)a * PAGE_SIZE)
52 struct analyze_frames {
53 struct bintree_ops ops;
57 struct list_head *pidlist;
61 long int pages_present;
62 long int pages_swapped;
63 long int pages_unique;
66 #define bintree_ops_to_af(bintree_ops) \
67 container_of((bintree_ops), struct analyze_frames, ops)
69 static void count_pages(struct bintree *b, struct bintree_ops *ops)
71 struct pageframe *pf = tree_to_pageframe(b);
72 struct analyze_frames *af = bintree_ops_to_af(ops);
76 /* Find pages which reference at least once a pid */
77 list_for_each_entry(ml, &pf->ml, list) {
78 if (ml->map->pid == af->pid)
82 } else if (af->pidlist && af->map) {
84 * Find pages that reference at least once all of the
85 * given pids and a given mapping
91 * Check that we reference the given mapping at least
94 list_for_each_entry(ml, &pf->ml, list) {
95 if (ml->map == af->map) {
106 * Check that we reference all of the given pids
107 * too. The order of the loops is important here. We
108 * must scan through all the references and test for a
109 * given pid. If we would iterate through the
110 * references in the outer loop, we might get
111 * duplicate matches for a pid since it is possible
112 * that a page is mapped multiple times in a process's
115 list_for_each_entry(pid, af->pidlist, list) {
116 list_for_each_entry(ml, &pf->ml, list) {
117 if (ml->map->pid == pid->pid) {
124 * If we have found as many matches as ther
125 * are pids, we will count the stats
127 if (matches == af->pids)
134 if (page_present(pf))
136 else if (page_swapped(pf))
138 if (pf->kpagecount == 1)
143 * print_page_stats - Prints system wide page stats
145 void print_page_stats(struct pageframe *pf)
147 struct analyze_frames af;
149 memset(&af, 0, sizeof(af));
151 af.ops.callback = count_pages;
153 count = bintree_walk(&pf->tree, &af.ops);
154 printf(" present pages: %6ld, %5lld %sB\n"
155 " swapped pages: %6ld, %5lld %sB\n"
156 " unique pages: %6ld, %5lld %sB\n"
157 " total pages: %6ld, %5lld %sB\n",
159 PAGE_TO_NICE(af.pages_present),
160 PAGE_TO_NICE_UNIT(af.pages_present),
162 PAGE_TO_NICE(af.pages_swapped),
163 PAGE_TO_NICE_UNIT(af.pages_swapped),
165 PAGE_TO_NICE(af.pages_unique),
166 PAGE_TO_NICE_UNIT(af.pages_unique),
169 PAGE_TO_NICE_UNIT(count));
172 void print_pid_stats(struct pageframe *pf, struct process *process_list,
173 struct parse_opts *opts)
175 struct analyze_frames af;
177 long int swapped, present, total;
178 long int biggest = 0, second_biggest;
179 int count, processes = 0;
182 * walk through all processes, find the one with most present
185 list_for_each_entry(ps, &process_list->list, list) {
186 memset(&af, 0, sizeof(af));
187 af.ops.callback = count_pages;
190 bintree_walk(&pf->tree, &af.ops);
191 ps->pages_present = af.pages_present;
192 ps->pages_swapped = af.pages_swapped;
193 biggest = MAX(biggest, ps->pages_present + ps->pages_swapped);
196 printf(" in ram swapped total pid");
197 if (opts->with_threads)
204 list_for_each_entry(ps, &process_list->list, list) {
206 present = ps->pages_present;
207 swapped = ps->pages_swapped;
208 total = present + swapped;
210 second_biggest = (total < biggest) &&
211 (second_biggest < total) ?
212 total : second_biggest;
214 if (total != biggest)
220 printf("%5lld %sB %5lld %sB %5lld %sB %5d ",
221 PAGE_TO_NICE(present), PAGE_TO_NICE_UNIT(present),
222 PAGE_TO_NICE(swapped), PAGE_TO_NICE_UNIT(swapped),
223 PAGE_TO_NICE(total), PAGE_TO_NICE_UNIT(total),
226 if (opts->with_threads)
227 printf("%5d ", ps->tid);
230 ps->is_initial_pid ? '*' : ' ',
238 biggest = second_biggest;
242 printf("Total %d processes\n", processes);
245 static void _dump_process_maps(struct pageframe *pf, struct process *ps,
246 struct parse_opts *opts)
249 long int swapped, present, total;
250 long int biggest = 0, second_biggest;
251 int count, processes = 0, pids = 0;
253 if (is_parse_option(opts, PARSE_SHARED_MAPPING)) {
255 list_for_each_entry(pid, &opts->pidlist, list)
259 list_for_each_entry(map, &ps->maps->list, list) {
260 struct analyze_frames af;
262 if (is_parse_option(opts, PARSE_SHARED_MAPPING)) {
263 memset(&af, 0, sizeof(af));
264 af.ops.callback = count_pages;
265 af.pidlist = &opts->pidlist;
269 bintree_walk(&pf->tree, &af.ops);
270 map->pages_present = af.pages_present;
271 map->pages_swapped = af.pages_swapped;
274 biggest = MAX(biggest, map->pages_present + map->pages_swapped);
277 printf("process: [%d] %s\n", ps->pid, ps->name);
278 printf(" size in ram swapped total name\n");
282 list_for_each_entry(map, &ps->maps->list, list) {
284 present = map->pages_present;
285 swapped = map->pages_swapped;
286 total = present + swapped;
288 second_biggest = (total < biggest) &&
289 (second_biggest < total) ?
290 total : second_biggest;
292 if (total != biggest)
296 * Do not print zero sized mappings if
297 * --shared-mappings is enabled
299 if (is_parse_option(opts, PARSE_SHARED_MAPPING) && total == 0)
302 printf("%5lld %sB %5lld %sB %5lld %sB %5lld %sB %s\n",
303 NICE_DIV(map->size), NICE_UNIT(map->size),
304 PAGE_TO_NICE(present), PAGE_TO_NICE_UNIT(present),
305 PAGE_TO_NICE(swapped), PAGE_TO_NICE_UNIT(swapped),
306 PAGE_TO_NICE(total), PAGE_TO_NICE_UNIT(total),
313 if (count > 0 && biggest > 0) {
314 biggest = second_biggest;
320 void dump_process_maps(struct pageframe *pf, struct process *process_list,
321 struct parse_opts *opts)
325 list_for_each_entry(ps, &process_list->list, list) {
326 _dump_process_maps(pf, ps, opts);