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