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