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 should_scan_process(struct parse_opts *opts, struct process *process)
113 if (is_parse_option(opts, PARSE_PID)) {
114 list_for_each_entry(pid, &opts->pidlist, list) {
115 if (pid->pid == process->pid) {
122 if (is_parse_option(opts, PARSE_MAP_NAME))
125 if (is_parse_option(opts, PARSE_NOADD_TREE))
131 static int should_scan_mapping(struct parse_opts *opts, struct maps *map)
135 if (is_parse_option(opts, PARSE_MAP_NAME)) {
136 if (strstr(map->name, opts->name))
139 if (is_parse_option(opts, PARSE_NOADD_TREE))
147 static int should_add_to_tree(struct parse_opts *opts, struct pageframe *pf,
150 if (is_parse_option(opts, PARSE_NOADD_TREE))
156 /* Read data from the /proc/pid/pagemap file */
157 static int parse_pageframe(FILE *file, struct pageframe *pf_tree,
158 struct maps *maps, struct parse_opts *opts)
161 struct maps_list *tmp;
162 struct pageframe *match, *pageframe = NULL;
164 unsigned long long pf[10240];
170 /* Go through the list of allocated memory areas */
171 list_for_each_entry(map, &maps->list, list) {
172 start = map->start >> (PAGE_SHIFT - 3);
173 len = map->size >> (PAGE_SHIFT);
175 if (!should_scan_mapping(opts, map))
178 ret = fseek(file, start, SEEK_SET);
181 fprintf(stderr, "Error seeking to %lx: %s\n", start,
186 for (i = 0; i < len; i++) {
189 MIN(sizeof(pf), (len - i) * 8), file);
196 pageframe = alloc_pageframe();
197 ret -= sizeof(pf[0]);
199 /* ignore unused pages */
200 if (!pf[ret / sizeof(pf[0])])
203 pageframe->pf = (pf[ret / sizeof(pf[0])]);
205 /* ignore unused pages */
206 if (!(page_swapped(pageframe) ||
207 page_present(pageframe)))
210 if (should_add_to_tree(opts, pageframe, map)) {
211 match = tree_to_pageframe(
212 bintree_add(&pf_tree->tree,
216 match = tree_to_pageframe(
217 bintree_find(&pf_tree->tree,
225 if (match == pageframe)
230 * Add a link from the physical page to this
233 tmp = alloc_maplist();
235 list_add(&tmp->list, &match->ml);
237 if (page_present(match))
238 map->pages_present++;
239 else if (page_swapped(match))
240 map->pages_swapped++;
247 static int read_pageframe(int pid, int tid, struct pageframe *pageframe,
248 struct process *process_list, struct parse_opts *opts)
251 struct process *process;
252 struct pidlist *pidl, *n;
256 process = malloc(sizeof(*process));
257 memset(process, 0, sizeof(*process));
258 INIT_LIST_HEAD(&process->list);
263 if (!should_scan_process(opts, process))
266 snprintf(path, sizeof(path), "/proc/%d/task/%d/maps", pid, tid);
267 file = fopen(path, "rb");
272 maps = parse_maps(file, pid, tid);
274 process->maps = maps;
276 snprintf(path, sizeof(path), "/proc/%d/task/%d/pagemap", pid, tid);
277 file = fopen(path, "rb");
282 parse_pageframe(file, pageframe, maps, opts);
285 if (read_cmdline(pid, tid, process->name, sizeof(process->name)))
289 list_for_each_entry(maps, &process->maps->list, list) {
290 process->pages_present += maps->pages_present;
291 process->pages_swapped += maps->pages_swapped;
295 if (!is_parse_option(opts, PARSE_NOADD_TREE))
296 process->is_initial_pid = 1;
298 list_add_tail(&process->list, &process_list->list);
305 * Remove the pid from the list. It is no longer an
306 * interesting pid, since we can't access its data
308 list_for_each_entry_safe(pidl, n, &opts->pidlist, list) {
309 if (pidl->pid == pid) {
310 list_del(&pidl->list);
319 static int read_pageframe_with_threads(int pid,
320 struct pageframe *pageframe,
321 struct process *process_list,
322 struct parse_opts *opts)
329 if (opts->with_threads)
330 tid = get_next_tid(pid, &dir);
337 count += read_pageframe(pid, tid, pageframe, process_list,
340 if (!opts->with_threads)
347 int scan_all_pids(struct pageframe *pf, struct process *process_list,
348 struct parse_opts *opts)
350 struct pidlist *pidlist, *n;
355 if (is_parse_option(opts, PARSE_PID)) {
356 list_for_each_entry_safe(pidlist, n, &opts->pidlist, list) {
357 count += read_pageframe_with_threads(pidlist->pid, pf,
362 if ((count == 0) && !(is_parse_option(opts, PARSE_MAP_NAME))) {
363 printf("Failed to find any matching processes "
364 "with given arguments\n");
368 if (is_parse_option(opts, PARSE_DUMP))
371 if (is_parse_option(opts, PARSE_MAP_NAME)) {
373 pid = get_next_pid(&dir);
376 read_pageframe_with_threads(pid, pf, process_list,
380 /* Do not add new pages in the tree after the initial scan */
381 opts->parse_mask |= PARSE_NOADD_TREE;
384 pid = get_next_pid(&dir);
387 read_pageframe_with_threads(pid, pf, process_list, opts);
393 struct kpageflag_data {
394 struct bintree_ops ops;
400 #define bintree_ops_to_kpfd(bintree_ops) \
401 container_of((bintree_ops), struct kpageflag_data, ops)
403 static void _update_kpageflags(struct bintree *bt, struct bintree_ops *ops)
405 struct pageframe *pf = tree_to_pageframe(bt);
406 struct kpageflag_data *kpfd = bintree_ops_to_kpfd(ops);
408 long int pfnn = pfn(pf) * sizeof(pf->kpageflags);
410 ret = lseek(kpfd->kpageflags_fd, pfnn, SEEK_SET);
413 fprintf(stderr, "Error seeking to %lx: %s\n",
414 pfnn, strerror(error));
418 ret = read(kpfd->kpageflags_fd, &pf->kpageflags,
419 sizeof(pf->kpageflags));
422 fprintf(stderr, "Error reading from %llx: %s\n",
423 pf->pf * sizeof(pf->kpageflags),
428 ret = lseek(kpfd->kpagecount_fd, pfnn, SEEK_SET);
431 fprintf(stderr, "Error seeking to %lx: %s\n",
432 pfnn, strerror(error));
436 ret = read(kpfd->kpagecount_fd, &pf->kpagecount,
437 sizeof(pf->kpagecount));
440 fprintf(stderr, "Error reading from %llx: %s\n",
441 pf->pf * sizeof(pf->kpagecount),
447 int update_kpageflags(struct pageframe *pf)
449 struct kpageflag_data kpfd = {
451 .callback = _update_kpageflags,
453 .kpageflags_fd = open("/proc/kpageflags", O_RDONLY),
454 .kpagecount_fd = open("/proc/kpagecount", O_RDONLY),
457 if (kpfd.kpageflags_fd == -1 || kpfd.kpagecount_fd == -1)
460 bintree_walk(&pf->tree, &kpfd.ops);
462 close(kpfd.kpageflags_fd);
463 close(kpfd.kpagecount_fd);