f2fstat.c revision 4ff7400c519a8f644b8181756939fcb313345c12
1#include <stdio.h> 2#include <unistd.h> 3#include <stdlib.h> 4#include <string.h> 5#include <fcntl.h> 6#include <libgen.h> 7 8#ifdef DEBUG 9#define dbg(fmt, args...) printf(fmt, __VA_ARGS__); 10#else 11#define dbg(fmt, args...) 12#endif 13 14/* 15 * f2fs status 16 */ 17#define F2FS_STATUS "/sys/kernel/debug/f2fs/status" 18 19#define KEY_NODE 0x00000001 20#define KEY_META 0x00000010 21 22unsigned long util; 23unsigned long used_node_blks; 24unsigned long used_data_blks; 25//unsigned long inline_inode; 26 27unsigned long free_segs; 28unsigned long valid_segs; 29unsigned long dirty_segs; 30unsigned long prefree_segs; 31 32unsigned long gc; 33unsigned long bg_gc; 34unsigned long gc_data_blks; 35unsigned long gc_node_blks; 36 37//unsigned long extent_hit_ratio; 38 39unsigned long dirty_node, node_kb; 40unsigned long dirty_dents; 41unsigned long dirty_meta, meta_kb; 42unsigned long nat_caches; 43unsigned long dirty_sit; 44 45unsigned long free_nids; 46 47unsigned long ssr_blks; 48unsigned long lfs_blks; 49unsigned long memory_kb; 50 51struct options { 52 int delay; 53 int interval; 54 char partname[32]; 55}; 56 57struct mm_table { 58 const char *name; 59 unsigned long *val; 60 int flag; 61}; 62 63static int compare_mm_table(const void *a, const void *b) 64{ 65 dbg("[COMPARE] %s, %s\n", ((struct mm_table *)a)->name, ((struct mm_table *)b)->name); 66 return strcmp(((struct mm_table *)a)->name, ((struct mm_table *)b)->name); 67} 68 69static inline void remove_newline(char **head) 70{ 71again: 72 if (**head == '\n') { 73 *head = *head + 1; 74 goto again; 75 } 76} 77 78void f2fstat(struct options *opt) 79{ 80 int fd; 81 int ret; 82 char keyname[32]; 83 char buf[4096]; 84 struct mm_table key = { keyname, NULL }; 85 struct mm_table *found; 86 int f2fstat_table_cnt; 87 char *head, *tail; 88 int found_cnt = 0; 89 90 static struct mm_table f2fstat_table[] = { 91 { " - Data", &used_data_blks, 0 }, 92 { " - Dirty", &dirty_segs, 0 }, 93 { " - Free", &free_segs, 0 }, 94 { " - NATs", &nat_caches, 0 }, 95 { " - Node", &used_node_blks, 0 }, 96 { " - Prefree", &prefree_segs, 0 }, 97 { " - SITs", &dirty_sit, 0 }, 98 { " - Valid", &valid_segs, 0 }, 99 { " - dents", &dirty_dents, 0 }, 100 { " - meta", &dirty_meta, KEY_META }, 101 { " - nodes", &dirty_node, KEY_NODE }, 102 { "GC calls", &gc, 0 }, 103 { "LFS", &lfs_blks, 0 }, 104 { "Memory", &memory_kb, 0 }, 105 { "SSR", &ssr_blks, 0 }, 106 { "Utilization", &util, 0 }, 107 }; 108 109 f2fstat_table_cnt = sizeof(f2fstat_table)/sizeof(struct mm_table); 110 111 fd = open(F2FS_STATUS, O_RDONLY); 112 if (fd < 0) { 113 perror("open " F2FS_STATUS); 114 exit(EXIT_FAILURE); 115 } 116 117 ret = read(fd, buf, 4096); 118 if (ret < 0) { 119 perror("read " F2FS_STATUS); 120 exit(EXIT_FAILURE); 121 } 122 buf[ret] = '\0'; 123 124 head = buf; 125 126 if (opt->partname[0] != '\0') { 127 head = strstr(buf, opt->partname); 128 if (head == NULL) 129 exit(EXIT_FAILURE); 130 } 131 132 for (;;) { 133 remove_newline(&head); 134 tail = strchr(head, ':'); 135 if (!tail) 136 break; 137 *tail = '\0'; 138 if (strlen(head) >= sizeof(keyname)) { 139 dbg("[OVER] %s\n", head); 140 *tail = ':'; 141 tail = strchr(head, '\n'); 142 head = tail + 1; 143 continue; 144 } 145 146 strcpy(keyname, head); 147 148 found = bsearch(&key, f2fstat_table, f2fstat_table_cnt, sizeof(struct mm_table), compare_mm_table); 149 dbg("[RESULT] %s (%s)\n", head, (found) ? "O" : "X"); 150 head = tail + 1; 151 if (!found) 152 goto nextline; 153 154 *(found->val) = strtoul(head, &tail, 10); 155 if (found->flag) { 156 int npages; 157 tail = strstr(head, "in"); 158 head = tail + 2; 159 npages = strtoul(head, &tail, 10); 160 switch (found->flag & (KEY_NODE | KEY_META)) { 161 case KEY_NODE: 162 node_kb = npages * 4; 163 break; 164 case KEY_META: 165 meta_kb = npages * 4; 166 break; 167 } 168 } 169 if (++found_cnt == f2fstat_table_cnt) 170 break; 171nextline: 172 tail = strchr(head, '\n'); 173 if (!tail) 174 break; 175 head = tail + 1; 176 } 177 178 close(fd); 179} 180 181void usage(void) 182{ 183 printf("Usage: f2fstat [option]\n" 184 " -d delay (secs)\n" 185 " -i interval of head info\n" 186 " -p partition name (e.g. /dev/sda3)\n"); 187 exit(EXIT_FAILURE); 188} 189 190void parse_option(int argc, char *argv[], struct options *opt) 191{ 192 char option; 193 const char *option_string = "d:i:p:h"; 194 195 while ((option = getopt(argc, argv, option_string)) != EOF) { 196 switch (option) { 197 case 'd': 198 opt->delay = atoi(optarg); 199 break; 200 case 'i': 201 opt->interval = atoi(optarg); 202 break; 203 case 'p': 204 strcpy(opt->partname, basename(optarg)); 205 break; 206 default: 207 usage(); 208 break; 209 } 210 } 211} 212 213void print_head(void) 214{ 215 fprintf(stderr, "---utilization--- -----------main area-------- ---balancing async-- -gc- ---alloc--- -----memory-----\n"); 216 fprintf(stderr, "util node data free valid dirty prefree node dent meta sit gc ssr lfs total node meta\n"); 217} 218 219int main(int argc, char *argv[]) 220{ 221 char format[] = "%3ld %6ld %6ld %6ld %6ld %6ld %6ld %5ld %5ld %3ld %3ld %5ld %6ld %6ld %6ld %6ld %6ld\n"; 222 int head_interval; 223 struct options opt = { 224 .delay = 1, 225 .interval = 20, 226 .partname = { 0, }, 227 }; 228 229 parse_option(argc, argv, &opt); 230 head_interval = opt.interval; 231 232 print_head(); 233 while (1) { 234 if (head_interval-- == 0) { 235 print_head(); 236 head_interval = opt.interval; 237 } 238 239 f2fstat(&opt); 240 241 fprintf(stderr, format, util, used_node_blks, used_data_blks, 242 free_segs, valid_segs, dirty_segs, prefree_segs, 243 dirty_node, dirty_dents, dirty_meta, dirty_sit, 244 gc, ssr_blks, lfs_blks, memory_kb, node_kb, meta_kb); 245 246 sleep(opt.delay); 247 } 248 249 return 0; 250} 251