• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
dump_time(void)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 
dump_cpu_stats(void)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 
dump_mem_stats(void)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 
dump_proc_stats(void)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 
main()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