aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk@motorola.com>2014-12-19 16:05:10 -0800
committerJP Abgrall <jpa@google.com>2015-03-23 10:10:26 -0700
commit744352418daf27a99d73649d8d22b315ceafcd34 (patch)
tree41b976a63183621236239af2384d1f8ba1315c6a
parentc511d5d0ec5290dbf1e4e1bc8afc8ddd8feac4c4 (diff)
downloadandroid_external_f2fs-tools-744352418daf27a99d73649d8d22b315ceafcd34.tar.gz
android_external_f2fs-tools-744352418daf27a99d73649d8d22b315ceafcd34.tar.bz2
android_external_f2fs-tools-744352418daf27a99d73649d8d22b315ceafcd34.zip
parse.f2fs: add a tool to parse IO traces made by runtime f2fs
This patch adds parse.f2fs to retrieve process information and an amount of data reads and writes from given IO trace got by f2fs. Signed-off-by: Jaegeuk Kim <jaegeuk@motorola.com>
-rw-r--r--tools/Makefile.am3
-rw-r--r--tools/f2fs_io_parse.c322
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;
+}