| 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;
|
| +}
|
|
|