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
get_file_info(const char * fpath,size_t file_size)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
store_num_cached(const char * fpath,const struct stat * sb)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
scan_entry(const char * fpath,const struct stat * sb,int typeflag,struct FTW * ftwbuf)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
cmpsize(size_t a,size_t b)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
cmpfiles(const void * a,const void * b)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
main()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