hyperoptimized file reading

This commit is contained in:
2026-08-14 18:00:02 +02:00
parent 901d5b53d9
commit 81cfc2ce0d
8 changed files with 172 additions and 150 deletions

View File

@@ -1,6 +1,8 @@
#ifndef LINUXSMARTIE_SYS_H #ifndef LINUXSMARTIE_SYS_H
#define LINUXSMARTIE_SYS_H #define LINUXSMARTIE_SYS_H
#include "utils.h"
#include <stdint.h> #include <stdint.h>
#define SYS_GET_TIME_STR(t) sys_get_time_string((char[16]){0}, 16, t) #define SYS_GET_TIME_STR(t) sys_get_time_string((char[16]){0}, 16, t)
@@ -20,6 +22,8 @@ struct disk_t {
struct network_t { struct network_t {
uint32_t download; uint32_t download;
uint32_t upload; uint32_t upload;
sensor_file_t f_rx;
sensor_file_t f_tx;
char device[16]; char device[16];
}; };
@@ -41,8 +45,10 @@ void sys_get_disk(struct disk_t *disk);
void sys_get_network(struct network_t *network); void sys_get_network(struct network_t *network);
void sys_netdev_detect(struct network_t *network);
void sys_detect(struct syssensors_t *s, const char *platform); void sys_detect(struct syssensors_t *s, const char *platform);
void sys_update_sensors(struct syssensors_t *s); void sys_update_sensors(const struct syssensors_t *s);
#endif // LINUXSMARTIE_SYS_H #endif // LINUXSMARTIE_SYS_H

View File

@@ -2,7 +2,7 @@
#define LINUXSMARTIE_UTILS_H #define LINUXSMARTIE_UTILS_H
#include <stdint.h> #include <stdint.h>
#include <sys/types.h> #include <sys/types.h> // NOLINT yes its, needed for ssize_t
#if __STDC_VERSION__ >= 202000L #if __STDC_VERSION__ >= 202000L
#define C_STD "C23" #define C_STD "C23"
@@ -22,17 +22,20 @@
#define P_BYTES(bytes, start) pretty_bytes((bytes), (start), (char[16]){0}, 16) #define P_BYTES(bytes, start) pretty_bytes((bytes), (start), (char[16]){0}, 16)
#define P_NUM(num) pretty_num((num), (char[16]){0}, 16) #define P_NUM(num) pretty_num((num), (char[16]){0}, 16)
typedef enum { typedef enum : uint8_t {
SENSOR_I16, SENSOR_I16,
SENSOR_U8,
SENSOR_U16,
SENSOR_U64,
SENSOR_FLOAT,
} sensor_type_t; } sensor_type_t;
typedef struct { typedef struct {
char path[256]; sensor_type_t type;
int fd; int fd;
void* value; void* value;
uint32_t divider; uint32_t divider;
sensor_type_t type; } sensor_file_t;
} sensor_t;
int get_instance_lock(); int get_instance_lock();
@@ -46,22 +49,12 @@ char *pretty_bytes(uint64_t bytes, int8_t start_suffix, char *buf, size_t bufsz)
int get_hwmon_dir(char *path, size_t bufsz); int get_hwmon_dir(char *path, size_t bufsz);
ssize_t read_file(const char *dir, const char *file, char *buffer, size_t n); void open_sensor(sensor_file_t* s, const char* dir, const char *file, void* value, uint32_t divider, sensor_type_t type);
void fast_read_num_u64(const char *dir, const char *file, char *buf, uint64_t *result, uint32_t divider); void fast_read_sensor_into_mem(const sensor_file_t *s, void* val);
void fast_read_num_u16(const char *dir, const char *file, char *buf, uint16_t *result, uint32_t divider); void fast_read_sensor(const sensor_file_t *s);
void fast_read_num_u8(const char *dir, const char *file, char *buf, uint8_t *result, uint32_t divider); void close_sensor(const sensor_file_t* s);
void fast_read_num_i16(const char *dir, const char *file, char *buf, int16_t *result, uint32_t divider);
void fast_read_num_f(const char *dir, const char *file, char *buf, float *result, uint32_t divider);
void open_sensor(sensor_t* s, const char* dir, const char *file, void* value, uint32_t divider, sensor_type_t type);
void fast_read_sensor_i16(const sensor_t *s);
void close_sensor(const sensor_t* s);
#endif #endif

View File

@@ -3,10 +3,13 @@
#include "utils.h" #include "utils.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
static uint64_t max_energy_range_uj = 0; static sensor_file_t* sensors;
static sensor_file_t* cpu_freqs;
static constexpr uint64_t max_energy_range_uj = 65532610987;
void cpu_detect(struct cpu_sensors_t *t, const char *pci_dev) { void cpu_detect(struct cpu_sensors_t *t, const char *pci_dev) {
t->module = unknown; t->module = unknown;
@@ -20,14 +23,34 @@ void cpu_detect(struct cpu_sensors_t *t, const char *pci_dev) {
return; return;
} }
static char buf[32]; // fast_read_num_u64("/sys/class/powercap/intel-rapl:0/", "max_energy_range_uj", buf, &max_energy_range_uj, 1);
fast_read_num_u64("/sys/class/powercap/intel-rapl:0/", "max_energy_range_uj", buf, &max_energy_range_uj, 1); // t->module = read_file(t->hwmon, "/in1_input", nullptr, 0) ? zenpower : k10temp; // if we can read zenpower file then zenpower. idk if this is reliable, we're trying to avoid just reading the name
t->module = read_file(t->hwmon, "/in1_input", nullptr, 0) ? zenpower : k10temp; // if we can read zenpower file then zenpower. idk if this is reliable, we're trying to avoid just reading the name t->module = k10temp; // just assume its k10temp until we figure out a better way to detect it
applog(LOG_INF, "Detected %d cores, module enum #%d in path %s", t->num_cores, t->module, t->hwmon); applog(LOG_INF, "Detected %d cores, module enum #%d in path %s", t->num_cores, t->module, t->hwmon);
cpu_freqs = malloc(sizeof(sensor_file_t) * t->num_cores);
sensors = malloc(sizeof(sensor_file_t) * (t->module == zenpower ? 4 : 3));
for (uint8_t i = 0; i < t->num_cores; i++) {
char p[128];
sprintf(p, "/sys/devices/system/cpu/cpu%d/cpufreq/", i);
open_sensor(&cpu_freqs[i], p, "cpuinfo_avg_freq", nullptr, 1000, SENSOR_U64);
}
if (max_energy_range_uj != 0)
open_sensor(&sensors[0], "/sys/class/powercap/intel-rapl:0/", "energy_uj", nullptr, 1, SENSOR_U64);
if (t->module == k10temp) {
open_sensor(&sensors[1], t->hwmon, "/temp1_input", &t->tctl, 1000, SENSOR_I16);
open_sensor(&sensors[2], t->hwmon, "/temp3_input", &t->tccd1, 1000, SENSOR_I16);
} else if (t->module == zenpower) {
open_sensor(&sensors[1], t->hwmon, "/temp1_input", &t->tdie, 1000, SENSOR_I16);
open_sensor(&sensors[2], t->hwmon, "/temp2_input", &t->tctl, 1000, SENSOR_I16);
open_sensor(&sensors[3], t->hwmon, "/temp3_input", &t->tccd1, 1000, SENSOR_I16);
}
} }
void cpu_update(struct cpu_sensors_t *c) { void cpu_update(struct cpu_sensors_t *c) {
static char buf[32];
struct energy_t { struct energy_t {
struct timespec ts; struct timespec ts;
uint64_t energy; uint64_t energy;
@@ -40,7 +63,7 @@ void cpu_update(struct cpu_sensors_t *c) {
// read power from intel-rapl? works on amd too, btop uses this trick, seems accurate // read power from intel-rapl? works on amd too, btop uses this trick, seems accurate
// it tracks with "socket power" in hwinfo on windows, its actually the same thing i had in lcdsmartie // it tracks with "socket power" in hwinfo on windows, its actually the same thing i had in lcdsmartie
clock_gettime(CLOCK_MONOTONIC, &curr.ts); clock_gettime(CLOCK_MONOTONIC, &curr.ts);
fast_read_num_u64("/sys/class/powercap/intel-rapl:0/", "energy_uj", buf, &curr.energy, 1); fast_read_sensor_into_mem(&sensors[0], &curr.energy);
if (curr.energy >= prev.energy) if (curr.energy >= prev.energy)
energy_delta = curr.energy - prev.energy; energy_delta = curr.energy - prev.energy;
@@ -56,11 +79,9 @@ void cpu_update(struct cpu_sensors_t *c) {
// lots of reads but still faster than reading /proc/cpuinfo // lots of reads but still faster than reading /proc/cpuinfo
c->avg_freq = 0; c->avg_freq = 0;
char p[128];
for (uint8_t i = 0; i < c->num_cores; i++) { for (uint8_t i = 0; i < c->num_cores; i++) {
uint64_t t = 0; uint64_t t = 0;
sprintf(p, "/sys/devices/system/cpu/cpu%d/cpufreq/", i); fast_read_sensor_into_mem(&cpu_freqs[i], &t);
fast_read_num_u64(p, "cpuinfo_avg_freq", buf, &t, 1000);
c->avg_freq += (uint32_t)t; c->avg_freq += (uint32_t)t;
} }
c->avg_freq /= (c->num_cores > 1) ? c->num_cores : 1; c->avg_freq /= (c->num_cores > 1) ? c->num_cores : 1;
@@ -69,15 +90,15 @@ void cpu_update(struct cpu_sensors_t *c) {
return; return;
if (c->module == k10temp) { if (c->module == k10temp) {
fast_read_num_i16(c->hwmon, "/temp1_input", buf, &c->tctl, 1000); fast_read_sensor(&sensors[1]);
fast_read_num_i16(c->hwmon, "/temp3_input", buf, &c->tccd1, 1000); fast_read_sensor(&sensors[2]);
} }
// commented out unused values so its faster // commented out unused values so its faster
if (c->module == zenpower) { if (c->module == zenpower) {
fast_read_num_i16(c->hwmon, "/temp1_input", buf, &c->tdie, 1000); fast_read_sensor(&sensors[1]);
fast_read_num_i16(c->hwmon, "/temp2_input", buf, &c->tctl, 1000); fast_read_sensor(&sensors[2]);
fast_read_num_i16(c->hwmon, "/temp3_input", buf, &c->tccd1, 1000); fast_read_sensor(&sensors[3]);
// utils::fastReadNum<1000>(c->hwmon + "/in1_input", buf, c->vcore); // utils::fastReadNum<1000>(c->hwmon + "/in1_input", buf, c->vcore);
// utils::fastReadNum<1000>(c->hwmon + "/in2_input", buf, c->vsoc); // utils::fastReadNum<1000>(c->hwmon + "/in2_input", buf, c->vsoc);
} }

View File

@@ -6,8 +6,16 @@
#include "log.h" #include "log.h"
#include "utils.h" #include "utils.h"
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static constexpr char rel_metrics_path[] = "/../../gpu_metrics"; // gpu_metrics path relative to hwmon path static constexpr char rel_metrics_path[] = "/../../gpu_metrics"; // gpu_metrics path relative to hwmon path
static constexpr uint16_t max_metrics_length = 512; // length of the metrics buffer static constexpr uint16_t max_metrics_length = 512; // length of the metrics buffer
static sensor_file_t* sensors;
static int gpu_metrics_fd;
void gpu_detect(struct gpu_sensors_t *t, const char *pci) { void gpu_detect(struct gpu_sensors_t *t, const char *pci) {
snprintf(t->hwmon, sizeof(t->hwmon), "/sys/bus/pci/devices/%s/hwmon", pci); snprintf(t->hwmon, sizeof(t->hwmon), "/sys/bus/pci/devices/%s/hwmon", pci);
@@ -19,43 +27,55 @@ void gpu_detect(struct gpu_sensors_t *t, const char *pci) {
} }
t->has_gpu_metrics = false; t->has_gpu_metrics = false;
char raw_metrics[max_metrics_length]; char p[160];
if (!read_file(t->hwmon, rel_metrics_path, raw_metrics, sizeof(raw_metrics))) char *nt = stpcpy(p, t->hwmon);
return; strcpy(nt, rel_metrics_path);
const struct metrics_table_header *header = (struct metrics_table_header *)raw_metrics; gpu_metrics_fd = open(p, O_RDONLY | O_CLOEXEC);
applog(LOG_INF, "Found gpu_metrics_v%d_%d", header->format_revision, header->content_revision); if (gpu_metrics_fd > 0) {
t->has_gpu_metrics = true; t->has_gpu_metrics = true;
char raw_metrics[max_metrics_length];
read(gpu_metrics_fd, raw_metrics, sizeof(raw_metrics));
const struct metrics_table_header *header = (struct metrics_table_header *)raw_metrics;
applog(LOG_INF, "Found gpu_metrics_v%d_%d", header->format_revision, header->content_revision);
}
sensors = malloc(sizeof(sensor_file_t) * (t->has_gpu_metrics ? 10 : 5));
// we always open these
open_sensor(&sensors[0], t->hwmon, "/in0_input", &t->vcore, 1000, SENSOR_FLOAT);
open_sensor(&sensors[1], t->hwmon, "/fan1_input", &t->fan_speed, 1, SENSOR_U16);
open_sensor(&sensors[2], t->hwmon, "/power1_cap", &t->power_cap, 1000000, SENSOR_U16);
open_sensor(&sensors[3], t->hwmon, "/power1_average", &t->power_avg, 1000000, SENSOR_U16);
open_sensor(&sensors[4], t->hwmon, "/../../mem_info_vram_used", &t->vram_used, 1, SENSOR_U64);
if (t->has_gpu_metrics == false) {
open_sensor(&sensors[5], t->hwmon, "/freq1_input", &t->clock_core, 1000000, SENSOR_U16);
open_sensor(&sensors[6], t->hwmon, "/freq2_input", &t->clock_mem, 1000000, SENSOR_U16);
open_sensor(&sensors[7], t->hwmon, "/power1_input",&t->power_avg, 1000000, SENSOR_U16);
open_sensor(&sensors[8], t->hwmon, "/temp1_input", &t->temp_edge, 1000, SENSOR_U8);
open_sensor(&sensors[9], t->hwmon, "/../../gpu_busy_percent", &t->usage_core, 1, SENSOR_U8);
}
} }
/* some metrics are missing in gpu_metrics, we always fill them from fs, unused metrics are commented out */ /* some metrics are missing in gpu_metrics, we always fill them from fs, unused metrics are commented out */
static void fill_missing_metrics(struct gpu_sensors_t *g) { static void fill_missing_metrics() {
char buf[32];
fast_read_num_f(g->hwmon, "/in0_input", buf, &g->vcore, 1000);
// g->fan_pwm = std::stoi(readFile(g->hwmon + "/pwm1", 4)) * 100 / 256; // g->fan_pwm = std::stoi(readFile(g->hwmon + "/pwm1", 4)) * 100 / 256;
fast_read_num_u16(g->hwmon, "/fan1_input", buf, &g->fan_speed, 1);
fast_read_num_u16(g->hwmon, "/power1_cap", buf, &g->power_cap, 1000000);
fast_read_num_u16(g->hwmon, "/power1_average", buf, &g->power_avg, 1000000);
// utils::fastReadNum(g->hwmon + "/power1_cap_max", g->power_cap_max) / 1000000; // utils::fastReadNum(g->hwmon + "/power1_cap_max", g->power_cap_max) / 1000000;
fast_read_num_u64(g->hwmon, "/../../mem_info_vram_used", buf, &g->vram_used, 1);
// utils::fastReadNum(g->hwmon + "/../../mem_info_vram_total", g->vram_total); // utils::fastReadNum(g->hwmon + "/../../mem_info_vram_total", g->vram_total);
for (uint8_t i = 0; i < 5; i++)
fast_read_sensor(&sensors[i]);
} }
/* get sensors for pre-vega cards (rx480/580) */ /* get sensors for pre-vega cards (rx480/580) */
static void update_from_fs(struct gpu_sensors_t *g) { static void update_from_fs() {
char buf[32]; for (uint8_t i = 5; i < 10; i++)
fast_read_num_u16(g->hwmon, "/freq1_input", buf, &g->clock_core, 1000000); fast_read_sensor(&sensors[i]);
fast_read_num_u16(g->hwmon, "/freq2_input", buf, &g->clock_mem, 1000000);
fast_read_num_u16(g->hwmon, "/power1_input", buf, &g->power_avg, 1000000);
fast_read_num_u8(g->hwmon, "/temp1_input", buf, &g->temp_edge, 1000);
fast_read_num_u8(g->hwmon, "/../../gpu_busy_percent", buf, &g->usage_core, 1);
} }
static void update_from_metrics(struct gpu_sensors_t *g) { static void update_from_metrics(struct gpu_sensors_t *g) {
char raw_metrics[max_metrics_length]; char raw_metrics[max_metrics_length];
lseek(gpu_metrics_fd, 0, SEEK_SET);
if (!read_file(g->hwmon, rel_metrics_path, raw_metrics, sizeof(raw_metrics))) read(gpu_metrics_fd, raw_metrics, sizeof(raw_metrics));
return;
const struct metrics_table_header *header = (struct metrics_table_header *)raw_metrics; const struct metrics_table_header *header = (struct metrics_table_header *)raw_metrics;
switch (header->format_revision * 10 + header->content_revision) { switch (header->format_revision * 10 + header->content_revision) {
@@ -106,11 +126,11 @@ void gpu_update(struct gpu_sensors_t *g) {
const bool hwmon_valid = g->hwmon[0] != '\0'; const bool hwmon_valid = g->hwmon[0] != '\0';
if (hwmon_valid) if (hwmon_valid)
fill_missing_metrics(g); fill_missing_metrics();
if (g->has_gpu_metrics) if (g->has_gpu_metrics)
update_from_metrics(g); update_from_metrics(g);
else if (hwmon_valid) else if (hwmon_valid)
update_from_fs(g); update_from_fs();
if (g->fan_speed > 9999) if (g->fan_speed > 9999)
g->fan_speed = 9999; // sanity check fan speed g->fan_speed = 9999; // sanity check fan speed
} }

View File

@@ -10,10 +10,7 @@
#define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b))
int lcd_open(struct lcd_t *lcd, bool reopen); static int lcd_open(struct lcd_t *lcd, const bool reopen) {
void lcd_write(struct lcd_t *lcd, const uint8_t *cmdbuf, uint16_t len);
int lcd_open(struct lcd_t *lcd, const bool reopen) {
applog(LOG_INF, "Opening serial port at %s", lcd->port); applog(LOG_INF, "Opening serial port at %s", lcd->port);
if (lcd->fd <= 0 || reopen) if (lcd->fd <= 0 || reopen)
lcd->fd = open(lcd->port, O_WRONLY | O_NOCTTY); lcd->fd = open(lcd->port, O_WRONLY | O_NOCTTY);
@@ -36,7 +33,7 @@ void lcd_close(struct lcd_t *lcd) {
lcd->fd = -1; lcd->fd = -1;
} }
void lcd_write(struct lcd_t *lcd, const uint8_t *cmdbuf, const uint16_t len) { static void lcd_write(struct lcd_t *lcd, const uint8_t *cmdbuf, const uint16_t len) {
if (write(lcd->fd, cmdbuf, len) <= 0) { if (write(lcd->fd, cmdbuf, len) <= 0) {
applog(LOG_ERR, "failed to execute write(), lost access to port?"); applog(LOG_ERR, "failed to execute write(), lost access to port?");
lcd_close(lcd); lcd_close(lcd);
@@ -109,7 +106,7 @@ inline void lcd_clear_buf(struct lcd_t *lcd) {
/* flushes writebuffer to lcd, hyperoptmized, flushes buffer and commands in a single write operation */ /* flushes writebuffer to lcd, hyperoptmized, flushes buffer and commands in a single write operation */
inline void lcd_flush_buf(struct lcd_t *lcd) { void lcd_flush_buf(struct lcd_t *lcd) {
constexpr uint8_t set_disp[] = {254, 71, 1, 1}; // set cursor to char 1, line 1 constexpr uint8_t set_disp[] = {254, 71, 1, 1}; // set cursor to char 1, line 1
memcpy(&lcd->writebuf.text[0], set_disp, 4); memcpy(&lcd->writebuf.text[0], set_disp, 4);
memcpy(&lcd->writebuf.text[2 * LCD_COLS + 4], set_disp, 4); memcpy(&lcd->writebuf.text[2 * LCD_COLS + 4], set_disp, 4);

View File

@@ -23,13 +23,13 @@ static constexpr char netif[] = "enp4s0f0";
static constexpr char cpu_pcidev[] = "0000:00:18.3"; static constexpr char cpu_pcidev[] = "0000:00:18.3";
static constexpr char gpu_pcidev[] = "0000:0a:00.0"; static constexpr char gpu_pcidev[] = "0000:0a:00.0";
struct control_t { static struct {
pthread_mutex_t sensors_mtx; pthread_mutex_t sensors_mtx;
pthread_cond_t sensors_ready; pthread_cond_t sensors_ready;
atomic_bool running; atomic_bool running;
} control; } control;
struct sensors_t { // NOLINT yes it is struct sensors_t { // NOLINT stfu
time_t ts; time_t ts;
struct memory_t ram; struct memory_t ram;
struct disk_t home; struct disk_t home;
@@ -56,6 +56,7 @@ static void *sensors_thread(void *arg) {
cpu_detect(&sensors->cpu, cpu_pcidev); cpu_detect(&sensors->cpu, cpu_pcidev);
gpu_detect(&sensors->gpu, gpu_pcidev); gpu_detect(&sensors->gpu, gpu_pcidev);
sys_detect(&sensors->sys, "nct6775.656"); sys_detect(&sensors->sys, "nct6775.656");
sys_netdev_detect(&sensors->net);
aio_detect(&sensors->aio); aio_detect(&sensors->aio);
/* main sensor loop */ /* main sensor loop */
@@ -90,7 +91,7 @@ static void *sensors_thread(void *arg) {
static void *display_thread(void *arg) { static void *display_thread(void *arg) {
applog(LOG_START, "display thread started"); applog(LOG_START, "display thread started");
struct sensors_t *sensors = arg; const struct sensors_t *sensors = arg;
/* lcd setup */ /* lcd setup */
struct lcd_t lcd = { struct lcd_t lcd = {
@@ -191,7 +192,7 @@ int main() {
} }
/* malloc memory for the struct */ /* malloc memory for the struct */
struct sensors_t *sensors = malloc(sizeof(*sensors)); // no actual point in mallocing and it is ever so sligtly slower to access heap vs stack, but its cool struct sensors_t *sensors = malloc(sizeof(struct sensors_t)); // no actual point in mallocing but its cool
if (sensors == nullptr) { if (sensors == nullptr) {
applog(LOG_ERR, "can't allocate mem for the sensor struct. You don't got %lu bytes bro?", sizeof(*sensors)); applog(LOG_ERR, "can't allocate mem for the sensor struct. You don't got %lu bytes bro?", sizeof(*sensors));
free(sensors); free(sensors);

View File

@@ -8,7 +8,7 @@
#include "sys.h" #include "sys.h"
#include "utils.h" #include "utils.h"
static sensor_t sensors[1]; static sensor_file_t sensors;
char *sys_get_time_string(char *buf, const size_t bufsz, const time_t t) { char *sys_get_time_string(char *buf, const size_t bufsz, const time_t t) {
const struct tm *tm = localtime(&t); const struct tm *tm = localtime(&t);
@@ -61,26 +61,30 @@ void sys_get_network(struct network_t *network) {
uint64_t tx; uint64_t tx;
}; };
static char path[128];
static char buf[32];
static struct _net_t prev; static struct _net_t prev;
struct _net_t current = {}; struct _net_t current = {};
snprintf(path, sizeof(path), "/sys/class/net/%s/statistics/", network->device);
clock_gettime(CLOCK_MONOTONIC, &current.ts); clock_gettime(CLOCK_MONOTONIC, &current.ts);
fast_read_num_u64(path, "rx_bytes", buf, &current.rx, 1); fast_read_sensor_into_mem(&network->f_rx, &current.rx);
fast_read_num_u64(path, "tx_bytes", buf, &current.tx, 1); fast_read_sensor_into_mem(&network->f_tx, &current.tx);
const int64_t diff_us = timespec_diff_us(&current.ts, &prev.ts); const int64_t diff_us = timespec_diff_us(&current.ts, &prev.ts);
const uint64_t rx_delta = current.rx >= prev.rx ? current.rx - prev.rx : 0; const uint64_t rx_delta = current.rx >= prev.rx ? current.rx - prev.rx : 0;
const uint64_t tx_delta = current.tx >= prev.tx ? current.tx - prev.tx : 0; const uint64_t tx_delta = current.tx >= prev.tx ? current.tx - prev.tx : 0;
const double diff_s = (double)diff_us / 1000000.0; const double diff_s = (double)diff_us / 1000000.0;
network->download = (uint32_t)((double)rx_delta / diff_s); network->download = (uint32_t)((double)rx_delta / diff_s);
network->upload = (uint32_t)((double)tx_delta / diff_s); network->upload = (uint32_t)((double)tx_delta / diff_s);
if (rx_delta < 2000000000ULL && tx_delta < 2000000000ULL) prev = current;
prev = current;
// still fucky? // still fucky?
} }
void sys_netdev_detect(struct network_t *network) {
applog(LOG_INF, "Opening netdev %s", network->device);
static char path[128];
snprintf(path, sizeof(path), "/sys/class/net/%s/statistics/", network->device);
open_sensor(&network->f_rx, path, "rx_bytes", nullptr, 1, SENSOR_U64);
open_sensor(&network->f_tx, path, "tx_bytes", nullptr, 1, SENSOR_U64);
}
void sys_detect(struct syssensors_t *s, const char *platform) { void sys_detect(struct syssensors_t *s, const char *platform) {
snprintf(s->hwmon, sizeof(s->hwmon), "/sys/devices/platform/%s/hwmon", platform); snprintf(s->hwmon, sizeof(s->hwmon), "/sys/devices/platform/%s/hwmon", platform);
const int ret = get_hwmon_dir(s->hwmon, sizeof(s->hwmon)); const int ret = get_hwmon_dir(s->hwmon, sizeof(s->hwmon));
@@ -90,22 +94,12 @@ void sys_detect(struct syssensors_t *s, const char *platform) {
return; return;
} }
applog(LOG_INF, "Detected system sensors in %s", s->hwmon); applog(LOG_INF, "Detected system sensors in %s", s->hwmon);
open_sensor(&sensors, s->hwmon, "/temp5_input", &s->t_sensor, 1000, SENSOR_I16);
open_sensor(&sensors[0], s->hwmon, "/temp5_input", &s->t_sensor, 1000, SENSOR_I16);
} }
void sys_update_sensors(struct syssensors_t *s) { void sys_update_sensors(const struct syssensors_t *s) {
if (!s->hwmon[0]) if (!s->hwmon[0])
return; return;
static size_t num_sensors = 0; fast_read_sensor(&sensors);
if (num_sensors == 0)
num_sensors = sizeof(sensors) / sizeof(sensors[0]);
// static char buf[8];
// fast_read_num_u16(s->hwmon, "/fan2_input", buf, &s->fan_speed[0], 1); // cpu fan, aka aio pump now
// fast_read_num_u16(s->hwmon, "/fan7_input", buf, &s->fan_speed[1], 1); // cpu opt
// fast_read_num_i16(s->hwmon, "/temp5_input", buf, &s->t_sensor, 1000);
for (size_t i = 0; i < num_sensors; i++)
fast_read_sensor_i16(&sensors[i]);
} }

View File

@@ -13,7 +13,7 @@
#include "log.h" #include "log.h"
#include "utils.h" #include "utils.h"
int get_instance_lock(void) { int get_instance_lock() {
const char *xdg_runtime_dir = getenv("XDG_RUNTIME_DIR"); const char *xdg_runtime_dir = getenv("XDG_RUNTIME_DIR");
char tmp_dir[256]; char tmp_dir[256];
snprintf(tmp_dir, sizeof(tmp_dir), "%s/linuxSmartie.lock", xdg_runtime_dir); snprintf(tmp_dir, sizeof(tmp_dir), "%s/linuxSmartie.lock", xdg_runtime_dir);
@@ -80,82 +80,72 @@ int get_hwmon_dir(char *path, const size_t bufsz) {
return -1; return -1;
} }
/* instead of building the path here we could build it once in *_detect funcs for each sensor, but thats a lot of paths damn void open_sensor(sensor_file_t* s, const char* dir, const char *file, void* value, const uint32_t divider, const sensor_type_t type) {
* actual slowdown is in the syscalls anyway, open(), read(), close () */ char path[256];
/* read n bytes from path into buffer */
// file descriptors shouldnt change once opened, so we could open once, cache them, just call read() in the loop, then close all of them on program exit?
inline ssize_t read_file(const char *dir, const char *file, char *buffer, const size_t n) {
char path[160]; // bug alert
char *nt = stpcpy(path, dir); // nt is a pointer to the null terminator of the copied string char *nt = stpcpy(path, dir); // nt is a pointer to the null terminator of the copied string
strcpy(nt, file); // copy to the null terminator of prev copy, append basically strcpy(nt, file); // copy to the null terminator of prev copy, append basically
const int fd = open(path, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
if (buffer != nullptr) // if its null means we're just checking if it exists at all, so dont log it
applog(LOG_ERR, "Error reading %s", path);
return 0;
}
const ssize_t len = read(fd, buffer, n);
if (len > 0 && buffer)
buffer[len] = '\0';
close(fd);
return len;
}
inline void fast_read_num_u64(const char *dir, const char *file, char *buf, uint64_t *result, const uint32_t divider) {
read_file(dir, file, buf, 32);
*result = strtoull(buf, nullptr, 10) / divider;
}
inline void fast_read_num_u16(const char *dir, const char *file, char *buf, uint16_t *result, const uint32_t divider) {
read_file(dir, file, buf, 32);
*result = (uint16_t)(strtol(buf, nullptr, 10) / divider);
}
inline void fast_read_num_u8(const char *dir, const char *file, char *buf, uint8_t *result, const uint32_t divider) {
read_file(dir, file, buf, 32);
*result = (uint8_t)(strtol(buf, nullptr, 10) / divider);
}
inline void fast_read_num_i16(const char *dir, const char *file, char *buf, int16_t *result, const uint32_t divider) {
read_file(dir, file, buf, 32);
*result = (int16_t)(strtol(buf, nullptr, 10) / divider);
}
inline void fast_read_num_f(const char *dir, const char *file, char *buf, float *result, const uint32_t divider) {
read_file(dir, file, buf, 32);
const uint64_t val = strtoull(buf, nullptr, 10);
*result = (float)val / (float)divider;
}
void open_sensor(sensor_t* s, const char* dir, const char *file, void* value, const uint32_t divider, const sensor_type_t type) {
char *nt = stpcpy(s->path, dir); // nt is a pointer to the null terminator of the copied string
strcpy(nt, file); // copy to the null terminator of prev copy, append basically
s->divider = divider; s->divider = divider;
s->value = value; s->value = value;
s->type = type; s->type = type;
s->fd = open(s->path, O_RDONLY | O_CLOEXEC); s->fd = open(path, O_RDONLY | O_CLOEXEC);
if (s->fd < 0)
applog(LOG_ERR, "couldn't open %s", path);
} }
inline void fast_read_sensor_i16(const sensor_t *s) { inline void fast_read_sensor_into_mem(const sensor_file_t *s, void* val) {
if (s->fd < 0) {
applog(LOG_ERR, "invalid sensor fd %d", s->fd);
return;
}
char buf[32]; char buf[32];
lseek(s->fd, 0, SEEK_SET); lseek(s->fd, 0, SEEK_SET);
const ssize_t len = read(s->fd, buf, sizeof(buf)); const ssize_t len = read(s->fd, buf, sizeof(buf));
if (len > 0)
buf[len] = '\0'; if (len <= 0) {
// return if read failed applog(LOG_ERR, "error reading sensor");
return;
}
buf[len] = '\0';
switch (s->type) { switch (s->type) {
case SENSOR_I16: case SENSOR_I16:
*(int16_t*)s->value = (int16_t)(strtol(buf, nullptr, 10) / s->divider); *(int16_t*)val = (int16_t)(strtol(buf, nullptr, 10) / s->divider);
break;
case SENSOR_U8:
*(uint8_t*)val = (uint8_t)(strtol(buf, nullptr, 10) / s->divider);
break;
case SENSOR_U16:
*(uint16_t*)val = (uint16_t)(strtol(buf, nullptr, 10) / s->divider);
break;
case SENSOR_U64:
*(uint64_t*)val = strtoull(buf, nullptr, 10) / s->divider;
break;
case SENSOR_FLOAT:
const uint64_t t = strtoull(buf, nullptr, 10);
*(float*)val = (float)t / (float)s->divider;
break; break;
default: default:
return; applog(LOG_ERR, "unknown sensor type %d", s->type);
break;
} }
} }
void close_sensor(const sensor_t* s) { inline void fast_read_sensor(const sensor_file_t *s) {
if (s->value != nullptr) {
fast_read_sensor_into_mem(s, s->value);
return;
}
applog(LOG_ERR, "attempted to read into nullptr");
}
void close_sensor(const sensor_file_t* s) {
close(s->fd); close(s->fd);
} }