summaryrefslogtreecommitdiff
path: root/pagecache/dumpcache.c
diff options
context:
space:
mode:
Diffstat (limited to 'pagecache/dumpcache.c')
-rw-r--r--pagecache/dumpcache.c152
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;
+}