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