2 #include <machine/apmvar.h>
3 #include <sys/signal.h>
5 #include <sys/sysctl.h>
7 #include <sys/sensors.h>
23 #define MIN(a, b) ((a) < (b) ? (a) : (b))
25 static int power_sensors[MAXSENSORS];
26 static int cputemp_sensor = -1;
27 static int num_power_sensors = 0;
28 static int entries = 0;
46 struct graph g[NGRAPH];
48 struct cpu_usage *cpus;
59 struct cpustats diffs;
65 for (int i = 0; i < MAXSENSORS; ++i) {
66 const int mib[3] = { CTL_HW, HW_SENSORS, i };
68 size_t sdlen = sizeof dev;
70 if (sysctl (mib, 3, &dev, &sdlen, NULL, 0) == -1)
73 if (dev.maxnumt[SENSOR_WATTS] > 0) {
74 power_sensors[num_power_sensors++] = i;
77 if (dev.maxnumt[SENSOR_TEMP] > 0
78 && memcmp (dev.xname, "cpu", 3) == 0
79 && cputemp_sensor == -1) {
88 const int mib[] = { CTL_HW, HW_NCPU };
90 size_t size = sizeof ncpu;
92 if (sysctl (mib, 2, &ncpu, &size, NULL, 0) < 0)
99 percentages (struct cpustats *out, struct cpu_usage *cpu)
101 int64_t total_change = 0;
103 for (int i = 0; i < 6; ++i) {
104 int64_t change = cpu->new.cs_time[i] - cpu->old.cs_time[i];
106 change = INT64_MAX - cpu->old.cs_time[i] - cpu->new.cs_time[i];
108 cpu->diffs.cs_time[i] = change;
109 total_change += change;
110 cpu->old.cs_time[i] = cpu->new.cs_time[i];
113 if (total_change == 0)
116 for (int i = 0; i < 6; ++i) {
117 out->cs_time[i] = (cpu->diffs.cs_time[i] * 1000 + total_change / 2) / total_change;
126 const int mib[2] = { CTL_HW, HW_CPUSPEED };
128 size_t len = sizeof speed;
130 if (sysctl (mib, 2, &speed, &len, NULL, 0) == -1)
139 const int mib[5] = { CTL_HW, HW_SENSORS, cputemp_sensor, SENSOR_TEMP, 0 };
140 struct sensor sensor;
141 size_t len = sizeof sensor;
144 ret = sysctl (mib, 5, &sensor, &len, NULL, 0);
146 return (ret == -1 || sensor.status & SENSOR_FINVALID) ? -1 : sensor.value / 10000000;
150 cpu (int ncpu, struct cpu_usage *cpus)
154 for (int i = 0; i < ncpu; ++i) {
155 const int mib[] = { CTL_KERN, KERN_CPUSTATS, i };
157 size_t size = sizeof tmp;
159 if (sysctl (mib, 3, &cpus[i].new, &size, NULL, 0) < 0)
162 percentages (&tmp, &cpus[i]);
163 sum += 1000 - tmp.cs_time[5];
166 return sum / ncpu / 10;
172 struct apm_power_info info;
174 if (fd < 0 || ioctl (fd, APM_IOC_GETPOWER, &info) != 0)
177 return info.battery_life;
185 for (int i = 0; i < num_power_sensors; ++i) {
186 const int mib[5] = { CTL_HW, HW_SENSORS, power_sensors[i], SENSOR_WATTS, 0 };
187 struct sensor sensor;
188 size_t slen = sizeof sensor;
190 if (sysctl (mib, 5, &sensor, &slen, NULL, 0) == -1)
193 if (sensor.flags & SENSOR_FINVALID)
196 total += sensor.value;
203 create_win (struct display *dpy)
208 for (int i = 0; i < NGRAPH; ++i) {
213 getmaxyx (stdscr, h, w);
214 dpy->width = MIN (w - 2, LOGLEN);
216 wh = h / dpy->ngraph;
218 if (entries > dpy->width) {
219 const int diff = entries - dpy->width;
220 for (int i = 0; i < NGRAPH; ++i) {
221 struct graph *g = &dpy->g[i];
222 memmove (g->log, g->log + diff, dpy->width * sizeof (g->log[0]));
224 entries = dpy->width;
227 for (int i = 0; i < NGRAPH; ++i) {
228 struct graph *g = &dpy->g[i];
231 g->win = g->hide ? NULL : newwin (wh, w, 1 + wh * j++, 0);
236 draw_graph (struct graph *g, const char *fmt, int min, int max)
240 if (g->hide || g->win == NULL)
243 getmaxyx (g->win, h, w);
249 for (int i = 0; i < entries; ++i) {
258 for (int i = 0; i < entries; ++i) {
260 int y = (int)((float)(v - min) / (max - min) * h);
261 mvwaddch (g->win, h - y + 1, i + 1, 'X');
267 mvwprintw (g->win, 0, 3, fmt, g->log[entries - 1]);
268 wprintw (g->win, " (min: %d/max: %d)", min, max);
273 draw (struct display *dpy)
277 draw_graph (&dpy->g[G_CPUUSAGE], "CPU: %d%%", 0, 100);
278 draw_graph (&dpy->g[G_CPUTEMP], "CPU.: %d C", 0, 100);
279 draw_graph (&dpy->g[G_CPUSPEED], "CPU: %d MHz", INT_MAX, INT_MIN);
280 draw_graph (&dpy->g[G_BATTERY], "BAT: %d%%", 0, 100);
281 draw_graph (&dpy->g[G_POWER], "PWR: %dmW", INT_MAX, INT_MIN);
283 mvprintw (0, 0, "Panels: ");
284 for (int i = 0; i < NGRAPH; ++i) {
285 addch (dpy->g[i].hide ? ' ' : ('1' + i));
288 printw (" %c delay=%d", dpy->running ? 'R' : 'S', dpy->delay);
291 for (int i = 0; i < NGRAPH; ++i)
292 wnoutrefresh (dpy->g[i].win);
299 update_graph (int w, struct graph *g, int value)
302 memmove (g->log, g->log + 1, (LOGLEN - 1) * sizeof (g->log[0]));
303 g->log[entries - 1] = value;
305 g->log[entries] = value;
307 fprintf (stderr, "entries=%d, w=%d, value=%d\n", entries, w, value);
311 update (struct display *dpy)
315 update_graph (w, &dpy->g[G_CPUUSAGE], cpu (dpy->ncpu, dpy->cpus));
316 update_graph (w, &dpy->g[G_CPUTEMP], cputemp ());
317 update_graph (w, &dpy->g[G_CPUSPEED], cpuspeed ());
318 update_graph (w, &dpy->g[G_BATTERY], bat (dpy->fd_apm));
319 update_graph (w, &dpy->g[G_POWER], power ());
327 main (int argc, char *argv[])
331 memset (&dpy, 0, sizeof (dpy));
332 dpy.ncpu = num_cpu ();
333 dpy.cpus = calloc (dpy.ncpu, sizeof (struct cpu_usage));
334 dpy.fd_apm = open ("/dev/apm", O_RDONLY);
339 setlocale (LC_ALL, "");
343 intrflush (stdscr, FALSE);
344 keypad (stdscr, TRUE);
345 halfdelay (dpy.delay);
369 g = &dpy.g[ch - '1'];
370 if (dpy.ngraph == 1 && !g->hide)
377 halfdelay (dpy.delay);
382 halfdelay (dpy.delay);
385 dpy.running = !dpy.running;