Home | History | Annotate | Download | only in tools
      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