]> git.itanic.dy.fi Git - scan-pagemap/blob - analyze.c
bb0679f3a1c1e27c7fd650602372dbc8dafad355
[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_unique;
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 (list_empty(&pf->ml.list)) {
46                         return;
47                 }
48                 list_for_each_entry(ml, &pf->ml.list, list) {
49                         if (ml->map->pid == af->pid)
50                                 goto get_stats;
51                 }
52                 return;
53         }
54
55 get_stats:
56         if (pf->page_present)
57                 af->pages_present++;
58         else if (pf->page_swapped)
59                 af->pages_swapped++;
60         if (pf->refcount == 1)
61                 af->pages_unique++;
62 }
63
64 /*
65  * print_page_stats - Prints system wide page stats
66  */
67 void print_page_stats(struct pageframe *pf)
68 {
69         struct analyze_frames af;
70         long count;
71         memset(&af, 0, sizeof(af));
72
73         af.ops.callback = count_pages;
74
75         count = bintree_walk(&pf->tree, &af.ops);
76         printf("present pages: %ld, %lld %sB\n"
77                 "Swapped pages: %ld, %lld %sB\n"
78                 "Unique pages: %ld, %lld %sB\n"
79                 "Total %ld physical pages, %lld %sB\n",
80                 af.pages_present,
81                 PAGE_TO_NICE(af.pages_present),
82                 PAGE_TO_NICE_UNIT(af.pages_present),
83                 af.pages_swapped,
84                 PAGE_TO_NICE(af.pages_swapped),
85                 PAGE_TO_NICE_UNIT(af.pages_swapped),
86                 af.pages_unique,
87                 PAGE_TO_NICE(af.pages_unique),
88                 PAGE_TO_NICE_UNIT(af.pages_unique),
89                 count,
90                 PAGE_TO_NICE(count),
91                 PAGE_TO_NICE_UNIT(count));
92 }
93
94 void print_pid_stats(struct pageframe *pf, struct process *process_list,
95                 struct parse_opts *opts)
96 {
97         struct analyze_frames af;
98         struct process *ps;
99         long int swapped, present, total;
100         long int biggest = 0, second_biggest;
101         int count, processes = 0;
102
103         /*
104          * walk through all processes, find the one with most present
105          * pages
106          */
107         list_for_each_entry(ps, &process_list->list, list) {
108                 memset(&af, 0, sizeof(af));
109                 af.ops.callback = count_pages;
110                 af.pid = ps->pid;
111
112                 bintree_walk(&pf->tree, &af.ops);
113                 ps->pages_present = af.pages_present;
114                 ps->pages_swapped = af.pages_swapped;
115                 biggest = MAX(biggest, ps->pages_present + ps->pages_swapped);
116         }
117
118         printf("  in ram  swapped    total   pid");
119         if (opts->with_threads)
120                 printf("   tid");
121         printf(" name\n");
122
123 restart:
124         second_biggest = 0;
125         count = 0;
126         list_for_each_entry(ps, &process_list->list, list) {
127
128                 present = ps->pages_present;
129                 swapped = ps->pages_swapped;
130                 total = present + swapped;
131
132                 second_biggest = (total < biggest) &&
133                         (second_biggest < total) ?
134                         total : second_biggest;
135
136                 if (total != biggest)
137                         continue;
138
139                 if (total == 0)
140                         continue;
141
142                 printf("%5lld %sB %5lld %sB %5lld %sB %5d ",
143                         PAGE_TO_NICE(present), PAGE_TO_NICE_UNIT(present),
144                         PAGE_TO_NICE(swapped), PAGE_TO_NICE_UNIT(swapped),
145                         PAGE_TO_NICE(total), PAGE_TO_NICE_UNIT(total),
146                         ps->pid);
147
148                 if (opts->with_threads)
149                         printf("%5d ", ps->tid);
150
151                 printf("%s\n", ps->name);
152
153                 count++;
154                 processes++;
155         }
156
157         if (count > 0) {
158                 biggest = second_biggest;
159                 goto restart;
160         }
161
162         printf("Total %d processes\n", processes);
163 }
164
165 static void _dump_process_maps(struct process *ps)
166 {
167         struct maps *map;
168         long int swapped, present, total;
169         long int biggest = 0, second_biggest;
170         int count, processes = 0;
171
172         list_for_each_entry(map, &ps->maps->list, list) {
173                 biggest = MAX(biggest, map->pages_present + map->pages_swapped);
174         }
175
176         printf("process: [%d] %s\n", ps->pid, ps->name);
177         printf("    size   in ram  swapped    total name\n");
178 restart:
179         second_biggest = 0;
180         count = 0;
181         list_for_each_entry(map, &ps->maps->list, list) {
182
183                 present = map->pages_present;
184                 swapped = map->pages_swapped;
185                 total = present + swapped;
186
187                 second_biggest = (total < biggest) &&
188                         (second_biggest < total) ?
189                         total : second_biggest;
190
191                 if (total != biggest)
192                         continue;
193
194                 printf("%5lld %sB %5lld %sB %5lld %sB %5lld %sB %s\n",
195                         NICE_DIV(map->size), NICE_UNIT(map->size),
196                         PAGE_TO_NICE(present), PAGE_TO_NICE_UNIT(present),
197                         PAGE_TO_NICE(swapped), PAGE_TO_NICE_UNIT(swapped),
198                         PAGE_TO_NICE(total), PAGE_TO_NICE_UNIT(total),
199                         map->name);
200
201                 count++;
202                 processes++;
203         }
204
205         if (count > 0 && biggest > 0) {
206                 biggest = second_biggest;
207                 goto restart;
208         }
209         printf("\n");
210 }
211
212 void dump_process_maps(struct process *process_list)
213 {
214         struct process *ps;
215
216         if (list_empty(&process_list->list))
217                 _dump_process_maps(process_list);
218
219         list_for_each_entry(ps, &process_list->list, list) {
220                 _dump_process_maps(ps);
221         }
222 }