• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
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 */
atoh(char * str)89 static inline int atoh(char *str)
90 {
91 	int val;
92 	sscanf(str, "%x", &val);
93 	return val;
94 }
95 
do_init()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 
show_usage()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 
parse_options(int argc,char * argv[])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 
get_pid_entry(int pid)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 
handle_tp_pid(char * ptr)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 
handle_tp_ios(char * ptr)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 
do_parse(FILE * file)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 
__print_pid()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 
__print_ftype()269 static void __print_ftype()
270 {
271 	int i;
272 
273 	setlocale(LC_ALL, "");
274 	printf("\n===== Data R/W in 4KB according 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 
do_print()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 
main(int argc,char ** argv)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