Index: tools/android/ps_ext/ps_ext.c |
diff --git a/tools/android/ps_ext/ps_ext.c b/tools/android/ps_ext/ps_ext.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..06cf7bcff98cec8a35f3642f5629f59f29e25f12 |
--- /dev/null |
+++ b/tools/android/ps_ext/ps_ext.c |
@@ -0,0 +1,192 @@ |
+/* |
+ * 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 <ctype.h> |
+#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. |
+ */ |
+ |
+static void dump_time(void) { |
+ float uptime_secs = 0.0F; |
+ const long rate = sysconf(_SC_CLK_TCK); |
+ FILE *f = fopen("/proc/uptime", "r"); |
+ if (!f) |
+ return; |
+ fscanf(f, "%f", &uptime_secs); |
+ fclose(f); |
+ const long ticks = (long) (rate * uptime_secs); |
+ printf(" \"time\": { \"ticks\": %ld, \"rate\": %ld}", 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; |
+ |
+ const long kb_per_page = sysconf(_SC_PAGESIZE) / 1024; |
+ 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 %*u %lu %*u %lu %lu " |
+ "%*d %*d %*d %*d %ld %*d %llu %*u %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(" \"%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, |
+ vm_rss * kb_per_page); |
+ } |
+ 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; |
+} |