2 * Copyright (C) 2010 Timo Kokkonen <timo.t.kokkonen@iki.fi>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 #include <sys/types.h>
29 static struct maps_list *alloc_maplist(void)
31 struct maps_list *map;
33 map = calloc(sizeof *map, 1);
37 INIT_LIST_HEAD(&map->list);
42 static struct maps *alloc_map(void)
46 map = calloc(sizeof(*map), 1);
50 INIT_LIST_HEAD(&map->list);
55 static struct maps *parse_maps(FILE *file, int pid, int tid)
57 struct maps *the_map = NULL;
61 while (fgets(line, sizeof(line), file)) {
62 struct maps *map = alloc_map();
63 unsigned long start, end;
72 ret = sscanf(line, "%lx-%lx %*s %*s %*s %*s %n",
76 printf("Error reading input: %s\n", line);
82 map->size = end - start;
86 strncpy(map->name, line + skip, sizeof(map->name) - 1);
88 /* zero out the newline */
89 map->name[MAX(strlen(map->name) - 1, 0)] = '\0';
91 list_add_tail(&map->list, &the_map->list);
97 static struct pageframe *alloc_pageframe(void)
99 struct pageframe *pageframe;
101 pageframe = malloc(sizeof *pageframe);
102 if (pageframe == NULL)
105 clear_pageframe(pageframe);
110 static int pid_is_match(int pidn, struct list_head *pidlist)
114 list_for_each_entry(pid, pidlist, list) {
115 if (pid->pid == pidn)
122 static int should_scan_process(struct parse_opts *opts, struct process *process)
126 if (is_parse_option(opts, PARSE_PID) &&
127 is_parse_option(opts, PARSE_MAP_NAME)) {
128 if (pid_is_match(process->pid, &opts->pidlist))
131 if (is_parse_option(opts, PARSE_PID)) {
132 if (pid_is_match(process->pid, &opts->pidlist))
136 if (is_parse_option(opts, PARSE_MAP_NAME))
140 if (is_parse_option(opts, PARSE_NOADD_TREE))
146 static int should_scan_mapping(struct parse_opts *opts, struct maps *map)
150 if (is_parse_option(opts, PARSE_MAP_NAME)) {
151 if (strstr(map->name, opts->name))
154 if (is_parse_option(opts, PARSE_NOADD_TREE))
162 static int should_add_to_tree(struct parse_opts *opts, struct pageframe *pf,
165 if (is_parse_option(opts, PARSE_NOADD_TREE))
171 /* Read data from the /proc/pid/pagemap file */
172 static int parse_pageframe(FILE *file, struct rb_root *root,
173 struct maps *maps, struct parse_opts *opts)
176 struct maps_list *tmp;
177 struct pageframe *match, *pageframe = NULL;
179 unsigned long long pf[10240];
185 /* Go through the list of allocated memory areas */
186 list_for_each_entry(map, &maps->list, list) {
187 start = map->start >> (PAGE_SHIFT - 3);
188 len = map->size >> (PAGE_SHIFT);
190 if (!should_scan_mapping(opts, map))
193 ret = fseek(file, start, SEEK_SET);
195 fprintf(stderr, "Error seeking to %lx: %m\n", start);
199 for (i = 0; i < len; i++) {
202 MIN(sizeof(pf), (len - i) * 8), file);
208 pageframe = alloc_pageframe();
209 ret -= sizeof(pf[0]);
211 /* ignore unused pages */
212 if (!pf[ret / sizeof(pf[0])])
215 pageframe->pf = (pf[ret / sizeof(pf[0])]);
217 /* ignore unused pages */
218 if (!(page_swapped(pageframe) ||
219 page_present(pageframe)))
222 if (should_add_to_tree(opts, pageframe, map))
223 match = pf_insert(root, pageframe);
225 match = pf_search(root, pageframe);
230 if (match == pageframe)
235 * Add a link from the physical page to this
238 tmp = alloc_maplist();
240 list_add(&tmp->list, &match->ml);
242 if (page_present(match))
243 map->pages_present++;
244 else if (page_swapped(match))
245 map->pages_swapped++;
252 static int read_pageframe(int pid, int tid, struct rb_root *root,
253 struct process *process_list, struct parse_opts *opts)
256 struct process *process;
257 struct pidlist *pidl, *n;
261 process = calloc(sizeof(*process), 1);
262 INIT_LIST_HEAD(&process->list);
267 if (!should_scan_process(opts, process))
270 snprintf(path, sizeof(path), "/proc/%d/task/%d/maps", pid, tid);
271 file = fopen(path, "rb");
276 maps = parse_maps(file, pid, tid);
278 process->maps = maps;
280 snprintf(path, sizeof(path), "/proc/%d/task/%d/pagemap", pid, tid);
281 file = fopen(path, "rb");
286 parse_pageframe(file, root, maps, opts);
289 if (read_cmdline(pid, tid, process->name, sizeof(process->name)))
292 if (!is_parse_option(opts, PARSE_NOADD_TREE))
293 process->is_initial_pid = 1;
295 list_add_tail(&process->list, &process_list->list);
302 * Remove the pid from the list. It is no longer an
303 * interesting pid, since we can't access its data
305 list_for_each_entry_safe(pidl, n, &opts->pidlist, list) {
306 if (pidl->pid == pid) {
307 list_del(&pidl->list);
316 static int read_pageframe_with_threads(int pid,
317 struct rb_root *root,
318 struct process *process_list,
319 struct parse_opts *opts)
326 if (opts->with_threads)
327 tid = get_next_tid(pid, &dir);
334 count += read_pageframe(pid, tid, root, process_list, opts);
336 if (!opts->with_threads)
343 int scan_all_pids(struct rb_root *root, struct process *process_list,
344 struct parse_opts *opts)
346 struct pidlist *pidlist, *n;
352 if (is_parse_option(opts, PARSE_PID)) {
353 list_for_each_entry_safe(pidlist, n, &opts->pidlist, list) {
354 count += read_pageframe_with_threads(pidlist->pid, root,
359 if ((count == 0) && !(is_parse_option(opts, PARSE_MAP_NAME))) {
360 printf("Failed to find any matching processes "
361 "with given arguments\n");
365 if (is_parse_option(opts, PARSE_DUMP))
368 if (is_parse_option(opts, PARSE_MAP_NAME) &&
369 !is_parse_option(opts, PARSE_PID)) {
370 printf("Scanning page mappings for process: ");
372 pid = get_next_pid(&dir);
376 for (i = 0; i < len; i++)
378 len = printf("% 5d", pid);
381 read_pageframe_with_threads(pid, root, process_list,
385 for (i = 0; i < len; i++)
390 /* Do not add new pages in the tree after the initial scan */
391 opts->parse_mask |= PARSE_NOADD_TREE;
393 printf("Scanning page mappings for process: ");
395 pid = get_next_pid(&dir);
399 for (i = 0; i < len; i++)
401 len = printf("% 5d", pid);
404 read_pageframe_with_threads(pid, root, process_list, opts);
406 for (i = 0; i < len; i++)
413 int update_kpageflags(struct rb_root *root)
415 struct pageframe *pf;
420 kpageflags_fd = open("/proc/kpageflags", O_RDONLY);
421 if (kpageflags_fd < 0)
424 kpagecount_fd = open("/proc/kpagecount", O_RDONLY);
425 if (kpagecount_fd < 0)
428 pf = rb_to_pageframe(rb_first(root));
431 long int pfnn = pfn(pf) * sizeof(pf->kpageflags);
433 ret = lseek(kpageflags_fd, pfnn, SEEK_SET);
435 fprintf(stderr, "Error seeking to %lx: %m\n", pfnn);
439 ret = read(kpageflags_fd, &pf->kpageflags,
440 sizeof(pf->kpageflags));
442 fprintf(stderr, "Error reading from %llx: %m\n",
443 pf->pf * sizeof(pf->kpageflags));
447 ret = lseek(kpagecount_fd, pfnn, SEEK_SET);
449 fprintf(stderr, "Error seeking to %lx: %m\n", pfnn);
453 ret = read(kpagecount_fd, &pf->kpagecount,
454 sizeof(pf->kpagecount));
456 fprintf(stderr, "Error reading from %llx: %m\n",
457 pf->pf * sizeof(pf->kpagecount));
461 pf = rb_to_pageframe(rb_next(&pf->tree));
464 close(kpageflags_fd);
465 close(kpagecount_fd);