1/* 2 * f2fs IO tracer 3 * 4 * Copyright (c) 2014 Motorola Mobility 5 * Copyright (c) 2014 Jaegeuk Kim <jaegeuk@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 */ 23enum show_type { 24 SHOW_PID, 25 SHOW_FTYPE, 26 SHOW_ALL, 27}; 28 29enum trace_types { 30 TP_PID, 31 TP_IOS, 32 TP_MAX, 33}; 34 35struct tps { 36 enum trace_types type; 37 const char *name; 38}; 39 40struct 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 */ 46enum rw_type { 47 READ, 48 WRITE, 49 MAX_RW, 50}; 51 52enum 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 63char *file_type_string[] = { 64 "User ", 65 "Dir ", 66 "Node ", 67 "Meta ", 68 "Atomic ", 69 "Voltile ", 70 "Misc ", 71}; 72 73struct 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 */ 82int major = 0, minor = 0; 83int show_option = SHOW_ALL; 84unsigned long long total_io[__NR_FILES][MAX_RW]; 85 86LIST_HEAD(plist, pid_ent) pid_info; 87 88/* Functions */ 89static inline int atoh(char *str) 90{ 91 int val; 92 sscanf(str, "%x", &val); 93 return val; 94} 95 96static 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 107void 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 119static 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 151struct 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 162static 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 178static 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 /* unsigned long long blkaddr = atoh(ptr); */ 195 196 ptr = strtok(NULL, " "); 197 len = atoh(ptr); 198 199 /* update per-pid stat */ 200 p = get_pid_entry(pid); 201 p->io[type][rw & 0x1] += len; 202 p->total_io[rw & 0x1] += len; 203 204 /* update total stat */ 205 total_io[type][rw & 0x1] += len; 206} 207 208static void do_parse(FILE *file) 209{ 210 char line[300]; 211 char *ptr; 212 int i; 213 214 while (fgets(line, sizeof(line), file) != NULL) { 215 ptr = strtok(line, ":"); 216 217 ptr = strtok(NULL, " :"); 218 219 for (i = 0; i < TP_MAX; i++) { 220 if (!strcmp(ptr, trace_points[i].name)) 221 break; 222 } 223 if (i == TP_MAX) 224 continue; 225 ptr = strtok(NULL, " :"); 226 if (major && major != atoh(ptr)) 227 continue; 228 ptr = strtok(NULL, " :"); 229 if (minor && minor != atoh(ptr)) 230 continue; 231 232 switch (i) { 233 case TP_PID: 234 handle_tp_pid(ptr); 235 break; 236 case TP_IOS: 237 handle_tp_ios(ptr); 238 break; 239 } 240 } 241} 242 243static void __print_pid() 244{ 245 struct pid_ent *entry; 246 int i; 247 248 setlocale(LC_ALL, ""); 249 printf("%8s %16s %17s ||", "PID", "NAME", "R/W in 4KB"); 250 for (i = 0; i < __NR_FILES; i++) 251 printf(" %17s |", file_type_string[i]); 252 printf("\n"); 253 254 LIST_FOREACH(entry, &pid_info, ptr) { 255 printf("%8x %16s %'8lld %'8lld ||", 256 entry->pid, entry->name, 257 entry->total_io[READ], 258 entry->total_io[WRITE]); 259 for (i = 0; i < __NR_FILES; i++) 260 printf(" %'8lld %'8lld |", 261 entry->io[i][READ], 262 entry->io[i][WRITE]); 263 printf("\n"); 264 } 265} 266 267static void __print_ftype() 268{ 269 int i; 270 271 setlocale(LC_ALL, ""); 272 printf("\n===== Data R/W in 4KB accoring to File types =====\n"); 273 for (i = 0; i < __NR_FILES; i++) 274 printf(" %17s |", file_type_string[i]); 275 printf("\n"); 276 277 for (i = 0; i < __NR_FILES; i++) 278 printf(" %'8lld %'8lld |", 279 total_io[i][READ], 280 total_io[i][WRITE]); 281 printf("\n"); 282} 283 284static void do_print() 285{ 286 switch (show_option) { 287 case SHOW_PID: 288 __print_pid(); 289 break; 290 case SHOW_FTYPE: 291 __print_ftype(); 292 break; 293 case SHOW_ALL: 294 __print_pid(); 295 printf("\n\n"); 296 __print_ftype(); 297 break; 298 } 299} 300 301int main(int argc, char **argv) 302{ 303 FILE *file; 304 int opt; 305 306 opt = parse_options(argc, argv); 307 308 file = fopen(argv[opt], "r"); 309 if (!file) { 310 perror("open log file"); 311 exit(EXIT_FAILURE); 312 } 313 314 do_init(); 315 316 do_parse(file); 317 318 do_print(); 319 320 fclose(file); 321 return 0; 322} 323