#include #include #include #include #include #include #include #include "pagemap.h" #define HASH_SHIFT 13 #define HASH_MASK ((1 << HASH_SHIFT) - 1) #define HASH_KEY(flags) (flags & HASH_MASK) static unsigned long page_count[1 << HASH_SHIFT]; static uint64_t page_flags[1 << HASH_SHIFT]; int hash_index(uint64_t flags) { int i; int k = HASH_KEY(flags); if (!flags) return 0; for (i = 1; i < ARRAY_SIZE(page_count); i++, k++) { if (!k || k >= ARRAY_SIZE(page_count)) k = 1; if (page_flags[k] == 0) { page_flags[k] = flags; return k; } if (page_flags[k] == flags) return k; } exit(1); /* die hard on full hash table */ } char *page_flag_name(uint64_t flags) { int i, j; int bit; static char buf[65]; for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) { bit = (flags >> i) & 1; if (!page_flag_names[i]) { if (bit) fprintf(stderr, "unkown flag bit %d\n", i); continue; } buf[j++] = bit ? page_flag_names[i][0] : '_'; } return buf; } char *page_flag_longname(uint64_t flags) { int i, n; static char buf[1024]; for (i = 0, n = 0; i < ARRAY_SIZE(page_flag_names); i++) { if (!page_flag_names[i]) continue; if ((flags >> i) & 1) n += snprintf(buf + n, sizeof(buf) - n, "%s,", page_flag_names[i] + 2); } if (n) n--; buf[n] = '\0'; return buf; } static unsigned long nr_pages; static uint64_t kpageflags[KPF_BYTES * (1<<20)]; unsigned long collect_page_count() { unsigned long n; unsigned long i; uint64_t flags; int fd; fd = open(PROC_KPAGEFLAGS, O_RDONLY); if (fd < 0) { perror(PROC_KPAGEFLAGS); exit(1); } while (1) { n = read(fd, kpageflags, sizeof(kpageflags)); if (n == 0) break; if (n < 0) { perror(PROC_KPAGEFLAGS); exit(2); } if (n % KPF_BYTES != 0) { fprintf(stderr, "partial read: %lu bytes\n", n); exit(3); } n = n / KPF_BYTES; for (i = 0; i < n; i++) { flags = kpageflags[i]; page_count[hash_index(flags)]++; } nr_pages += n; } close(fd); } void show_page_count() { int i; printf(" flags\tpage-count MB" " symbolic-flags\t\t\tlong-symbolic-flags\n"); for (i = 0; i < ARRAY_SIZE(page_count); i++) { if (page_count[i]) printf("0x%012lx\t%10lu %8lu %s\t%s\n", page_flags[i], page_count[i], pages2mb(page_count[i]), page_flag_name(page_flags[i]), page_flag_longname(page_flags[i])); } printf(" total\t%10lu %8lu\n", nr_pages, pages2mb(nr_pages)); } int main(int argc, char *argv[]) { collect_page_count(); show_page_count(); return 0; }