Home | History | Annotate | Download | only in pagecache
      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