14 static struct maps_list *alloc_maplist(void)
16 struct maps_list *map;
18 map = malloc(sizeof *map);
22 memset(map, 0, sizeof(*map));
23 INIT_LIST_HEAD(&map->list);
28 static struct maps *alloc_map(void)
32 map = malloc(sizeof *map);
36 memset(map, 0, sizeof(*map));
37 INIT_LIST_HEAD(&map->list);
42 static struct maps *parse_maps(FILE *file, int pid, int tid)
44 struct maps *the_map = NULL;
48 while (fgets(line, sizeof(line), file)) {
49 struct maps *map = alloc_map();
50 unsigned long start, end;
59 ret = sscanf(line, "%lx-%lx %*s %*s %*s %*s %s",
63 printf("Error reading input: %s\n", line);
69 map->size = end - start;
74 strncpy(map->name, name, sizeof(map->name));
76 list_add_tail(&map->list, &the_map->list);
82 static struct pageframe *alloc_pageframe(void)
84 struct pageframe *pageframe;
86 pageframe = malloc(sizeof *pageframe);
87 if (pageframe == NULL)
90 clear_pageframe(pageframe);
95 static int compare_pageframe(struct bintree *at, struct bintree *bt)
97 struct pageframe *a, *b;
98 a = tree_to_pageframe(at);
99 b = tree_to_pageframe(bt);
101 return a->pf - b->pf;
104 struct bintree_ops pageframe_ops = {
105 .compare = compare_pageframe,
108 static int pid_is_match(int pidn, struct list_head *pidlist)
112 list_for_each_entry(pid, pidlist, list) {
113 if (pid->pid == pidn)
120 static int should_scan_process(struct parse_opts *opts, struct process *process)
124 if (is_parse_option(opts, PARSE_PID) &&
125 is_parse_option(opts, PARSE_MAP_NAME)) {
126 if (pid_is_match(process->pid, &opts->pidlist))
129 if (is_parse_option(opts, PARSE_PID)) {
130 if (pid_is_match(process->pid, &opts->pidlist))
134 if (is_parse_option(opts, PARSE_MAP_NAME))
138 if (is_parse_option(opts, PARSE_NOADD_TREE))
144 static int should_scan_mapping(struct parse_opts *opts, struct maps *map)
148 if (is_parse_option(opts, PARSE_MAP_NAME)) {
149 if (strstr(map->name, opts->name))
152 if (is_parse_option(opts, PARSE_NOADD_TREE))
160 static int should_add_to_tree(struct parse_opts *opts, struct pageframe *pf,
163 if (is_parse_option(opts, PARSE_NOADD_TREE))
169 /* Read data from the /proc/pid/pagemap file */
170 static int parse_pageframe(FILE *file, struct pageframe *pf_tree,
171 struct maps *maps, struct parse_opts *opts)
174 struct maps_list *tmp;
175 struct pageframe *match, *pageframe = NULL;
177 unsigned long long pf[10240];
183 /* Go through the list of allocated memory areas */
184 list_for_each_entry(map, &maps->list, list) {
185 start = map->start >> (PAGE_SHIFT - 3);
186 len = map->size >> (PAGE_SHIFT);
188 if (!should_scan_mapping(opts, map))
191 ret = fseek(file, start, SEEK_SET);
194 fprintf(stderr, "Error seeking to %lx: %s\n", start,
199 for (i = 0; i < len; i++) {
202 MIN(sizeof(pf), (len - i) * 8), file);
209 pageframe = alloc_pageframe();
210 ret -= sizeof(pf[0]);
212 /* ignore unused pages */
213 if (!pf[ret / sizeof(pf[0])])
216 pageframe->pf = (pf[ret / sizeof(pf[0])]);
218 /* ignore unused pages */
219 if (!(page_swapped(pageframe) ||
220 page_present(pageframe)))
223 if (should_add_to_tree(opts, pageframe, map)) {
224 match = tree_to_pageframe(
225 bintree_add(&pf_tree->tree,
229 match = tree_to_pageframe(
230 bintree_find(&pf_tree->tree,
238 if (match == pageframe)
243 * Add a link from the physical page to this
246 tmp = alloc_maplist();
248 list_add(&tmp->list, &match->ml);
250 if (page_present(match))
251 map->pages_present++;
252 else if (page_swapped(match))
253 map->pages_swapped++;
260 static int read_pageframe(int pid, int tid, struct pageframe *pageframe,
261 struct process *process_list, struct parse_opts *opts)
264 struct process *process;
265 struct pidlist *pidl, *n;
269 process = malloc(sizeof(*process));
270 memset(process, 0, sizeof(*process));
271 INIT_LIST_HEAD(&process->list);
276 if (!should_scan_process(opts, process))
279 snprintf(path, sizeof(path), "/proc/%d/task/%d/maps", pid, tid);
280 file = fopen(path, "rb");
285 maps = parse_maps(file, pid, tid);
287 process->maps = maps;
289 snprintf(path, sizeof(path), "/proc/%d/task/%d/pagemap", pid, tid);
290 file = fopen(path, "rb");
295 parse_pageframe(file, pageframe, maps, opts);
298 if (read_cmdline(pid, tid, process->name, sizeof(process->name)))
302 list_for_each_entry(maps, &process->maps->list, list) {
303 process->pages_present += maps->pages_present;
304 process->pages_swapped += maps->pages_swapped;
308 if (!is_parse_option(opts, PARSE_NOADD_TREE))
309 process->is_initial_pid = 1;
311 list_add_tail(&process->list, &process_list->list);
318 * Remove the pid from the list. It is no longer an
319 * interesting pid, since we can't access its data
321 list_for_each_entry_safe(pidl, n, &opts->pidlist, list) {
322 if (pidl->pid == pid) {
323 list_del(&pidl->list);
332 static int read_pageframe_with_threads(int pid,
333 struct pageframe *pageframe,
334 struct process *process_list,
335 struct parse_opts *opts)
342 if (opts->with_threads)
343 tid = get_next_tid(pid, &dir);
350 count += read_pageframe(pid, tid, pageframe, process_list,
353 if (!opts->with_threads)
360 int scan_all_pids(struct pageframe *pf, struct process *process_list,
361 struct parse_opts *opts)
363 struct pidlist *pidlist, *n;
368 if (is_parse_option(opts, PARSE_PID)) {
369 list_for_each_entry_safe(pidlist, n, &opts->pidlist, list) {
370 count += read_pageframe_with_threads(pidlist->pid, pf,
375 if ((count == 0) && !(is_parse_option(opts, PARSE_MAP_NAME))) {
376 printf("Failed to find any matching processes "
377 "with given arguments\n");
381 if (is_parse_option(opts, PARSE_DUMP))
384 if (is_parse_option(opts, PARSE_MAP_NAME) &&
385 !is_parse_option(opts, PARSE_PID)) {
387 pid = get_next_pid(&dir);
390 read_pageframe_with_threads(pid, pf, process_list,
394 /* Do not add new pages in the tree after the initial scan */
395 opts->parse_mask |= PARSE_NOADD_TREE;
398 pid = get_next_pid(&dir);
401 read_pageframe_with_threads(pid, pf, process_list, opts);
407 struct kpageflag_data {
408 struct bintree_ops ops;
414 #define bintree_ops_to_kpfd(bintree_ops) \
415 container_of((bintree_ops), struct kpageflag_data, ops)
417 static void _update_kpageflags(struct bintree *bt, struct bintree_ops *ops)
419 struct pageframe *pf = tree_to_pageframe(bt);
420 struct kpageflag_data *kpfd = bintree_ops_to_kpfd(ops);
422 long int pfnn = pfn(pf) * sizeof(pf->kpageflags);
424 ret = lseek(kpfd->kpageflags_fd, pfnn, SEEK_SET);
427 fprintf(stderr, "Error seeking to %lx: %s\n",
428 pfnn, strerror(error));
432 ret = read(kpfd->kpageflags_fd, &pf->kpageflags,
433 sizeof(pf->kpageflags));
436 fprintf(stderr, "Error reading from %llx: %s\n",
437 pf->pf * sizeof(pf->kpageflags),
442 ret = lseek(kpfd->kpagecount_fd, pfnn, SEEK_SET);
445 fprintf(stderr, "Error seeking to %lx: %s\n",
446 pfnn, strerror(error));
450 ret = read(kpfd->kpagecount_fd, &pf->kpagecount,
451 sizeof(pf->kpagecount));
454 fprintf(stderr, "Error reading from %llx: %s\n",
455 pf->pf * sizeof(pf->kpagecount),
461 int update_kpageflags(struct pageframe *pf)
463 struct kpageflag_data kpfd = {
465 .callback = _update_kpageflags,
467 .kpageflags_fd = open("/proc/kpageflags", O_RDONLY),
468 .kpagecount_fd = open("/proc/kpagecount", O_RDONLY),
471 if (kpfd.kpageflags_fd == -1 || kpfd.kpagecount_fd == -1)
474 bintree_walk(&pf->tree, &kpfd.ops);
476 close(kpfd.kpageflags_fd);
477 close(kpfd.kpagecount_fd);