13 void sleep_nanos(long nanos
) {
17 nanosleep(&rqtp
, NULL
);
20 long get_time_nanos() {
22 gettimeofday(&t
, NULL
);
23 return t
.tv_sec
* 1000000000L + t
.tv_usec
* 1000;
26 char* read_file(char* filename
) {
27 static char buf
[32768];
30 int fd
= open(filename
, 0);
37 ssize_t result
= read(fd
, buf
+pos
, sizeof(buf
)-pos
);
45 if (pos
>= sizeof(buf
)) {
46 fprintf(stderr
, "Failed reading file, too much data: %s\n", filename
);
52 long parse_int(char* s
) {
58 long value
= strtol(s
, NULL
, 10);
60 fprintf(stderr
, "Failed to parse string: %s -- %s\n", strerror(errno
), s
);
67 char* read_next_line(char** s
) {
68 char* end
= index(*s
, '\n');
79 int read_cpu_idle_jiffys() {
80 char* procstat
= read_file("/proc/stat");
81 if (procstat
== NULL
) {
82 fprintf(stderr
, "Failed reading file /proc/stat: %s\n", strerror(errno
));
86 char* line
= read_next_line(&procstat
);
92 for (int i
= 0; i
<= 4; ++i
, line
=NULL
) {
93 result
= strtok(line
, " ");
95 return parse_int(result
);
99 char* procstat
= read_file("/proc/stat");
100 if (procstat
== NULL
) {
101 fprintf(stderr
, "Failed reading file /proc/stat: %s\n", strerror(errno
));
107 char* line
= read_next_line(&procstat
);
111 if (strncmp("cpu", line
, 3) == 0) {
118 int read_cpu_percent() {
119 int num_cpus
= count_cpus();
121 long tstart
= get_time_nanos();
122 int idle_jiffy1
= read_cpu_idle_jiffys();
123 sleep_nanos(100000000L);
124 int idle_jiffy2
= read_cpu_idle_jiffys();
125 long tend
= get_time_nanos();
127 double duration_sec
= ((double)tend
- (double)tstart
) / 1000000000.0;
128 double idle_jiffys_per_second
= (idle_jiffy2
- idle_jiffy1
) / duration_sec
;
130 double idle_jiffys_per_cpu_second
= idle_jiffys_per_second
/ num_cpus
;
132 // One jiffy is 10ms, so we can get the percentage very easily!
133 return 100 - (int)round(idle_jiffys_per_cpu_second
);
136 int read_mem_free_mibis() {
137 char* meminfo
= read_file("/proc/meminfo");
138 if (meminfo
== NULL
) {
139 fprintf(stderr
, "Failed reading file /proc/meminfo: %s\n", strerror(errno
));
144 char* line
= read_next_line(&meminfo
);
149 char* key
= strtok(line
, ": ");
150 char* value_str
= strtok(NULL
, ": ");
152 if (key
== NULL
|| value_str
== NULL
) {
153 fprintf(stderr
, "Failed to parse key/value token in /proc/meminfo\n");
157 if (strcmp(key
, "MemAvailable") == 0) {
158 int mem_available
= parse_int(value_str
);
159 return (int)round((double)mem_available
/ 1024);
163 fprintf(stderr
, "Failed to find MemAvailable in /proc/meminfo\n");
167 int read_zfs_arc_used_mibis() {
168 char* arcstats
= read_file("/proc/spl/kstat/zfs/arcstats");
169 if (arcstats
== NULL
) {
174 char* line
= read_next_line(&arcstats
);
179 char* key
= strtok(line
, " ");
181 char* value_str
= strtok(NULL
, " ");
183 if (key
== NULL
|| value_str
== NULL
) {
184 fprintf(stderr
, "Failed to parse key/value token in /proc/spl/kstat/zfs/arcstats\n");
188 if (strcmp(key
, "size") == 0) {
189 long arc_used
= parse_int(value_str
);
190 return (int)round((double)arc_used
/ 1024 / 1024);
194 fprintf(stderr
, "Failed to find 'c' in /proc/spl/kstat/zfs/arcstats\n");
198 int read_battery_percent() {
199 char* percent_str
= NULL
;
201 if (percent_str
== NULL
) {
202 percent_str
= read_file("/sys/class/power_supply/BAT0/capacity");
205 if (percent_str
== NULL
) {
206 percent_str
= read_file("/sys/class/power_supply/BAT1/capacity");
209 if (percent_str
== NULL
) {
210 fprintf(stderr
, "Failed reading file battery capacity file: %s\n", strerror(errno
));
214 return parse_int(percent_str
);
217 void print_red_threshold(
218 char* name
, char* units
,
220 int red_low
, int red_high
226 char* color
= "black";
227 if (value
>= red_low
&& value
<= red_high
) {
232 "%s <span color='%s'>%d</span>%s ",
233 name
, color
, value
, units
237 int main(int argc
, char** argv
) {
238 char* show_flags
= "cmb";
240 show_flags
= argv
[1];
245 if (strchr(show_flags
, 'c')) {
253 if (strchr(show_flags
, 'm')) {
256 read_mem_free_mibis() + read_zfs_arc_used_mibis(),
261 if (strchr(show_flags
, 'b')) {
264 read_battery_percent(),