]> git.itanic.dy.fi Git - scan-pagemap/blob - analyze.c
analyzer: Avoid ignoring mappings with only one reference
[scan-pagemap] / analyze.c
1 #include <string.h>
2 #include <stdio.h>
3
4 #include "analyze.h"
5 #include "utils.h"
6 #include "bintree.h"
7
8 #define SI_k    1024ll
9 #define SI_M    (SI_k * SI_k)
10 #define SI_G    (SI_M * SI_k)
11
12 #define PRETTY_THRESH   100
13 #define NICE_DIV(a)                                                     \
14         ((a) < SI_k * PRETTY_THRESH ? (a) :                             \
15                 (a < SI_M * PRETTY_THRESH ? ((a) / SI_k) :              \
16                         (a < SI_G * PRETTY_THRESH ? ((a) / SI_M) :      \
17                                 ((a) / SI_G))))
18
19 #define NICE_UNIT(a)                                                    \
20         ((a) < (SI_k * PRETTY_THRESH) ? " " :                           \
21                 ((a) < (SI_M * PRETTY_THRESH) ? "k" :                   \
22                         ((a) < (SI_G * PRETTY_THRESH) ? "M" : "G")))
23
24 #define PAGE_TO_NICE(a)         NICE_DIV((long long)a * PAGE_SIZE)
25 #define PAGE_TO_NICE_UNIT(a)    NICE_UNIT((long long)a * PAGE_SIZE)
26
27 struct analyze_frames {
28         struct bintree_ops ops;
29         long int pages_present;
30         long int pages_swapped;
31         long int pages_unused;
32         int pid;
33 };
34
35 #define bintree_ops_to_af(bintree_ops)                          \
36         container_of((bintree_ops), struct analyze_frames, ops)
37
38 static void count_pages(struct bintree *b, struct bintree_ops *ops)
39 {
40         struct pageframe *pf = tree_to_pageframe(b);
41         struct analyze_frames *af = bintree_ops_to_af(ops);
42         struct maps_list *ml;
43
44         if (af->pid) {
45                 if (!pf->ml)
46                         return;
47                 if (list_empty(&pf->ml->list)) {
48                         ml = list_to_maps_list(&pf->ml->list);
49                         if (ml->map->pid == af->pid)
50                                 goto get_stats;
51                 }
52                 list_for_each_entry(ml, &pf->ml->list, list) {
53                         if (ml->map->pid == af->pid)
54                                 goto get_stats;
55                 }
56                 return;
57         }
58
59 get_stats:
60         if (pf->page_present) {
61                 af->pages_present++;
62         } else if (pf->page_swapped) {
63                 af->pages_swapped++;
64         } else {
65                 af->pages_unused++;
66         }
67 }
68
69 /*
70  * print_page_stats - Prints system wide page stats
71  */
72 void print_page_stats(struct pageframe *pf)
73 {
74         struct analyze_frames af;
75         long count;
76         memset(&af, 0, sizeof(af));
77
78         af.ops.callback = count_pages;
79
80         count = bintree_walk(&pf->tree, &af.ops);
81         printf("present pages: %ld, %lld %sB\n"
82                 "Swapped pages: %ld, %lld %sB\n"
83                 "Unused pages: %ld, %lld %sB\n"
84                 "Total %ld physical pages, %lld %sB\n",
85                 af.pages_present,
86                 PAGE_TO_NICE(af.pages_present),
87                 PAGE_TO_NICE_UNIT(af.pages_present),
88                 af.pages_swapped,
89                 PAGE_TO_NICE(af.pages_swapped),
90                 PAGE_TO_NICE_UNIT(af.pages_swapped),
91                 af.pages_unused,
92                 PAGE_TO_NICE(af.pages_unused),
93                 PAGE_TO_NICE_UNIT(af.pages_unused),
94                 count,
95                 PAGE_TO_NICE(count),
96                 PAGE_TO_NICE_UNIT(count));
97 }
98
99 void print_pid_stats(struct pageframe *pf, struct process *process_list,
100                 struct parse_opts *opts)
101 {
102         struct analyze_frames af;
103         struct process *ps;
104         long int swapped, present, total;
105         long int biggest = 0, second_biggest;
106         int count, processes = 0;
107
108         /*
109          * walk through all processes, find the one with most present
110          * pages
111          */
112         list_for_each_entry(ps, &process_list->list, list) {
113                 memset(&af, 0, sizeof(af));
114                 af.ops.callback = count_pages;
115                 af.pid = ps->pid;
116
117                 bintree_walk(&pf->tree, &af.ops);
118                 ps->pages_present = af.pages_present;
119                 ps->pages_swapped = af.pages_swapped;
120                 biggest = MAX(biggest, ps->pages_present + ps->pages_swapped);
121         }
122
123         printf("   in ram   swapped   pid");
124         if (opts->with_threads)
125                 printf("   tid");
126         printf(" name\n");
127
128 restart:
129         second_biggest = 0;
130         count = 0;
131         list_for_each_entry(ps, &process_list->list, list) {
132
133                 present = ps->pages_present;
134                 swapped = ps->pages_swapped;
135                 total = present + swapped;
136
137                 second_biggest = (total < biggest) &&
138                         (second_biggest < total) ?
139                         total : second_biggest;
140
141                 if (total != biggest)
142                         continue;
143
144                 if (total == 0)
145                         continue;
146
147                 printf("%6lld %sB %6lld %sB %5d ",
148                         PAGE_TO_NICE(present), PAGE_TO_NICE_UNIT(present),
149                         PAGE_TO_NICE(swapped), PAGE_TO_NICE_UNIT(swapped),
150                         ps->pid);
151
152                 if (opts->with_threads)
153                         printf("%5d ", ps->tid);
154
155                 printf("%s\n", ps->name);
156
157                 count++;
158                 processes++;
159         }
160
161         if (count > 0) {
162                 biggest = second_biggest;
163                 goto restart;
164         }
165
166         printf("Total %d processes\n", processes);
167 }