OLD | NEW |
(Empty) | |
| 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 } |
OLD | NEW |