From 326842fca4883f1256aa9ed019bb3206ee76fca7 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Thu, 30 Apr 2015 09:49:41 -0700 Subject: dumpstate: report per-partition MMC performance (Cherry pick from commit 540e3de99fa1baa5eaf3eb3d49f4e98fd9f5bd91) Change-Id: If5cabe186d8377056effa1c0672a90e277cd7221 --- cmds/dumpstate/dumpstate.c | 63 +++++++++++++++++++++++++++++++++++++++++- cmds/dumpstate/dumpstate.h | 10 +++++++ cmds/dumpstate/utils.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+), 1 deletion(-) (limited to 'cmds') diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c index 7668a6c..95c49cf 100644 --- a/cmds/dumpstate/dumpstate.c +++ b/cmds/dumpstate/dumpstate.c @@ -99,6 +99,67 @@ static void dump_dev_files(const char *title, const char *driverpath, const char closedir(d); } +static bool skip_not_stat(const char *path) { + static const char stat[] = "/stat"; + size_t len = strlen(path); + if (path[len - 1] == '/') { /* Directory? */ + return false; + } + return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */ +} + +static const char mmcblk0[] = "/sys/block/mmcblk0/"; + +static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) { + unsigned long fields[11], read_perf, write_perf; + bool z; + char *cp, *buffer = NULL; + size_t i = 0; + FILE *fp = fdopen(fd, "rb"); + getline(&buffer, &i, fp); + fclose(fp); + if (!buffer) { + return -errno; + } + i = strlen(buffer); + while ((i > 0) && (buffer[i - 1] == '\n')) { + buffer[--i] = '\0'; + } + if (!*buffer) { + free(buffer); + return 0; + } + z = true; + for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) { + fields[i] = strtol(cp, &cp, 0); + if (fields[i] != 0) { + z = false; + } + } + if (z) { /* never accessed */ + free(buffer); + return 0; + } + + if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) { + path += sizeof(mmcblk0) - 1; + } + + printf("%s: %s\n", path, buffer); + free(buffer); + + read_perf = 0; + if (fields[3]) { + read_perf = 512 * fields[2] / fields[3]; + } + write_perf = 0; + if (fields[7]) { + write_perf = 512 * fields[6] / fields[7]; + } + printf("%s: read: %luKB/s write: %luKB/s\n", path, read_perf, write_perf); + return 0; +} + /* dumps the current system state to stdout */ static void dumpstate() { time_t now = time(NULL); @@ -133,7 +194,7 @@ static void dumpstate() { dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version"); run_command("UPTIME", 10, "uptime", NULL); - dump_file("MMC PERF", "/sys/block/mmcblk0/stat"); + dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd); dump_file("MEMORY INFO", "/proc/meminfo"); run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-t", NULL); run_command("PROCRANK", 20, "procrank", NULL); diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 8335e26..c5d3044 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -35,6 +35,16 @@ int dump_file(const char *title, const char *path); */ int dump_file_from_fd(const char *title, const char *path, int fd); +/* calls skip to gate calling dump_from_fd recursively + * in the specified directory. dump_from_fd defaults to + * dump_file_from_fd above when set to NULL. skip defaults + * to false when set to NULL. dump_from_fd will always be + * called with title NULL. + */ +int dump_files(const char *title, const char *dir, + bool (*skip)(const char *path), + int (*dump_from_fd)(const char *title, const char *path, int fd)); + /* forks a command and waits for it to finish -- terminate args with NULL */ int run_command(const char *title, int timeout_seconds, const char *command, ...); diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c index 3d9a2b5..5801de1 100644 --- a/cmds/dumpstate/utils.c +++ b/cmds/dumpstate/utils.c @@ -310,6 +310,75 @@ int dump_file(const char *title, const char *path) { return _dump_file_from_fd(title, path, fd); } +/* calls skip to gate calling dump_from_fd recursively + * in the specified directory. dump_from_fd defaults to + * dump_file_from_fd above when set to NULL. skip defaults + * to false when set to NULL. dump_from_fd will always be + * called with title NULL. + */ +int dump_files(const char *title, const char *dir, + bool (*skip)(const char *path), + int (*dump_from_fd)(const char *title, const char *path, int fd)) { + DIR *dirp; + struct dirent *d; + char *newpath = NULL; + char *slash = "/"; + int fd, retval = 0; + + if (title) { + printf("------ %s (%s) ------\n", title, dir); + } + + if (dir[strlen(dir) - 1] == '/') { + ++slash; + } + dirp = opendir(dir); + if (dirp == NULL) { + retval = -errno; + fprintf(stderr, "%s: %s\n", dir, strerror(errno)); + return retval; + } + + if (!dump_from_fd) { + dump_from_fd = dump_file_from_fd; + } + for (; ((d = readdir(dirp))); free(newpath), newpath = NULL) { + if ((d->d_name[0] == '.') + && (((d->d_name[1] == '.') && (d->d_name[2] == '\0')) + || (d->d_name[1] == '\0'))) { + continue; + } + asprintf(&newpath, "%s%s%s%s", dir, slash, d->d_name, + (d->d_type == DT_DIR) ? "/" : ""); + if (!newpath) { + retval = -errno; + continue; + } + if (skip && (*skip)(newpath)) { + continue; + } + if (d->d_type == DT_DIR) { + int ret = dump_files(NULL, newpath, skip, dump_from_fd); + if (ret < 0) { + retval = ret; + } + continue; + } + fd = TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC)); + if (fd < 0) { + retval = fd; + printf("*** %s: %s\n", newpath, strerror(errno)); + continue; + } + (*dump_from_fd)(NULL, newpath, fd); + } + closedir(dirp); + if (title) { + printf("\n"); + } + return retval; +} + /* fd must have been opened with the flag O_NONBLOCK. With this flag set, * it's possible to avoid issues where opening the file itself can get * stuck. -- cgit v1.1