diff options
Diffstat (limited to 'pagecache/dumpcache.c')
-rw-r--r-- | pagecache/dumpcache.c | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/pagecache/dumpcache.c b/pagecache/dumpcache.c new file mode 100644 index 00000000..fc06bf24 --- /dev/null +++ b/pagecache/dumpcache.c @@ -0,0 +1,152 @@ +#include <ftw.h> +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> + +#include <ctype.h> +#include <stddef.h> +#include <sys/mman.h> +#include <sys/stat.h> + +// Initial size of the array holding struct file_info +#define INITIAL_NUM_FILES 512 + +// Max number of file descriptors to use for ntfw +#define MAX_NUM_FD 1 + +struct file_info { + char *name; + size_t file_size; + size_t num_cached_pages; +}; + +// Size of pages on this system +static int g_page_size; + +// Total number of cached pages found so far +static size_t g_total_cached = 0; + +// Total number of files scanned so far +static size_t g_num_files = 0; + +// Scanned files and their associated cached page counts +static struct file_info **g_files; + +// Current size of files array +size_t g_files_size; + +static struct file_info *get_file_info(const char* fpath, size_t file_size) { + struct file_info *info; + if (g_num_files >= g_files_size) { + g_files = realloc(g_files, 2 * g_files_size * sizeof(struct file_info*)); + if (!g_files) { + fprintf(stderr, "Couldn't allocate space for files array: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + g_files_size = 2 * g_files_size; + } + + info = calloc(1, sizeof(*info)); + if (!info) { + fprintf(stderr, "Couldn't allocate space for file struct: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + info->name = malloc(strlen(fpath) + 1); + if (!info->name) { + fprintf(stderr, "Couldn't allocate space for file struct: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + strcpy(info->name, fpath); + + info->num_cached_pages = 0; + info->file_size = file_size; + + g_files[g_num_files++] = info; + + return info; +} + +static int store_num_cached(const char* fpath, const struct stat *sb) { + int fd; + fd = open (fpath, O_RDONLY); + + if (fd == -1) { + printf("Could not open file."); + return -1; + } + + void* mapped_addr = mmap(NULL, sb->st_size, PROT_NONE, MAP_SHARED, fd, 0); + + if (mapped_addr != MAP_FAILED) { + // Calculate bit-vector size + size_t num_file_pages = (sb->st_size + g_page_size - 1) / g_page_size; + unsigned char* mincore_data = calloc(1, num_file_pages); + int ret = mincore(mapped_addr, sb->st_size, mincore_data); + int num_cached = 0; + unsigned int page = 0; + for (page = 0; page < num_file_pages; page++) { + if (mincore_data[page]) num_cached++; + } + if (num_cached > 0) { + struct file_info *info = get_file_info(fpath, sb->st_size); + info->num_cached_pages += num_cached; + g_total_cached += num_cached; + } + munmap(mapped_addr, sb->st_size); + } + + close(fd); + return 0; +} + +static int scan_entry(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { + if (typeflag == FTW_F) { + store_num_cached(fpath, sb); + } + return 0; +} + +static int cmpsize(size_t a, size_t b) { + if (a < b) return -1; + if (a > b) return 1; + return 0; +} + +static int cmpfiles(const void *a, const void *b) { + return cmpsize((*((struct file_info**)a))->num_cached_pages, + (*((struct file_info**)b))->num_cached_pages); +} + +int main() +{ + g_page_size = getpagesize(); + + g_files = malloc(INITIAL_NUM_FILES * sizeof(struct file_info*)); + g_files_size = INITIAL_NUM_FILES; + + // Walk filesystem trees + nftw("/system/", &scan_entry, MAX_NUM_FD, 0); + nftw("/vendor/", &scan_entry, MAX_NUM_FD, 0); + nftw("/data/", &scan_entry, MAX_NUM_FD, 0); + + // Sort entries + qsort(g_files, g_num_files, sizeof(g_files[0]), &cmpfiles); + + // Dump entries + for (size_t i = 0; i < g_num_files; i++) { + struct file_info *info = g_files[i]; + fprintf(stdout, "%s: %zu cached pages (%.2f MB, %lu%% of total file size.)\n", info->name, + info->num_cached_pages, + (float) (info->num_cached_pages * g_page_size) / 1024 / 1024, + (100 * info->num_cached_pages * g_page_size) / info->file_size); + } + + fprintf(stdout, "TOTAL CACHED: %zu pages (%f MB)\n", g_total_cached, + (float) (g_total_cached * 4096) / 1024 / 1024); + return 0; +} |