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_meminfo(int* mem_free_mibis
, int* mem_total_mibis
) {
137 char* meminfo
= read_file("/proc/meminfo");
138 if (meminfo
== NULL
) {
139 fprintf(stderr
, "Failed reading file /proc/meminfo: %s\n", strerror(errno
));
143 *mem_free_mibis
= -1;
144 *mem_total_mibis
= -1;
147 char* line
= read_next_line(&meminfo
);
152 char* key
= strtok(line
, ": ");
153 char* value_str
= strtok(NULL
, ": ");
155 if (key
== NULL
|| value_str
== NULL
) {
156 fprintf(stderr
, "Failed to parse key/value token in /proc/meminfo\n");
160 if (strcmp(key
, "MemAvailable") == 0) {
161 int mem_available
= parse_int(value_str
);
162 *mem_free_mibis
= (int)round((double)mem_available
/ 1024);
165 if (strcmp(key
, "MemTotal") == 0) {
166 int mem_available
= parse_int(value_str
);
167 *mem_total_mibis
= (int)round((double)mem_available
/ 1024);
171 if (*mem_free_mibis
< 0 || *mem_total_mibis
< 0) {
172 fprintf(stderr
, "Failed to find field in /proc/meminfo\n");
179 int read_zfs_arc_used_mibis() {
180 char* arcstats
= read_file("/proc/spl/kstat/zfs/arcstats");
181 if (arcstats
== NULL
) {
186 char* line
= read_next_line(&arcstats
);
191 char* key
= strtok(line
, " ");
193 char* value_str
= strtok(NULL
, " ");
195 if (key
== NULL
|| value_str
== NULL
) {
196 fprintf(stderr
, "Failed to parse key/value token in /proc/spl/kstat/zfs/arcstats\n");
200 if (strcmp(key
, "size") == 0) {
201 long arc_used
= parse_int(value_str
);
202 return (int)round((double)arc_used
/ 1024 / 1024);
206 fprintf(stderr
, "Failed to find 'c' in /proc/spl/kstat/zfs/arcstats\n");
210 int read_battery_percent() {
211 char* percent_str
= NULL
;
213 if (percent_str
== NULL
) {
214 percent_str
= read_file("/sys/class/power_supply/BAT0/capacity");
217 if (percent_str
== NULL
) {
218 percent_str
= read_file("/sys/class/power_supply/BAT1/capacity");
221 if (percent_str
== NULL
) {
222 fprintf(stderr
, "Failed reading file battery capacity file: %s\n", strerror(errno
));
226 return parse_int(percent_str
);
229 void print_red_threshold(
230 char* name
, char* units
,
232 int red_low
, int red_high
238 char* color
= "black";
239 if (value
>= red_low
&& value
<= red_high
) {
244 "%s <span color='%s'>%d</span>%s\n",
245 name
, color
, value
, units
249 int main(int argc
, char** argv
) {
250 char* show_flags
= "cmb";
251 char* top_padding
= "0";
253 show_flags
= argv
[1];
256 top_padding
= argv
[2];
259 printf("<txt><span size=\"%s\">\n</span>", top_padding
);
261 if (strchr(show_flags
, 'c')) {
269 if (strchr(show_flags
, 'm')) {
270 int mem_free_mibis
, mem_total_mibis
;
271 read_meminfo(&mem_free_mibis
, &mem_total_mibis
);
274 mem_free_mibis
+ read_zfs_arc_used_mibis(),
275 0, mem_total_mibis
/ 10
279 if (strchr(show_flags
, 'b')) {
282 read_battery_percent(),