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 struct pageframe *alloc_pageframe(void)
82 struct pageframe *pageframe;
84 pageframe = malloc(sizeof *pageframe);
85 if (pageframe == NULL)
88 clear_pageframe(pageframe);
93 static int compare_pageframe(struct bintree *at, struct bintree *bt)
95 struct pageframe *a, *b;
96 a = tree_to_pageframe(at);
97 b = tree_to_pageframe(bt);
102 struct bintree_ops pageframe_ops = {
103 .compare = compare_pageframe,
106 static int read_cmdline(int pid, int tid, char *cmdline, size_t len)
112 snprintf(path, sizeof(path), "/proc/%d/task/%d/cmdline", pid, tid);
113 file = fopen(path, "rb");
118 ret = fread(cmdline, 1, len, file);
120 cmdline[ret - 1] = 0;
123 return ret > 0 ? 0 : -1;
126 static char *get_name_by_pid(int pid)
129 static char cmdline[128];
135 if (read_cmdline(pid, pid, cmdline, sizeof(cmdline))) {
140 bname = basename(cmdline);
146 static int should_scan_process(struct parse_opts *opts, struct process *process)
152 if (is_parse_option(opts, PARSE_PROCESS_NAME)) {
153 name = get_name_by_pid(process->pid);
154 if (!strcmp(opts->name, name ? name : ""))
158 if (is_parse_option(opts, PARSE_PID)) {
159 list_for_each_entry(pid, &opts->pidlist, list) {
160 if (pid->pid == process->pid) {
167 if (is_parse_option(opts, PARSE_MAP_NAME))
170 if (is_parse_option(opts, PARSE_NOADD_TREE))
176 static int should_scan_mapping(struct parse_opts *opts, struct maps *map)
180 if (is_parse_option(opts, PARSE_MAP_NAME)) {
181 if (!strcmp(opts->name, map->name))
184 if (is_parse_option(opts, PARSE_NOADD_TREE))
192 static int should_add_to_tree(struct parse_opts *opts, struct pageframe *pf,
195 if (is_parse_option(opts, PARSE_NOADD_TREE))
201 /* Read data from the /proc/pid/pagemap file */
202 static int parse_pageframe(FILE *file, struct pageframe *pf_tree,
203 struct maps *maps, struct parse_opts *opts)
206 struct maps_list *tmp;
207 struct pageframe *match, *pageframe = NULL;
209 unsigned long long pf[10240];
215 /* Go through the list of allocated memory areas */
216 list_for_each_entry(map, &maps->list, list) {
217 start = map->start >> (PAGE_SHIFT - 3);
218 len = map->size >> (PAGE_SHIFT);
220 if (!should_scan_mapping(opts, map))
223 ret = fseek(file, start, SEEK_SET);
226 fprintf(stderr, "Error seeking to %lx: %s\n", start,
231 for (i = 0; i < len; i++) {
234 MIN(sizeof(pf), (len - i) * 8), file);
241 pageframe = alloc_pageframe();
242 ret -= sizeof(pf[0]);
244 /* ignore unused pages */
245 if (!pf[ret / sizeof(pf[0])])
248 pageframe->pf = (pf[ret / sizeof(pf[0])]);
250 /* ignore unused pages */
251 if (!(page_swapped(pageframe) ||
252 page_present(pageframe)))
255 if (should_add_to_tree(opts, pageframe, map)) {
256 match = tree_to_pageframe(
257 bintree_add(&pf_tree->tree,
261 match = tree_to_pageframe(
262 bintree_find(&pf_tree->tree,
270 if (match == pageframe)
275 * Add a link from the physical page to this
278 tmp = alloc_maplist();
280 list_add(&tmp->list, &match->ml);
282 if (page_present(match))
283 map->pages_present++;
284 else if (page_swapped(match))
285 map->pages_swapped++;
292 static int read_pageframe(int pid, int tid, struct pageframe *pageframe,
293 struct process *process_list, struct parse_opts *opts)
296 struct process *process;
300 process = malloc(sizeof(*process));
301 memset(process, 0, sizeof(*process));
302 INIT_LIST_HEAD(&process->list);
307 if (!should_scan_process(opts, process))
310 snprintf(path, sizeof(path), "/proc/%d/task/%d/maps", pid, tid);
311 file = fopen(path, "rb");
316 maps = parse_maps(file, pid, tid);
318 process->maps = maps;
320 snprintf(path, sizeof(path), "/proc/%d/task/%d/pagemap", pid, tid);
321 file = fopen(path, "rb");
326 parse_pageframe(file, pageframe, maps, opts);
329 if (read_cmdline(pid, tid, process->name, sizeof(process->name)))
333 list_for_each_entry(maps, &process->maps->list, list) {
334 process->pages_present += maps->pages_present;
335 process->pages_swapped += maps->pages_swapped;
339 if (!is_parse_option(opts, PARSE_NOADD_TREE))
340 process->is_initial_pid = 1;
342 list_add_tail(&process->list, &process_list->list);
351 static int parse_pid(DIR **dir)
353 struct dirent *dirent;
357 dirent = readdir(*dir);
365 printf("Failed to read /proc directory: %s\n", strerror(error));
369 if (dirent->d_name[0] < '0' || dirent->d_name[0] > '9')
372 return atoi(dirent->d_name);
375 static int opendir_check(DIR **dir, const char *path)
380 *dir = opendir(path);
383 fprintf(stderr, "Failed to open %s directory: %s\n",
384 path, strerror(error));
392 static int get_next_tid(int pid, DIR **dir)
397 snprintf(path, sizeof(path), "/proc/%d/task/", pid);
398 if (opendir_check(dir, path))
402 return parse_pid(dir);
405 static int get_next_pid(DIR **dir)
407 if (opendir_check(dir, "/proc"))
410 return parse_pid(dir);
413 static int get_next_pid_by_name(DIR **dir, char *name)
418 if (opendir_check(dir, "/proc"))
422 pid = parse_pid(dir);
426 pname = get_name_by_pid(pid);
429 if (strcmp(pname, name))
438 static int read_pageframe_with_threads(int pid,
439 struct pageframe *pageframe,
440 struct process *process_list,
441 struct parse_opts *opts)
448 if (opts->with_threads)
449 tid = get_next_tid(pid, &dir);
456 count += read_pageframe(pid, tid, pageframe, process_list,
459 if (!opts->with_threads)
466 int scan_all_pids(struct pageframe *pf, struct process *process_list,
467 struct parse_opts *opts)
469 struct pidlist *pidlist;
474 if (is_parse_option(opts, PARSE_PROCESS_NAME)) {
475 while ((pid = get_next_pid_by_name(&dir, opts->name))) {
476 count += read_pageframe_with_threads(pid, pf,
483 if (is_parse_option(opts, PARSE_PID)) {
484 list_for_each_entry(pidlist, &opts->pidlist, list) {
485 count += read_pageframe_with_threads(pidlist->pid, pf,
490 if ((count == 0) && !(is_parse_option(opts, PARSE_MAP_NAME))) {
491 printf("Failed to find any matching processes "
492 "with given arguments\n");
496 if (is_parse_option(opts, PARSE_DUMP))
499 if (is_parse_option(opts, PARSE_MAP_NAME)) {
501 pid = get_next_pid(&dir);
504 read_pageframe_with_threads(pid, pf, process_list,
508 /* Do not add new pages in the tree after the initial scan */
509 opts->parse_mask |= PARSE_NOADD_TREE;
512 pid = get_next_pid(&dir);
515 read_pageframe_with_threads(pid, pf, process_list, opts);