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 97
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 /* General counters */
62 long int pages_present;
63 long int pages_swapped;
64 long int pages_unique;
66 /* kpageflag stats counters */
67 long int kpageflag[KPAGEFLAGS_NUM];
70 #define bintree_ops_to_af(bintree_ops) \
71 container_of((bintree_ops), struct analyze_frames, ops)
73 static void count_pages(struct bintree *b, struct bintree_ops *ops)
75 struct pageframe *pf = tree_to_pageframe(b);
76 struct analyze_frames *af = bintree_ops_to_af(ops);
81 /* Find pages which reference at least once a pid */
82 list_for_each_entry(ml, &pf->ml, list) {
83 if (ml->map->pid == af->pid)
87 } else if (af->pidlist && af->map) {
89 * Find pages that reference at least once all of the
90 * given pids and a given mapping
96 * Check that we reference the given mapping at least
99 list_for_each_entry(ml, &pf->ml, list) {
100 if (ml->map == af->map) {
111 * Check that we reference all of the given pids
112 * too. The order of the loops is important here. We
113 * must scan through all the references and test for a
114 * given pid. If we would iterate through the
115 * references in the outer loop, we might get
116 * duplicate matches for a pid since it is possible
117 * that a page is mapped multiple times in a process's
120 list_for_each_entry(pid, af->pidlist, list) {
121 list_for_each_entry(ml, &pf->ml, list) {
122 if (ml->map->pid == pid->pid) {
129 * If we have found as many matches as ther
130 * are pids, we will count the stats
132 if (matches == af->pids)
139 if (page_present(pf))
141 else if (page_swapped(pf))
143 if (pf->kpagecount == 1)
146 for (i = 0; i < KPAGEFLAGS_NUM; i++)
147 if (kpageflag_is_set(pf, i))
152 * print_page_stats - Prints system wide page stats
154 void print_page_stats(struct pageframe *pf)
156 struct analyze_frames af;
159 memset(&af, 0, sizeof(af));
161 af.ops.callback = count_pages;
163 count = bintree_walk(&pf->tree, &af.ops);
165 for (i = 0; i < KPAGEFLAGS_NUM; i++) {
166 if (!af.kpageflag[i])
169 printf("%13s pages: %6ld, %5lld %sB\n",
172 PAGE_TO_NICE(af.kpageflag[i]),
173 PAGE_TO_NICE_UNIT(af.kpageflag[i]));
176 printf(" present pages: %6ld, %5lld %sB\n"
177 " swapped pages: %6ld, %5lld %sB\n"
178 " unique pages: %6ld, %5lld %sB\n"
179 " total pages: %6ld, %5lld %sB\n",
181 PAGE_TO_NICE(af.pages_present),
182 PAGE_TO_NICE_UNIT(af.pages_present),
184 PAGE_TO_NICE(af.pages_swapped),
185 PAGE_TO_NICE_UNIT(af.pages_swapped),
187 PAGE_TO_NICE(af.pages_unique),
188 PAGE_TO_NICE_UNIT(af.pages_unique),
191 PAGE_TO_NICE_UNIT(count));
194 void print_pid_stats(struct pageframe *pf, struct process *process_list,
195 struct parse_opts *opts)
197 struct analyze_frames af;
199 long int swapped, present, unique, total;
200 long int biggest = 0, second_biggest;
201 int count, processes = 0;
204 * walk through all processes, find the one with most present
207 list_for_each_entry(ps, &process_list->list, list) {
208 memset(&af, 0, sizeof(af));
209 af.ops.callback = count_pages;
212 bintree_walk(&pf->tree, &af.ops);
213 ps->pages_present = af.pages_present;
214 ps->pages_swapped = af.pages_swapped;
215 ps->pages_unique = af.pages_unique;
216 biggest = MAX(biggest, ps->pages_present + ps->pages_swapped);
219 printf(" RSS swapped USS total pid");
220 if (opts->with_threads)
227 list_for_each_entry(ps, &process_list->list, list) {
229 present = ps->pages_present;
230 swapped = ps->pages_swapped;
231 unique = ps->pages_unique;
232 total = present + swapped;
234 second_biggest = (total < biggest) &&
235 (second_biggest < total) ?
236 total : second_biggest;
238 if (total != biggest)
244 printf("%5lld %sB %5lld %sB %5lld %sB %5lld %sB %5d ",
245 PAGE_TO_NICE(present), PAGE_TO_NICE_UNIT(present),
246 PAGE_TO_NICE(swapped), PAGE_TO_NICE_UNIT(swapped),
247 PAGE_TO_NICE(unique), PAGE_TO_NICE_UNIT(unique),
248 PAGE_TO_NICE(total), PAGE_TO_NICE_UNIT(total),
251 if (opts->with_threads)
252 printf("%5d ", ps->tid);
255 ps->is_initial_pid ? '*' : ' ',
263 biggest = second_biggest;
267 printf("Total %d processes\n", processes);
270 static void _dump_process_maps(struct pageframe *pf, struct process *ps,
271 struct parse_opts *opts)
274 long int swapped, present, total;
275 long int biggest = 0, second_biggest;
276 int count, processes = 0, pids = 0;
278 if (is_parse_option(opts, PARSE_SHARED_MAPPING)) {
280 list_for_each_entry(pid, &opts->pidlist, list)
284 list_for_each_entry(map, &ps->maps->list, list) {
285 struct analyze_frames af;
287 if (is_parse_option(opts, PARSE_SHARED_MAPPING)) {
288 memset(&af, 0, sizeof(af));
289 af.ops.callback = count_pages;
290 af.pidlist = &opts->pidlist;
294 bintree_walk(&pf->tree, &af.ops);
295 map->pages_present = af.pages_present;
296 map->pages_swapped = af.pages_swapped;
299 biggest = MAX(biggest, map->pages_present + map->pages_swapped);
302 printf("process: [%d] %s\n", ps->pid, ps->name);
303 printf(" size RSS swapped total name\n");
307 list_for_each_entry(map, &ps->maps->list, list) {
309 present = map->pages_present;
310 swapped = map->pages_swapped;
311 total = present + swapped;
313 second_biggest = (total < biggest) &&
314 (second_biggest < total) ?
315 total : second_biggest;
317 if (total != biggest)
321 * Do not print zero sized mappings if
322 * --shared-mappings is enabled
324 if (is_parse_option(opts, PARSE_SHARED_MAPPING) && total == 0)
327 printf("%5lld %sB %5lld %sB %5lld %sB %5lld %sB %s\n",
328 NICE_DIV(map->size), NICE_UNIT(map->size),
329 PAGE_TO_NICE(present), PAGE_TO_NICE_UNIT(present),
330 PAGE_TO_NICE(swapped), PAGE_TO_NICE_UNIT(swapped),
331 PAGE_TO_NICE(total), PAGE_TO_NICE_UNIT(total),
338 if (count > 0 && biggest > 0) {
339 biggest = second_biggest;
345 void dump_process_maps(struct pageframe *pf, struct process *process_list,
346 struct parse_opts *opts)
350 list_for_each_entry(ps, &process_list->list, list) {
351 _dump_process_maps(pf, ps, opts);