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