1 /* 2 * f2fs IO tracer 3 * 4 * Copyright (c) 2014 Motorola Mobility 5 * Copyright (c) 2014 Jaegeuk Kim <jaegeuk (at) kernel.org> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 #define _LARGEFILE64_SOURCE 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <unistd.h> 15 #include <string.h> 16 #include <sys/queue.h> 17 #include <assert.h> 18 #include <locale.h> 19 20 #define P_NAMELEN 16 21 22 /* For global trace methods */ 23 enum show_type { 24 SHOW_PID, 25 SHOW_FTYPE, 26 SHOW_ALL, 27 }; 28 29 enum trace_types { 30 TP_PID, 31 TP_IOS, 32 TP_MAX, 33 }; 34 35 struct tps { 36 enum trace_types type; 37 const char *name; 38 }; 39 40 struct tps trace_points[] = { 41 { TP_PID, "f2fs_trace_pid" }, 42 { TP_IOS, "f2fs_trace_ios" }, 43 }; 44 45 /* For f2fs_trace_pid and f2fs_trace_ios */ 46 enum rw_type { 47 READ, 48 WRITE, 49 MAX_RW, 50 }; 51 52 enum file_type { 53 __NORMAL_FILE, 54 __DIR_FILE, 55 __NODE_FILE, 56 __META_FILE, 57 __ATOMIC_FILE, 58 __VOLATILE_FILE, 59 __MISC_FILE, 60 __NR_FILES, 61 }; 62 63 char *file_type_string[] = { 64 "User ", 65 "Dir ", 66 "Node ", 67 "Meta ", 68 "Atomic ", 69 "Voltile ", 70 "Misc ", 71 }; 72 73 struct pid_ent { 74 int pid; 75 char name[P_NAMELEN]; 76 unsigned long long io[__NR_FILES][MAX_RW]; 77 unsigned long long total_io[MAX_RW]; 78 LIST_ENTRY(pid_ent) ptr; 79 }; 80 81 /* global variables */ 82 int major = 0, minor = 0; 83 int show_option = SHOW_ALL; 84 unsigned long long total_io[__NR_FILES][MAX_RW]; 85 86 LIST_HEAD(plist, pid_ent) pid_info; 87 88 /* Functions */ 89 static inline int atoh(char *str) 90 { 91 int val; 92 sscanf(str, "%x", &val); 93 return val; 94 } 95 96 static void do_init() 97 { 98 struct pid_ent *misc; 99 100 misc = calloc(1, sizeof(struct pid_ent)); 101 assert(misc); 102 103 LIST_INIT(&pid_info); 104 LIST_INSERT_HEAD(&pid_info, misc, ptr); 105 } 106 107 void show_usage() 108 { 109 printf("\nUsage: parse.f2fs [options] log_file\n"); 110 printf("[options]:\n"); 111 printf(" -a RW sorted by pid & file types\n"); 112 printf(" -f RW sorted by file types\n"); 113 printf(" -p RW sorted by pid\n"); 114 printf(" -m major number\n"); 115 printf(" -n minor number\n"); 116 exit(1); 117 } 118 119 static int parse_options(int argc, char *argv[]) 120 { 121 const char *option_string = "fm:n:p"; 122 int option = 0; 123 124 while ((option = getopt(argc, argv, option_string)) != EOF) { 125 switch (option) { 126 case 'f': 127 show_option = SHOW_FTYPE; 128 break; 129 case 'm': 130 major = atoh(optarg); 131 break; 132 case 'n': 133 minor = atoh(optarg); 134 break; 135 case 'p': 136 show_option = SHOW_PID; 137 break; 138 default: 139 printf("\tError: Unknown option %c\n", option); 140 show_usage(); 141 break; 142 } 143 } 144 if ((optind + 1) != argc) { 145 printf("\tError: Log file is not specified.\n"); 146 show_usage(); 147 } 148 return optind; 149 } 150 151 struct pid_ent *get_pid_entry(int pid) 152 { 153 struct pid_ent *entry; 154 155 LIST_FOREACH(entry, &pid_info, ptr) { 156 if (entry->pid == pid) 157 return entry; 158 } 159 return LIST_FIRST(&pid_info); 160 } 161 162 static void handle_tp_pid(char *ptr) 163 { 164 struct pid_ent *pent; 165 166 pent = calloc(1, sizeof(struct pid_ent)); 167 assert(pent); 168 169 ptr = strtok(NULL, " "); 170 pent->pid = atoh(ptr); 171 172 ptr = strtok(NULL, " "); 173 strcpy(pent->name, ptr); 174 175 LIST_INSERT_HEAD(&pid_info, pent, ptr); 176 } 177 178 static void handle_tp_ios(char *ptr) 179 { 180 int pid, type, rw, len; 181 struct pid_ent *p; 182 183 ptr = strtok(NULL, " "); 184 pid = atoh(ptr); 185 186 ptr = strtok(NULL, " "); 187 ptr = strtok(NULL, " "); 188 type = atoh(ptr); 189 190 ptr = strtok(NULL, " "); 191 rw = atoh(ptr); 192 193 ptr = strtok(NULL, " "); 194 /* int op_flags = atoh(ptr) */ 195 ptr = strtok(NULL, " "); 196 /* unsigned long long blkaddr = atoh(ptr); */ 197 198 ptr = strtok(NULL, " "); 199 len = atoh(ptr); 200 201 /* update per-pid stat */ 202 p = get_pid_entry(pid); 203 p->io[type][rw & 0x1] += len; 204 p->total_io[rw & 0x1] += len; 205 206 /* update total stat */ 207 total_io[type][rw & 0x1] += len; 208 } 209 210 static void do_parse(FILE *file) 211 { 212 char line[300]; 213 char *ptr; 214 int i; 215 216 while (fgets(line, sizeof(line), file) != NULL) { 217 ptr = strtok(line, ":"); 218 219 ptr = strtok(NULL, " :"); 220 221 for (i = 0; i < TP_MAX; i++) { 222 if (!strcmp(ptr, trace_points[i].name)) 223 break; 224 } 225 if (i == TP_MAX) 226 continue; 227 ptr = strtok(NULL, " :"); 228 if (major && major != atoh(ptr)) 229 continue; 230 ptr = strtok(NULL, " :"); 231 if (minor && minor != atoh(ptr)) 232 continue; 233 234 switch (i) { 235 case TP_PID: 236 handle_tp_pid(ptr); 237 break; 238 case TP_IOS: 239 handle_tp_ios(ptr); 240 break; 241 } 242 } 243 } 244 245 static void __print_pid() 246 { 247 struct pid_ent *entry; 248 int i; 249 250 setlocale(LC_ALL, ""); 251 printf("%8s %16s %17s ||", "PID", "NAME", "R/W in 4KB"); 252 for (i = 0; i < __NR_FILES; i++) 253 printf(" %17s |", file_type_string[i]); 254 printf("\n"); 255 256 LIST_FOREACH(entry, &pid_info, ptr) { 257 printf("%8x %16s %'8lld %'8lld ||", 258 entry->pid, entry->name, 259 entry->total_io[READ], 260 entry->total_io[WRITE]); 261 for (i = 0; i < __NR_FILES; i++) 262 printf(" %'8lld %'8lld |", 263 entry->io[i][READ], 264 entry->io[i][WRITE]); 265 printf("\n"); 266 } 267 } 268 269 static void __print_ftype() 270 { 271 int i; 272 273 setlocale(LC_ALL, ""); 274 printf("\n===== Data R/W in 4KB accoring to File types =====\n"); 275 for (i = 0; i < __NR_FILES; i++) 276 printf(" %17s |", file_type_string[i]); 277 printf("\n"); 278 279 for (i = 0; i < __NR_FILES; i++) 280 printf(" %'8lld %'8lld |", 281 total_io[i][READ], 282 total_io[i][WRITE]); 283 printf("\n"); 284 } 285 286 static void do_print() 287 { 288 switch (show_option) { 289 case SHOW_PID: 290 __print_pid(); 291 break; 292 case SHOW_FTYPE: 293 __print_ftype(); 294 break; 295 case SHOW_ALL: 296 __print_pid(); 297 printf("\n\n"); 298 __print_ftype(); 299 break; 300 } 301 } 302 303 int main(int argc, char **argv) 304 { 305 FILE *file; 306 int opt; 307 308 opt = parse_options(argc, argv); 309 310 file = fopen(argv[opt], "r"); 311 if (!file) { 312 perror("open log file"); 313 exit(EXIT_FAILURE); 314 } 315 316 do_init(); 317 318 do_parse(file); 319 320 do_print(); 321 322 fclose(file); 323 return 0; 324 } 325