diff options
author | Jaegeuk Kim <jaegeuk@motorola.com> | 2015-03-24 02:57:50 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2015-03-24 02:57:50 +0000 |
commit | 988eb658633d0fe1cadbb71d96343300cd462453 (patch) | |
tree | 41b976a63183621236239af2384d1f8ba1315c6a | |
parent | 0e01ed60eb8f845db5728d2c24d87be5f5f0c3ca (diff) | |
parent | 744352418daf27a99d73649d8d22b315ceafcd34 (diff) | |
download | f2fs-tools-988eb658633d0fe1cadbb71d96343300cd462453.tar.gz |
am 74435241: parse.f2fs: add a tool to parse IO traces made by runtime f2fs
* commit '744352418daf27a99d73649d8d22b315ceafcd34':
parse.f2fs: add a tool to parse IO traces made by runtime f2fs
-rw-r--r-- | tools/Makefile.am | 3 | ||||
-rw-r--r-- | tools/f2fs_io_parse.c | 322 |
2 files changed, 324 insertions, 1 deletions
diff --git a/tools/Makefile.am b/tools/Makefile.am index 1ead174..69a0bb1 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -2,6 +2,7 @@ AM_CPPFLAGS = ${libuuid_CFLAGS} -I$(top_srcdir)/include AM_CFLAGS = -Wall -sbin_PROGRAMS = f2fstat fibmap.f2fs +sbin_PROGRAMS = f2fstat fibmap.f2fs parse.f2fs f2fstat_SOURCES = f2fstat.c fibmap_f2fs_SOURCES = fibmap.c +parse_f2fs_SOURCES = f2fs_io_parse.c diff --git a/tools/f2fs_io_parse.c b/tools/f2fs_io_parse.c new file mode 100644 index 0000000..7f97270 --- /dev/null +++ b/tools/f2fs_io_parse.c @@ -0,0 +1,322 @@ +/* + * f2fs IO tracer + * + * Copyright (c) 2014 Motorola Mobility + * Copyright (c) 2014 Jaegeuk Kim <jaegeuk@kernel.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#define _LARGEFILE64_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/queue.h> +#include <assert.h> +#include <locale.h> + +#define P_NAMELEN 16 + +/* For global trace methods */ +enum show_type { + SHOW_PID, + SHOW_FTYPE, + SHOW_ALL, +}; + +enum trace_types { + TP_PID, + TP_IOS, + TP_MAX, +}; + +struct tps { + enum trace_types type; + const char *name; +}; + +struct tps trace_points[] = { + { TP_PID, "f2fs_trace_pid" }, + { TP_IOS, "f2fs_trace_ios" }, +}; + +/* For f2fs_trace_pid and f2fs_trace_ios */ +enum rw_type { + READ, + WRITE, + MAX_RW, +}; + +enum file_type { + __NORMAL_FILE, + __DIR_FILE, + __NODE_FILE, + __META_FILE, + __ATOMIC_FILE, + __VOLATILE_FILE, + __MISC_FILE, + __NR_FILES, +}; + +char *file_type_string[] = { + "User ", + "Dir ", + "Node ", + "Meta ", + "Atomic ", + "Voltile ", + "Misc ", +}; + +struct pid_ent { + int pid; + char name[P_NAMELEN]; + unsigned long long io[__NR_FILES][MAX_RW]; + unsigned long long total_io[MAX_RW]; + LIST_ENTRY(pid_ent) ptr; +}; + +/* global variables */ +int major = 0, minor = 0; +int show_option = SHOW_ALL; +unsigned long long total_io[__NR_FILES][MAX_RW]; + +LIST_HEAD(plist, pid_ent) pid_info; + +/* Functions */ +static inline int atoh(char *str) +{ + int val; + sscanf(str, "%x", &val); + return val; +} + +static void do_init() +{ + struct pid_ent *misc; + + misc = calloc(1, sizeof(struct pid_ent)); + assert(misc); + + LIST_INIT(&pid_info); + LIST_INSERT_HEAD(&pid_info, misc, ptr); +} + +void show_usage() +{ + printf("\nUsage: parse.f2fs [options] log_file\n"); + printf("[options]:\n"); + printf(" -a RW sorted by pid & file types\n"); + printf(" -f RW sorted by file types\n"); + printf(" -p RW sorted by pid\n"); + printf(" -m major number\n"); + printf(" -n minor number\n"); + exit(1); +} + +static int parse_options(int argc, char *argv[]) +{ + const char *option_string = "fm:n:p"; + int option = 0; + + while ((option = getopt(argc, argv, option_string)) != EOF) { + switch (option) { + case 'f': + show_option = SHOW_FTYPE; + break; + case 'm': + major = atoh(optarg); + break; + case 'n': + minor = atoh(optarg); + break; + case 'p': + show_option = SHOW_PID; + break; + default: + printf("\tError: Unknown option %c\n", option); + show_usage(); + break; + } + } + if ((optind + 1) != argc) { + printf("\tError: Log file is not specified.\n"); + show_usage(); + } + return optind; +} + +struct pid_ent *get_pid_entry(int pid) +{ + struct pid_ent *entry; + + LIST_FOREACH(entry, &pid_info, ptr) { + if (entry->pid == pid) + return entry; + } + return LIST_FIRST(&pid_info); +} + +static void handle_tp_pid(char *ptr) +{ + struct pid_ent *pent; + + pent = calloc(1, sizeof(struct pid_ent)); + assert(pent); + + ptr = strtok(NULL, " "); + pent->pid = atoh(ptr); + + ptr = strtok(NULL, " "); + strcpy(pent->name, ptr); + + LIST_INSERT_HEAD(&pid_info, pent, ptr); +} + +static void handle_tp_ios(char *ptr) +{ + int pid, type, rw, len; + struct pid_ent *p; + + ptr = strtok(NULL, " "); + pid = atoh(ptr); + + ptr = strtok(NULL, " "); + ptr = strtok(NULL, " "); + type = atoh(ptr); + + ptr = strtok(NULL, " "); + rw = atoh(ptr); + + ptr = strtok(NULL, " "); + /* unsigned long long blkaddr = atoh(ptr); */ + + ptr = strtok(NULL, " "); + len = atoh(ptr); + + /* update per-pid stat */ + p = get_pid_entry(pid); + p->io[type][rw & 0x1] += len; + p->total_io[rw & 0x1] += len; + + /* update total stat */ + total_io[type][rw & 0x1] += len; +} + +static void do_parse(FILE *file) +{ + char line[300]; + char *ptr; + int i; + + while (fgets(line, sizeof(line), file) != NULL) { + ptr = strtok(line, ":"); + + ptr = strtok(NULL, " :"); + + for (i = 0; i < TP_MAX; i++) { + if (!strcmp(ptr, trace_points[i].name)) + break; + } + if (i == TP_MAX) + continue; + ptr = strtok(NULL, " :"); + if (major && major != atoh(ptr)) + continue; + ptr = strtok(NULL, " :"); + if (minor && minor != atoh(ptr)) + continue; + + switch (i) { + case TP_PID: + handle_tp_pid(ptr); + break; + case TP_IOS: + handle_tp_ios(ptr); + break; + } + } +} + +static void __print_pid() +{ + struct pid_ent *entry; + int i; + + setlocale(LC_ALL, ""); + printf("%8s %16s %17s ||", "PID", "NAME", "R/W in 4KB"); + for (i = 0; i < __NR_FILES; i++) + printf(" %17s |", file_type_string[i]); + printf("\n"); + + LIST_FOREACH(entry, &pid_info, ptr) { + printf("%8x %16s %'8lld %'8lld ||", + entry->pid, entry->name, + entry->total_io[READ], + entry->total_io[WRITE]); + for (i = 0; i < __NR_FILES; i++) + printf(" %'8lld %'8lld |", + entry->io[i][READ], + entry->io[i][WRITE]); + printf("\n"); + } +} + +static void __print_ftype() +{ + int i; + + setlocale(LC_ALL, ""); + printf("\n===== Data R/W in 4KB accoring to File types =====\n"); + for (i = 0; i < __NR_FILES; i++) + printf(" %17s |", file_type_string[i]); + printf("\n"); + + for (i = 0; i < __NR_FILES; i++) + printf(" %'8lld %'8lld |", + total_io[i][READ], + total_io[i][WRITE]); + printf("\n"); +} + +static void do_print() +{ + switch (show_option) { + case SHOW_PID: + __print_pid(); + break; + case SHOW_FTYPE: + __print_ftype(); + break; + case SHOW_ALL: + __print_pid(); + printf("\n\n"); + __print_ftype(); + break; + } +} + +int main(int argc, char **argv) +{ + FILE *file; + int opt; + + opt = parse_options(argc, argv); + + file = fopen(argv[opt], "r"); + if (!file) { + perror("open log file"); + exit(EXIT_FAILURE); + } + + do_init(); + + do_parse(file); + + do_print(); + + fclose(file); + return 0; +} |