1 #include <ftw.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <math.h> 5 #include <string.h> 6 #include <errno.h> 7 #include <unistd.h> 8 #include <fcntl.h> 9 10 #include <ctype.h> 11 #include <stddef.h> 12 #include <sys/mman.h> 13 #include <sys/stat.h> 14 15 // Initial size of the array holding struct file_info 16 #define INITIAL_NUM_FILES 512 17 18 // Max number of file descriptors to use for ntfw 19 #define MAX_NUM_FD 1 20 21 struct file_info { 22 char *name; 23 size_t file_size; 24 size_t num_cached_pages; 25 }; 26 27 // Size of pages on this system 28 static int g_page_size; 29 30 // Total number of cached pages found so far 31 static size_t g_total_cached = 0; 32 33 // Total number of files scanned so far 34 static size_t g_num_files = 0; 35 36 // Scanned files and their associated cached page counts 37 static struct file_info **g_files; 38 39 // Current size of files array 40 size_t g_files_size; 41 42 static struct file_info *get_file_info(const char* fpath, size_t file_size) { 43 struct file_info *info; 44 if (g_num_files >= g_files_size) { 45 g_files = realloc(g_files, 2 * g_files_size * sizeof(struct file_info*)); 46 if (!g_files) { 47 fprintf(stderr, "Couldn't allocate space for files array: %s\n", strerror(errno)); 48 exit(EXIT_FAILURE); 49 } 50 g_files_size = 2 * g_files_size; 51 } 52 53 info = calloc(1, sizeof(*info)); 54 if (!info) { 55 fprintf(stderr, "Couldn't allocate space for file struct: %s\n", strerror(errno)); 56 exit(EXIT_FAILURE); 57 } 58 59 info->name = malloc(strlen(fpath) + 1); 60 if (!info->name) { 61 fprintf(stderr, "Couldn't allocate space for file struct: %s\n", strerror(errno)); 62 exit(EXIT_FAILURE); 63 } 64 strcpy(info->name, fpath); 65 66 info->num_cached_pages = 0; 67 info->file_size = file_size; 68 69 g_files[g_num_files++] = info; 70 71 return info; 72 } 73 74 static int store_num_cached(const char* fpath, const struct stat *sb) { 75 int fd; 76 fd = open (fpath, O_RDONLY); 77 78 if (fd == -1) { 79 printf("Could not open file."); 80 return -1; 81 } 82 83 void* mapped_addr = mmap(NULL, sb->st_size, PROT_NONE, MAP_SHARED, fd, 0); 84 85 if (mapped_addr != MAP_FAILED) { 86 // Calculate bit-vector size 87 size_t num_file_pages = (sb->st_size + g_page_size - 1) / g_page_size; 88 unsigned char* mincore_data = calloc(1, num_file_pages); 89 int ret = mincore(mapped_addr, sb->st_size, mincore_data); 90 int num_cached = 0; 91 unsigned int page = 0; 92 for (page = 0; page < num_file_pages; page++) { 93 if (mincore_data[page]) num_cached++; 94 } 95 if (num_cached > 0) { 96 struct file_info *info = get_file_info(fpath, sb->st_size); 97 info->num_cached_pages += num_cached; 98 g_total_cached += num_cached; 99 } 100 munmap(mapped_addr, sb->st_size); 101 } 102 103 close(fd); 104 return 0; 105 } 106 107 static int scan_entry(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { 108 if (typeflag == FTW_F) { 109 store_num_cached(fpath, sb); 110 } 111 return 0; 112 } 113 114 static int cmpsize(size_t a, size_t b) { 115 if (a < b) return -1; 116 if (a > b) return 1; 117 return 0; 118 } 119 120 static int cmpfiles(const void *a, const void *b) { 121 return cmpsize((*((struct file_info**)a))->num_cached_pages, 122 (*((struct file_info**)b))->num_cached_pages); 123 } 124 125 int main() 126 { 127 size_t i; 128 g_page_size = getpagesize(); 129 130 g_files = malloc(INITIAL_NUM_FILES * sizeof(struct file_info*)); 131 g_files_size = INITIAL_NUM_FILES; 132 133 // Walk filesystem trees 134 nftw("/system/", &scan_entry, MAX_NUM_FD, 0); 135 nftw("/vendor/", &scan_entry, MAX_NUM_FD, 0); 136 nftw("/data/", &scan_entry, MAX_NUM_FD, 0); 137 138 // Sort entries 139 qsort(g_files, g_num_files, sizeof(g_files[0]), &cmpfiles); 140 141 // Dump entries 142 for (i = 0; i < g_num_files; i++) { 143 struct file_info *info = g_files[i]; 144 fprintf(stdout, "%s: %zu cached pages (%.2f MB, %zu%% of total file size.)\n", info->name, 145 info->num_cached_pages, 146 (float) (info->num_cached_pages * g_page_size) / 1024 / 1024, 147 (100 * info->num_cached_pages * g_page_size) / info->file_size); 148 } 149 150 fprintf(stdout, "TOTAL CACHED: %zu pages (%f MB)\n", g_total_cached, 151 (float) (g_total_cached * 4096) / 1024 / 1024); 152 return 0; 153 } 154