11 static struct maps_list *alloc_maplist(void)
13 struct maps_list *map;
15 map = malloc(sizeof *map);
19 memset(map, 0, sizeof(*map));
20 INIT_LIST_HEAD(&map->list);
25 static struct maps *alloc_map(void)
29 map = malloc(sizeof *map);
33 memset(map, 0, sizeof(*map));
34 INIT_LIST_HEAD(&map->list);
39 static struct maps *parse_maps(FILE *file, int pid, int tid)
41 struct maps *the_map = NULL;
45 while(fgets(line, sizeof(line), file)) {
46 struct maps *map = alloc_map();
47 unsigned long start, end;
56 ret = sscanf(line, "%lx-%lx %*s %*s %*s %*s %s",
60 printf("Error reading input: %s\n", line);
66 map->size = end - start;
71 strncpy(map->name, name, sizeof(map->name));
73 list_add_tail(&map->list, &the_map->list);
79 static void clear_pageframe(struct pageframe *pf)
81 memset(pf, 0, sizeof(*pf));
84 static struct pageframe *alloc_pageframe(void)
86 struct pageframe *pageframe;
88 pageframe = malloc(sizeof *pageframe);
89 if (pageframe == NULL)
92 clear_pageframe(pageframe);
97 #define BITRANGE(first, last) (((2ll << (last - first)) - 1) << first)
99 static void pageframe_to_struct(unsigned long long p, struct pageframe *pf)
101 /* Refer Documentation/vm/pagemap.txt for the format */
102 pf->page_present = !!(BITRANGE(63, 63) & p);
103 pf->page_swapped = !!(BITRANGE(62, 62) & p);
104 pf->page_shift = (BITRANGE(55, 60) & p) >> 55;
105 pf->pfn = (BITRANGE(0, 54) & p);
106 pf->swap_type = (BITRANGE(0, 4) & p);
107 pf->swap_offset = (BITRANGE(5, 54) & p) >> 5;
109 printf("pfn: %lx shift: %d present: %d swapped %d\n",
110 pf->pfn, pf->page_shift, pf->page_present, pf->page_swapped);
114 static int compare_pageframe(struct bintree *at, struct bintree *bt)
116 struct pageframe *a, *b;
117 a = tree_to_pageframe(at);
118 b = tree_to_pageframe(bt);
120 return a->pfn - b->pfn;
123 struct bintree_ops pageframe_ops = {
124 .compare = compare_pageframe,
127 static int check_parse_opts(struct parse_opts *opts, struct pageframe *pf,
130 if (opts->parse_mask & PARSE_PID) {
131 if (opts->pid == map->pid)
135 if (opts->parse_mask & PARSE_MAP_NAME) {
136 if (!strcmp(opts->map_name, map->name))
143 /* Read data from the /proc/pid/pagemap file */
144 static int parse_pageframe(FILE *file, struct pageframe *pf_tree,
145 struct maps *maps, struct parse_opts *opts)
148 struct maps_list *tmp;
149 struct pageframe *match, *pageframe = NULL;
151 unsigned long long pf[10240];
157 /* Go through the list of allocated memory areas */
158 list_for_each_entry(map, &maps->list, list) {
159 start = map->start >> (PAGE_SHIFT - 3);
160 len = map->size >> (PAGE_SHIFT - 3);
162 ret = fseek(file, start, SEEK_SET);
165 fprintf(stderr, "Error seeking to %lx: %s\n", start,
170 for (i = 0; i < len; i++) {
173 MIN(sizeof(pf), (len - i) * 8), file);
180 pageframe = alloc_pageframe();
181 ret -= sizeof(pf[0]);
183 /* ignore unused pages */
184 if (!pf[ret / sizeof(pf[0])])
187 pageframe_to_struct(pf[ret / sizeof(pf[0])], pageframe);
189 /* ignore unused pages */
190 if (!(pageframe->page_swapped ||
191 pageframe->page_present))
194 if (check_parse_opts(opts, pageframe, map)) {
195 match = tree_to_pageframe(
196 bintree_add(&pf_tree->tree,
200 match = tree_to_pageframe(
201 bintree_find(&pf_tree->tree,
209 if (match == pageframe)
214 * Add a link from the physical page to this
218 match->ml = alloc_maplist();
219 match->ml->map = map;
221 tmp = alloc_maplist();
223 list_add(&match->ml->list, &tmp->list);
226 if (match->page_present) {
227 map->pages_present++;
228 } else if (match->page_swapped) {
229 map->pages_swapped++;
237 void read_pageframe(int pid, int tid, struct pageframe *pageframe,
238 struct process **process_list, struct parse_opts *opts)
241 struct process *process;
246 process = malloc(sizeof(*process));
247 memset(process, 0, sizeof(*process));
248 INIT_LIST_HEAD(&process->list);
250 if (*process_list == NULL)
251 *process_list = process;
256 list_add_tail(&process->list, &(*process_list)->list);
258 snprintf(path, sizeof(path), "/proc/%d/task/%d/maps", pid, tid);
259 file = fopen(path, "rb");
264 maps = parse_maps(file, pid, tid);
266 process->maps = maps;
268 snprintf(path, sizeof(path), "/proc/%d/task/%d/pagemap", pid, tid);
269 file = fopen(path, "rb");
274 parse_pageframe(file, pageframe, maps, opts);
277 snprintf(path, sizeof(path), "/proc/%d/task/%d/cmdline", pid, tid);
278 file = fopen(path, "rb");
283 ret = fread(process->name, 1, sizeof(process->name), file);
285 process->name[ret - 1] = 0;
291 list_for_each_entry(maps, &process->maps->list, list) {
292 process->pages_present += maps->pages_present;
293 process->pages_swapped += maps->pages_swapped;
299 static int parse_pid(DIR **dir)
301 struct dirent *dirent;
305 dirent = readdir(*dir);
313 printf("Failed to read /proc directory: %s\n", strerror(error));
317 if (dirent->d_name[0] < '0' || dirent->d_name[0] > '9')
320 return atoi(dirent->d_name);
323 static int get_next_tid(int pid, DIR **dir)
330 snprintf(path, sizeof(path), "/proc/%d/task/", pid);
331 *dir = opendir(path);
334 printf("Failed to open %s directory: %s\n",
341 return parse_pid(dir);
344 static int get_next_pid(void)
346 static DIR *dir = NULL;
350 dir = opendir("/proc");
353 printf("Failed to open /proc directory: %s\n",
359 return parse_pid(&dir);
362 static void read_pageframe_with_threads(int pid,
363 struct pageframe *pageframe,
364 struct process **process_list,
365 struct parse_opts *opts)
371 tid = get_next_tid(pid, &dir);
376 read_pageframe(pid, pid, pageframe, process_list, opts);
380 void scan_all_pids(struct pageframe *pf, struct process **process_list,
381 struct parse_opts *opts)
385 if (opts->parse_mask & PARSE_PID)
386 read_pageframe_with_threads(opts->pid, pf, process_list, opts);
389 pid = get_next_pid();
392 read_pageframe_with_threads(pid, pf, process_list, opts);