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