blob: 4503a6e6b0c63067fe71a296505dd44b4c13c222 [file] [log] [blame]
Martijn Coenen0a1b0182015-11-30 14:43:10 +01001#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>
Wei Wangce1cef82016-09-26 16:47:49 -070012#include <mntent.h>
Martijn Coenen0a1b0182015-11-30 14:43:10 +010013#include <sys/mman.h>
14#include <sys/stat.h>
15
16// Initial size of the array holding struct file_info
17#define INITIAL_NUM_FILES 512
18
19// Max number of file descriptors to use for ntfw
20#define MAX_NUM_FD 1
21
22struct file_info {
23 char *name;
24 size_t file_size;
25 size_t num_cached_pages;
26};
27
28// Size of pages on this system
29static int g_page_size;
30
31// Total number of cached pages found so far
32static size_t g_total_cached = 0;
33
34// Total number of files scanned so far
35static size_t g_num_files = 0;
36
37// Scanned files and their associated cached page counts
38static struct file_info **g_files;
39
40// Current size of files array
41size_t g_files_size;
42
43static struct file_info *get_file_info(const char* fpath, size_t file_size) {
44 struct file_info *info;
45 if (g_num_files >= g_files_size) {
46 g_files = realloc(g_files, 2 * g_files_size * sizeof(struct file_info*));
47 if (!g_files) {
48 fprintf(stderr, "Couldn't allocate space for files array: %s\n", strerror(errno));
49 exit(EXIT_FAILURE);
50 }
51 g_files_size = 2 * g_files_size;
52 }
53
54 info = calloc(1, sizeof(*info));
55 if (!info) {
56 fprintf(stderr, "Couldn't allocate space for file struct: %s\n", strerror(errno));
57 exit(EXIT_FAILURE);
58 }
59
60 info->name = malloc(strlen(fpath) + 1);
61 if (!info->name) {
62 fprintf(stderr, "Couldn't allocate space for file struct: %s\n", strerror(errno));
63 exit(EXIT_FAILURE);
64 }
65 strcpy(info->name, fpath);
66
67 info->num_cached_pages = 0;
68 info->file_size = file_size;
69
70 g_files[g_num_files++] = info;
71
72 return info;
73}
74
75static int store_num_cached(const char* fpath, const struct stat *sb) {
Wei Wangce1cef82016-09-26 16:47:49 -070076 int fd, ret = -1;
Martijn Coenen0a1b0182015-11-30 14:43:10 +010077 fd = open (fpath, O_RDONLY);
78
79 if (fd == -1) {
Wei Wangce1cef82016-09-26 16:47:49 -070080 fprintf(stderr, "Could not open file: %s\n", fpath);
81 return ret;
Martijn Coenen0a1b0182015-11-30 14:43:10 +010082 }
83
84 void* mapped_addr = mmap(NULL, sb->st_size, PROT_NONE, MAP_SHARED, fd, 0);
85
86 if (mapped_addr != MAP_FAILED) {
87 // Calculate bit-vector size
88 size_t num_file_pages = (sb->st_size + g_page_size - 1) / g_page_size;
89 unsigned char* mincore_data = calloc(1, num_file_pages);
Wei Wangce1cef82016-09-26 16:47:49 -070090 ret = mincore(mapped_addr, sb->st_size, mincore_data);
91 if (!ret) {
92 int num_cached = 0;
93 unsigned int page = 0;
94 for (page = 0; page < num_file_pages; page++) {
95 if (mincore_data[page]) num_cached++;
96 }
97 if (num_cached > 0) {
98 struct file_info *info = get_file_info(fpath, sb->st_size);
99 info->num_cached_pages += num_cached;
100 g_total_cached += num_cached;
101 }
Martijn Coenen0a1b0182015-11-30 14:43:10 +0100102 }
103 munmap(mapped_addr, sb->st_size);
104 }
105
106 close(fd);
Wei Wangce1cef82016-09-26 16:47:49 -0700107 return ret;
Martijn Coenen0a1b0182015-11-30 14:43:10 +0100108}
109
Wei Wangce1cef82016-09-26 16:47:49 -0700110static int scan_entry(const char *fpath, const struct stat *sb, int typeflag,
111 struct FTW * __attribute__((unused))ftwbuf) {
Martijn Coenen0a1b0182015-11-30 14:43:10 +0100112 if (typeflag == FTW_F) {
113 store_num_cached(fpath, sb);
114 }
115 return 0;
116}
117
118static int cmpsize(size_t a, size_t b) {
119 if (a < b) return -1;
120 if (a > b) return 1;
121 return 0;
122}
123
124static int cmpfiles(const void *a, const void *b) {
125 return cmpsize((*((struct file_info**)a))->num_cached_pages,
126 (*((struct file_info**)b))->num_cached_pages);
127}
128
129int main()
130{
Martijn Coenen31af9872015-12-07 09:51:12 +0100131 size_t i;
Martijn Coenen0a1b0182015-11-30 14:43:10 +0100132 g_page_size = getpagesize();
133
134 g_files = malloc(INITIAL_NUM_FILES * sizeof(struct file_info*));
135 g_files_size = INITIAL_NUM_FILES;
136
Wei Wangce1cef82016-09-26 16:47:49 -0700137 // Walk filesystem trees through procfs except rootfs/devfs/sysfs/procfs
138 FILE* fp = setmntent("/proc/mounts", "r");
139 if (fp == NULL) {
140 fprintf(stderr, "Error opening /proc/mounts\n");
141 return -errno;
142 }
143 struct mntent* mentry;
144 while ((mentry = getmntent(fp)) != NULL) {
145 if (strcmp(mentry->mnt_type, "rootfs") != 0 &&
146 strncmp("/dev", mentry->mnt_dir, strlen("/dev")) != 0 &&
147 strncmp("/sys", mentry->mnt_dir, strlen("/sys")) != 0 &&
148 strncmp("/proc", mentry->mnt_dir, strlen("/proc")) != 0) {
149 nftw(mentry->mnt_dir, &scan_entry, MAX_NUM_FD, FTW_MOUNT | FTW_PHYS | FTW_DEPTH);
150 }
151 }
152 endmntent(fp);
Martijn Coenen0a1b0182015-11-30 14:43:10 +0100153
154 // Sort entries
155 qsort(g_files, g_num_files, sizeof(g_files[0]), &cmpfiles);
156
157 // Dump entries
Martijn Coenen31af9872015-12-07 09:51:12 +0100158 for (i = 0; i < g_num_files; i++) {
Martijn Coenen0a1b0182015-11-30 14:43:10 +0100159 struct file_info *info = g_files[i];
Martijn Coenen31af9872015-12-07 09:51:12 +0100160 fprintf(stdout, "%s: %zu cached pages (%.2f MB, %zu%% of total file size.)\n", info->name,
Martijn Coenen0a1b0182015-11-30 14:43:10 +0100161 info->num_cached_pages,
162 (float) (info->num_cached_pages * g_page_size) / 1024 / 1024,
163 (100 * info->num_cached_pages * g_page_size) / info->file_size);
164 }
165
166 fprintf(stdout, "TOTAL CACHED: %zu pages (%f MB)\n", g_total_cached,
167 (float) (g_total_cached * 4096) / 1024 / 1024);
168 return 0;
169}