Skip to content

Commit

Permalink
Add procfs CPU usage data gathering implementation
Browse files Browse the repository at this point in the history
Closes castvoid#8
  • Loading branch information
ryandesign committed Mar 12, 2021
1 parent e231db8 commit 45da167
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ if(FAKE)
list(APPEND SOURCE_FILES cpu_usage_random.c)
elseif(HAVE_MACH_MACH_HOST_H)
list(APPEND SOURCE_FILES cpu_usage_mach.c)
elseif(EXISTS "/proc/stat")
list(APPEND SOURCE_FILES cpu_usage_procfs.c)
else()
message(FATAL_ERROR "Don't know how to get CPU usage data on this system (you could use -DFAKE=ON)")
endif()
Expand Down
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,32 @@ cmake . && make
```bash
./hwmond
```

### Running on Linux
On modern Linux systems that use udev, the front panel might be attached read-only:

```
libusb: error [_get_usbfs_fd] libusb couldn't open USB device /dev/bus/usb/002/004: Permission denied
libusb: error [_get_usbfs_fd] libusb requires write access to USB device nodes.
Couldn't connect to front panel! (Are you running this on an Intel Xserve?)
```

To fix this, copy the provided rules file into rules.d directory:

```bash
sudo cp udev/98-apple-xserve-frontpanel.rules /lib/udev/rules.d/
```

Then reload the udev rules:

```bash
sudo udevadm control --reload-rules
```

And tell udev to run the rules for the front panel:

```bash
sudo udevadm trigger --attr-match=idVendor=05ac --attr-match=idProduct=8261
```

On subsequent system startups, the rule will be loaded automatically.
87 changes: 87 additions & 0 deletions cpu_usage_procfs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/sysinfo.h>
#include <sys/types.h>
#include <unistd.h>

int get_num_packages(void) {
FILE *fp;
char buf[8];
int last_package_id, num_packages = 0;
bool found_one = false;

if ((fp = popen("lscpu -p=SOCKET", "r")) == NULL) {
printf("ERROR opening lscpu pipe: %s\n", strerror(errno));
return -1;
}

while (fgets(buf, sizeof(buf), fp) != NULL) {
if (sscanf(buf, "%d", &last_package_id) == 1) {
found_one = true;
}
}

if (found_one) {
num_packages = last_package_id + 1;
}

if (pclose(fp)) {
printf("ERROR running lscpu: %s\n", strerror(errno));
return -1;
}

if (num_packages <= 0) {
printf("WARNING: lscpu gave invalid number of packages %d, using 1\n", num_packages);
num_packages = 1;
}

return num_packages;
}

int fetch_ticks_by_core(unsigned int **ticks_by_core_busy_ptr, unsigned int **ticks_by_core_total_ptr, unsigned int *num_cores_ptr) {
int num_cores = get_nprocs_conf();
FILE *fp;
char buf[100];
unsigned long user, nice, system, idle, busy;
size_t core;

// Aggregate per-core ticks into busy & total counts
unsigned int *ticks_by_core_busy = calloc(num_cores, sizeof(unsigned int));
unsigned int *ticks_by_core_total = calloc(num_cores, sizeof(unsigned int));

if (ticks_by_core_busy == NULL || ticks_by_core_total == NULL) {
printf("Failed to alloc\n");
return -1;
}

if ((fp = fopen("/proc/stat", "r")) == NULL) {
printf("ERROR opening /proc/stat: %s\n", strerror(errno));
return -1;
}

core = 0;
while (core < num_cores && fgets(buf, sizeof(buf), fp) != NULL) {
if (buf[0] == 'c' && buf[1] == 'p' && buf[2] == 'u' && buf[3] >= '0' && buf[3] <= '9') {
if (sscanf(buf, "%*s %ld %ld %ld %ld", &user, &nice, &system, &idle) == 4) {
ticks_by_core_busy[core] = busy = user + nice + system;
ticks_by_core_total[core] = busy + idle;
core++;
}
}
}

if (fclose(fp)) {
printf("ERROR closing /proc/stat: %s\n", strerror(errno));
return -1;
}

// Output aggregated data
*ticks_by_core_busy_ptr = ticks_by_core_busy;
*ticks_by_core_total_ptr = ticks_by_core_total;
*num_cores_ptr = num_cores;

return 0;
}
2 changes: 2 additions & 0 deletions udev/98-apple-xserve-frontpanel.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Apple Intel Xserve front panel controller
SUBSYSTEM=="usb", ATTR{idVendor}=="05ac", ATTR{idProduct}=="8261", MODE="666"

0 comments on commit 45da167

Please sign in to comment.