Home | History | Annotate | Download | only in ps_ext
      1 /*
      2  * Copyright 2014 The Chromium Authors. All rights reserved.
      3  * Use of this source code is governed by a BSD-style license that can be
      4  * found in the LICENSE file.
      5  */
      6 
      7 #include <ctype.h>
      8 #include <dirent.h>
      9 #include <stdbool.h>
     10 #include <stdio.h>
     11 #include <stdlib.h>
     12 #include <string.h>
     13 #include <time.h>
     14 #include <unistd.h>
     15 
     16 /*
     17  * This tool is essentially an extended version of ps with JSON output.
     18  * Its output is meant consumed by scripts / tools for gathering OS/ps stats.
     19  * Output units:
     20  *   All times are expressed in ticks.
     21  *   All memory counters are expressed in Kb.
     22  */
     23 
     24 static void dump_time(void) {
     25   float uptime_secs = 0.0F;
     26   const long rate = sysconf(_SC_CLK_TCK);
     27   FILE *f = fopen("/proc/uptime", "r");
     28   if (!f)
     29     return;
     30   fscanf(f, "%f", &uptime_secs);
     31   fclose(f);
     32   const long ticks = (long) (rate * uptime_secs);
     33   printf("  \"time\": { \"ticks\": %ld, \"rate\": %ld}", ticks, rate);
     34 }
     35 
     36 static void dump_cpu_stats(void) {
     37   FILE *f = fopen("/proc/stat", "r");
     38   if (!f)
     39     return;
     40   printf("  \"cpu\":\n  [\n");
     41 
     42   bool terminate_prev_line = false;
     43   while (!feof(f)) {
     44     char line[256];
     45     char cpu[8];
     46     long unsigned t_usr = 0;
     47     long unsigned t_nice = 0;
     48     long unsigned t_sys = 0;
     49     long unsigned t_idle = 0;
     50     fgets(line, sizeof(line), f);
     51 
     52     /* Skip the total 'cpu ' line and the other irrelevant ones. */
     53     if (strncmp(line, "cpu", 3) != 0 || line[3] == ' ')
     54       continue;
     55     if (sscanf(line, "%s %lu %lu %lu %lu",
     56                cpu, &t_usr, &t_nice, &t_sys, &t_idle) != 5) {
     57       continue;
     58     }
     59 
     60     if (terminate_prev_line)
     61       printf(",\n");
     62     terminate_prev_line = true;
     63     printf("    {\"usr\": %lu, \"sys\": %lu, \"idle\": %lu}",
     64            t_usr + t_nice, t_sys, t_idle);
     65   }
     66   fclose(f);
     67   printf("\n  ]");
     68 }
     69 
     70 static void dump_mem_stats(void) {
     71   FILE *f = fopen("/proc/meminfo", "r");
     72   if (!f)
     73     return;
     74   printf("  \"mem\":\n  {\n");
     75 
     76   bool terminate_prev_line = false;
     77   while (!feof(f)) {
     78     char line[256];
     79     char key[32];
     80     long value = 0;
     81 
     82     fgets(line, sizeof(line), f);
     83     if (sscanf(line, "%s %lu %*s", key, &value) < 2)
     84       continue;
     85 
     86     if (terminate_prev_line)
     87       printf(",\n");
     88     terminate_prev_line = true;
     89     printf("    \"%s\": %lu", key, value);
     90   }
     91   fclose(f);
     92   printf("\n  }");
     93 }
     94 
     95 static void dump_proc_stats(void) {
     96   struct dirent *de;
     97   DIR *d = opendir("/proc");
     98   if (!d)
     99     return;
    100 
    101   const long kb_per_page = sysconf(_SC_PAGESIZE) / 1024;
    102   bool terminate_prev_line = false;
    103   printf("  \"processes\":\n  {\n");
    104   while ((de = readdir(d))) {
    105     if (!isdigit(de->d_name[0]))
    106       continue;
    107     const int pid = atoi(de->d_name);
    108 
    109     /* Don't print out ourselves (how civilized). */
    110     if (pid == getpid())
    111       continue;
    112 
    113     char cmdline[64];
    114     char fpath[32];
    115     FILE *f;
    116 
    117     /* Read full process path / package from cmdline. */
    118     sprintf(fpath, "/proc/%d/cmdline", pid);
    119     f = fopen(fpath, "r");
    120     if (!f)
    121       continue;
    122     cmdline[0] = '\0';
    123     fgets(cmdline, sizeof(cmdline), f);
    124     fclose(f);
    125 
    126     /* Read cpu/io/mem stats. */
    127     char proc_name[256];
    128     long num_threads = 0;
    129     long unsigned min_faults = 0;
    130     long unsigned maj_faults = 0;
    131     long unsigned utime = 0;
    132     long unsigned ktime = 0;
    133     long unsigned vm_rss = 0;
    134     long long unsigned start_time = 0;
    135 
    136     sprintf(fpath, "/proc/%d/stat", pid);
    137     f = fopen(fpath, "r");
    138     if (!f)
    139       continue;
    140     fscanf(f, "%*d %s %*c %*d %*d %*d %*d %*d %*u %lu %*u %lu %*u %lu %lu "
    141            "%*d %*d %*d %*d %ld %*d %llu %*u %ld", proc_name, &min_faults,
    142            &maj_faults, &utime, &ktime, &num_threads, &start_time, &vm_rss);
    143     fclose(f);
    144 
    145     /* Prefer the cmdline when available, since it contains the package name. */
    146     char const * const cmd = (strlen(cmdline) > 0) ? cmdline : proc_name;
    147 
    148     if (terminate_prev_line)
    149       printf(",\n");
    150     terminate_prev_line = true;
    151     printf("   \"%d\": {"
    152            "\"name\": \"%s\", "
    153            "\"n_threads\": %ld, "
    154            "\"start_time\": %llu, "
    155            "\"user_time\": %lu, "
    156            "\"sys_time\": %lu, "
    157            "\"min_faults\": %lu, "
    158            "\"maj_faults\": %lu, "
    159            "\"vm_rss\": %lu"
    160            "}",
    161            pid,
    162            cmd,
    163            num_threads,
    164            start_time,
    165            utime,
    166            ktime,
    167            min_faults,
    168            maj_faults,
    169            vm_rss * kb_per_page);
    170   }
    171   closedir(d);
    172   printf("\n  }");
    173 }
    174 
    175 int main()
    176 {
    177   printf("{\n");
    178 
    179   dump_time();
    180   printf(",\n");
    181 
    182   dump_mem_stats();
    183   printf(",\n");
    184 
    185   dump_cpu_stats();
    186   printf(",\n");
    187 
    188   dump_proc_stats();
    189   printf("\n}\n");
    190 
    191   return 0;
    192 }
    193