diff options
author | primiano@chromium.org <primiano@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-07 14:28:40 +0000 |
---|---|---|
committer | primiano@chromium.org <primiano@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-07 14:28:40 +0000 |
commit | 857a91e9c53d64f522efefdbc6952b7244599fa0 (patch) | |
tree | d791105d0315e54d665a9dde46b9a2631513a966 /tools/android | |
parent | 62c731445653227c03428878d15c229cf942310f (diff) | |
download | chromium_src-857a91e9c53d64f522efefdbc6952b7244599fa0.zip chromium_src-857a91e9c53d64f522efefdbc6952b7244599fa0.tar.gz chromium_src-857a91e9c53d64f522efefdbc6952b7244599fa0.tar.bz2 |
[Android] Add ps_ext tool for tools-friendly cpu/mem/proc stats.
ps_ext is a simple ps-like tool, which generates a JSON dump containing
OS and processes stats. It is intended to be used by other tools, in
particular by the new memory_inspector (see related bug).
BUG=340294
R=pliard@chromium.org
Review URL: https://codereview.chromium.org/146803007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@249686 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'tools/android')
-rw-r--r-- | tools/android/android_tools.gyp | 7 | ||||
-rw-r--r-- | tools/android/ps_ext/ps_ext.c | 189 | ||||
-rw-r--r-- | tools/android/ps_ext/ps_ext.gyp | 28 |
3 files changed, 224 insertions, 0 deletions
diff --git a/tools/android/android_tools.gyp b/tools/android/android_tools.gyp index b780428..b330cde 100644 --- a/tools/android/android_tools.gyp +++ b/tools/android/android_tools.gyp @@ -31,5 +31,12 @@ 'memconsumer/memconsumer.gyp:memconsumer', ], }, + { + 'target_name': 'ps_ext', + 'type': 'none', + 'dependencies': [ + 'ps_ext/ps_ext.gyp:ps_ext', + ], + }, ], } diff --git a/tools/android/ps_ext/ps_ext.c b/tools/android/ps_ext/ps_ext.c new file mode 100644 index 0000000..caf6d88 --- /dev/null +++ b/tools/android/ps_ext/ps_ext.c @@ -0,0 +1,189 @@ +/* + * Copyright 2014 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include <dirent.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +/* + * This tool is essentially an extended version of ps with JSON output. + * Its output is meant consumed by scripts / tools for gathering OS/ps stats. + * Output units: + * All times are expressed in ticks. + * All memory counters are expressed in Kb. + */ + +#define CONV_PAGES_TO_KB(x) (x << (PAGE_SHIFT - 10)) + +static void dump_time(void) { + struct timespec tm = {0, 0}; + const long rate = sysconf(_SC_CLK_TCK); + clock_gettime(CLOCK_MONOTONIC, &tm); + const long ticks = rate * (tm.tv_sec * 1000L + tm.tv_nsec / 1000000) / 1000; + printf(" \"time\": { \"ticks\": %d, \"rate\": %d}", ticks, rate); +} + +static void dump_cpu_stats(void) { + FILE *f = fopen("/proc/stat", "r"); + if (!f) + return; + printf(" \"cpu\":\n [\n"); + + bool terminate_prev_line = false; + while (!feof(f)) { + char line[256]; + char cpu[8]; + long unsigned t_usr = 0; + long unsigned t_nice = 0; + long unsigned t_sys = 0; + long unsigned t_idle = 0; + fgets(line, sizeof(line), f); + + /* Skip the total 'cpu ' line and the other irrelevant ones. */ + if (strncmp(line, "cpu", 3) != 0 || line[3] == ' ') + continue; + if (sscanf(line, "%s %lu %lu %lu %lu", + cpu, &t_usr, &t_nice, &t_sys, &t_idle) != 5) { + continue; + } + + if (terminate_prev_line) + printf(",\n"); + terminate_prev_line = true; + printf(" {\"usr\": %lu, \"sys\": %lu, \"idle\": %lu}", + t_usr + t_nice, t_sys, t_idle); + } + fclose(f); + printf("\n ]"); +} + +static void dump_mem_stats(void) { + FILE *f = fopen("/proc/meminfo", "r"); + if (!f) + return; + printf(" \"mem\":\n {\n"); + + bool terminate_prev_line = false; + while (!feof(f)) { + char line[256]; + char key[32]; + long value = 0; + + fgets(line, sizeof(line), f); + if (sscanf(line, "%s %lu %*s", key, &value) < 2) + continue; + + if (terminate_prev_line) + printf(",\n"); + terminate_prev_line = true; + printf(" \"%s\": %lu", key, value); + } + fclose(f); + printf("\n }"); +} + +static void dump_proc_stats(void) { + struct dirent *de; + DIR *d = opendir("/proc"); + if (!d) + return; + + bool terminate_prev_line = false; + printf(" \"processes\":\n [\n"); + while ((de = readdir(d))) { + if (!isdigit(de->d_name[0])) + continue; + const int pid = atoi(de->d_name); + + /* Don't print out ourselves (how civilized). */ + if (pid == getpid()) + continue; + + char cmdline[64]; + char fpath[32]; + FILE *f; + + /* Read full process path / package from cmdline. */ + sprintf(fpath, "/proc/%d/cmdline", pid); + f = fopen(fpath, "r"); + if (!f) + continue; + cmdline[0] = '\0'; + fgets(cmdline, sizeof(cmdline), f); + fclose(f); + + /* Read cpu/io/mem stats. */ + char proc_name[256]; + long num_threads = 0; + long unsigned min_faults = 0; + long unsigned maj_faults = 0; + long unsigned utime = 0; + long unsigned ktime = 0; + long unsigned vm_rss = 0; + long long unsigned start_time = 0; + + sprintf(fpath, "/proc/%d/stat", pid); + f = fopen(fpath, "r"); + if (!f) + continue; + fscanf(f, "%*d %s %*c %*d %*d %*d %*d %*d %*u %lu %*lu %lu %*lu %lu %lu " + "%*ld %*ld %*ld %*ld %ld %*ld %llu %*lu %ld", proc_name, &min_faults, + &maj_faults, &utime, &ktime, &num_threads, &start_time, &vm_rss); + fclose(f); + + /* Prefer the cmdline when available, since it contains the package name. */ + char const * const cmd = (strlen(cmdline) > 0) ? cmdline : proc_name; + + if (terminate_prev_line) + printf(",\n"); + terminate_prev_line = true; + printf(" {" + "\"pid\": %d, " + "\"name\": \"%s\", " + "\"n_threads\": %ld, " + "\"start_time\": %llu, " + "\"user_time\": %lu, " + "\"sys_time\": %lu, " + "\"min_faults\": %lu, " + "\"maj_faults\": %lu, " + "\"vm_rss\": %lu" + "}", + pid, + cmd, + num_threads, + start_time, + utime, + ktime, + min_faults, + maj_faults, + CONV_PAGES_TO_KB(vm_rss)); + } + closedir(d); + printf("\n ]"); +} + +int main() +{ + printf("{\n"); + + dump_time(); + printf(",\n"); + + dump_mem_stats(); + printf(",\n"); + + dump_cpu_stats(); + printf(",\n"); + + dump_proc_stats(); + printf("\n}\n"); + + return 0; +} diff --git a/tools/android/ps_ext/ps_ext.gyp b/tools/android/ps_ext/ps_ext.gyp new file mode 100644 index 0000000..f1a24fe --- /dev/null +++ b/tools/android/ps_ext/ps_ext.gyp @@ -0,0 +1,28 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +{ + 'targets': [ + { + 'target_name': 'ps_ext', + 'type': 'executable', + 'conditions': [ + # Warning: A PIE tool cannot run on ICS 4.0.4, so only + # build it as position-independent when ASAN + # is activated. See b/6587214 for details. + [ 'asan==1', { + 'cflags': [ + '-fPIE', + ], + 'ldflags': [ + '-pie', + ], + }], + ], + 'sources': [ + 'ps_ext.c', + ], + }, + ], +} |