12 static struct maps_list *alloc_maplist(void)
14 struct maps_list *map;
16 map = malloc(sizeof *map);
20 memset(map, 0, sizeof(*map));
21 INIT_LIST_HEAD(&map->list);
26 static struct maps *alloc_map(void)
30 map = malloc(sizeof *map);
34 memset(map, 0, sizeof(*map));
35 INIT_LIST_HEAD(&map->list);
40 static struct maps *parse_maps(FILE *file, int pid, int tid)
42 struct maps *the_map = NULL;
46 while (fgets(line, sizeof(line), file)) {
47 struct maps *map = alloc_map();
48 unsigned long start, end;
57 ret = sscanf(line, "%lx-%lx %*s %*s %*s %*s %s",
61 printf("Error reading input: %s\n", line);
67 map->size = end - start;
72 strncpy(map->name, name, sizeof(map->name));
74 list_add_tail(&map->list, &the_map->list);
80 static void clear_pageframe(struct pageframe *pf)
82 memset(pf, 0, sizeof(*pf));
85 static struct pageframe *alloc_pageframe(void)
87 struct pageframe *pageframe;
89 pageframe = malloc(sizeof *pageframe);
90 if (pageframe == NULL)
93 clear_pageframe(pageframe);
98 #define BITRANGE(first, last) (((2ll << (last - first)) - 1) << first)
100 static void pageframe_to_struct(unsigned long long p, struct pageframe *pf)
102 /* Refer Documentation/vm/pagemap.txt for the format */
103 pf->page_present = !!(BITRANGE(63, 63) & p);
104 pf->page_swapped = !!(BITRANGE(62, 62) & p);
105 pf->page_shift = (BITRANGE(55, 60) & p) >> 55;
106 pf->pfn = (BITRANGE(0, 54) & p);
107 pf->swap_type = (BITRANGE(0, 4) & p);
108 pf->swap_offset = (BITRANGE(5, 54) & p) >> 5;
110 printf("pfn: %lx shift: %d present: %d swapped %d\n",
111 pf->pfn, pf->page_shift, pf->page_present, pf->page_swapped);
115 static int compare_pageframe(struct bintree *at, struct bintree *bt)
117 struct pageframe *a, *b;
118 a = tree_to_pageframe(at);
119 b = tree_to_pageframe(bt);
121 return a->pfn - b->pfn;
124 struct bintree_ops pageframe_ops = {
125 .compare = compare_pageframe,
128 static int read_cmdline(int pid, int tid, char *cmdline, size_t len)
134 snprintf(path, sizeof(path), "/proc/%d/task/%d/cmdline", pid, tid);
135 file = fopen(path, "rb");
140 ret = fread(cmdline, 1, len, file);
142 cmdline[ret - 1] = 0;
145 return ret > 0 ? 0 : -1;
148 static char *get_name_by_pid(int pid)
151 static char cmdline[128];
157 if (read_cmdline(pid, pid, cmdline, sizeof(cmdline))) {
162 bname = basename(cmdline);
168 static int should_scan_process(struct parse_opts *opts, struct process *process)
173 if (opts->parse_mask & PARSE_PROCESS_NAME) {
174 name = get_name_by_pid(process->pid);
175 if (!strcmp(opts->name, name ? name : ""))
179 if (opts->parse_mask & PARSE_PID) {
180 if (opts->pid == process->pid)
184 if (opts->parse_mask & PARSE_NOADD_TREE)
190 static int should_scan_mapping(struct parse_opts *opts, struct maps *map)
194 if (opts->parse_mask & PARSE_MAP_NAME) {
195 if (!strcmp(opts->name, map->name))
198 if (opts->parse_mask & PARSE_NOADD_TREE)
206 static int should_add_to_tree(struct parse_opts *opts, struct pageframe *pf,
209 if (opts->parse_mask & PARSE_NOADD_TREE)
215 /* Read data from the /proc/pid/pagemap file */
216 static int parse_pageframe(FILE *file, struct pageframe *pf_tree,
217 struct maps *maps, struct parse_opts *opts)
220 struct maps_list *tmp;
221 struct pageframe *match, *pageframe = NULL;
223 unsigned long long pf[10240];
229 /* Go through the list of allocated memory areas */
230 list_for_each_entry(map, &maps->list, list) {
231 start = map->start >> (PAGE_SHIFT - 3);
232 len = map->size >> (PAGE_SHIFT);
234 if (!should_scan_mapping(opts, map))
237 ret = fseek(file, start, SEEK_SET);
240 fprintf(stderr, "Error seeking to %lx: %s\n", start,
245 for (i = 0; i < len; i++) {
248 MIN(sizeof(pf), (len - i) * 8), file);
255 pageframe = alloc_pageframe();
256 ret -= sizeof(pf[0]);
258 /* ignore unused pages */
259 if (!pf[ret / sizeof(pf[0])])
262 pageframe_to_struct(pf[ret / sizeof(pf[0])], pageframe);
264 /* ignore unused pages */
265 if (!(pageframe->page_swapped ||
266 pageframe->page_present))
269 if (should_add_to_tree(opts, pageframe, map)) {
270 match = tree_to_pageframe(
271 bintree_add(&pf_tree->tree,
275 match = tree_to_pageframe(
276 bintree_find(&pf_tree->tree,
284 if (match == pageframe)
289 * Add a link from the physical page to this
293 match->ml = alloc_maplist();
294 match->ml->map = map;
296 tmp = alloc_maplist();
298 list_add(&tmp->list, &match->ml->list);
301 if (match->page_present)
302 map->pages_present++;
303 else if (match->page_swapped)
304 map->pages_swapped++;
311 static int read_pageframe(int pid, int tid, struct pageframe *pageframe,
312 struct process **process_list, struct parse_opts *opts)
315 struct process *process;
319 process = malloc(sizeof(*process));
320 memset(process, 0, sizeof(*process));
321 INIT_LIST_HEAD(&process->list);
323 if (*process_list == NULL)
324 *process_list = process;
329 if (!should_scan_process(opts, process))
332 snprintf(path, sizeof(path), "/proc/%d/task/%d/maps", pid, tid);
333 file = fopen(path, "rb");
338 maps = parse_maps(file, pid, tid);
340 process->maps = maps;
342 snprintf(path, sizeof(path), "/proc/%d/task/%d/pagemap", pid, tid);
343 file = fopen(path, "rb");
348 parse_pageframe(file, pageframe, maps, opts);
351 if (read_cmdline(pid, tid, process->name, sizeof(process->name)))
355 list_for_each_entry(maps, &process->maps->list, list) {
356 process->pages_present += maps->pages_present;
357 process->pages_swapped += maps->pages_swapped;
361 list_add_tail(&process->list, &(*process_list)->list);
370 static int parse_pid(DIR **dir)
372 struct dirent *dirent;
376 dirent = readdir(*dir);
384 printf("Failed to read /proc directory: %s\n", strerror(error));
388 if (dirent->d_name[0] < '0' || dirent->d_name[0] > '9')
391 return atoi(dirent->d_name);
394 static int opendir_check(DIR **dir, const char *path)
399 *dir = opendir(path);
402 fprintf(stderr, "Failed to open %s directory: %s\n",
403 path, strerror(error));
411 static int get_next_tid(int pid, DIR **dir)
416 snprintf(path, sizeof(path), "/proc/%d/task/", pid);
417 if (opendir_check(dir, path))
421 return parse_pid(dir);
424 static int get_next_pid(DIR **dir)
426 if (opendir_check(dir, "/proc"))
429 return parse_pid(dir);
432 static int get_next_pid_by_name(DIR **dir, char *name)
437 if (opendir_check(dir, "/proc"))
441 pid = parse_pid(dir);
445 pname = get_name_by_pid(pid);
448 if (strcmp(pname, name))
457 static int read_pageframe_with_threads(int pid,
458 struct pageframe *pageframe,
459 struct process **process_list,
460 struct parse_opts *opts)
467 if (opts->with_threads)
468 tid = get_next_tid(pid, &dir);
475 count += read_pageframe(pid, tid, pageframe, process_list,
478 if (!opts->with_threads)
485 int scan_all_pids(struct pageframe *pf, struct process **process_list,
486 struct parse_opts *opts)
492 if (opts->parse_mask & PARSE_PROCESS_NAME) {
493 while ((pid = get_next_pid_by_name(&dir, opts->name))) {
494 count += read_pageframe_with_threads(pid, pf,
501 if (opts->parse_mask & PARSE_PID)
502 count = read_pageframe_with_threads(opts->pid, pf, process_list,
505 if ((count == 0) && !(opts->parse_mask & PARSE_MAP_NAME)) {
506 printf("Failed to find any matching processes "
507 "with given arguments\n");
511 if (opts->parse_mask & PARSE_DUMP)
514 /* Do not add new pages in the tree after the initial scan */
515 opts->parse_mask |= PARSE_NOADD_TREE;
518 pid = get_next_pid(&dir);
521 read_pageframe_with_threads(pid, pf, process_list, opts);