Skip to content

Commit

Permalink
NetBSD: Fix CPU Usage.
Browse files Browse the repository at this point in the history
Report the correct number of CPUs and calculate the per-CPU load.

Start implementing a common BSD interface, as all BSD implementations use
*slightly* different functions to achieve the same goal,
and maintaining them in one place would be easier.

Fixes #2097.
  • Loading branch information
g0mb4 committed Dec 5, 2024
1 parent d024721 commit 005d830
Show file tree
Hide file tree
Showing 6 changed files with 235 additions and 58 deletions.
2 changes: 1 addition & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ if(OS_SOLARIS)
endif(OS_SOLARIS)

if(OS_NETBSD)
set(netbsd netbsd.cc netbsd.h)
set(netbsd netbsd.cc netbsd.h bsdcommon.cc bsdcommon.h)
set(optional_sources ${optional_sources} ${netbsd})
endif(OS_NETBSD)

Expand Down
163 changes: 163 additions & 0 deletions src/bsdcommon.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/*
*
* Conky, a system monitor, based on torsmo
*
* Please see COPYING for details
*
* Copyright (c) 2005-2024 Brenden Matthews, Philip Kovacs, et. al.
* (see AUTHORS)
* All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

#include "bsdcommon.h"
#include "logging.h"

#include <kvm.h>

#include <sys/sysctl.h>

static kvm_t *kd = nullptr;
static bool kvm_initialised = false;
static bool cpu_initialised = false;

static struct bsdcommon::cpu_load *cpu_loads = nullptr;

bool bsdcommon::init_kvm() {
if (kvm_initialised) {
return true;
}

kd = kvm_open(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr);
if (kd == nullptr) {
NORM_ERR("opening kvm");
return false;
}

kvm_initialised = true;
return false;
}

void bsdcommon::deinit_kvm() {
if (!kvm_initialised || kd == nullptr) {
return;
}

kvm_close(kd);
}

void bsdcommon::get_cpu_count(float **cpu_usage, unsigned int *cpu_count) {
int ncpu = 1;
int mib[2] = {CTL_HW, HW_NCPU};
size_t len = sizeof(ncpu);

if (sysctl(mib, 2, &ncpu, &len, nullptr, 0) != 0) {
NORM_ERR("error getting kern.ncpu, defaulting to 1");
ncpu = 1;
}

if (*cpu_count != ncpu) {
*cpu_count = ncpu;

if (*cpu_usage != nullptr) {
free(*cpu_usage);
*cpu_usage = nullptr;
}

if (cpu_loads != nullptr) {
free(cpu_loads);
cpu_loads = nullptr;
}
}

if (*cpu_usage == nullptr) {
// [0] - Total CPU
// [1, 2, ... ] - CPU1, CPU2, ...
*cpu_usage = (float*)calloc(ncpu + 1, sizeof(float));
if (*cpu_usage == nullptr) {
CRIT_ERR("calloc of cpu_usage");
}
}

if (cpu_loads == nullptr) {
cpu_loads = (struct cpu_load*)calloc(ncpu + 1, sizeof(struct cpu_load));
if (cpu_loads == nullptr) {
CRIT_ERR("calloc of cpu_loads");
}
}
}

void bsdcommon::update_cpu_usage(float **cpu_usage, unsigned int *cpu_count) {
uint64_t cp_time0[CPUSTATES];
int mib_cpu0[2] = {CTL_KERN, KERN_CP_TIME};
uint64_t cp_timen[CPUSTATES];
int mib_cpun[3] = {CTL_KERN, KERN_CP_TIME, 0};
size_t size = 0;
u_int64_t used = 0, total = 0;

if (!cpu_initialised) {
get_cpu_count(cpu_usage, cpu_count);
cpu_initialised = true;
}

size = sizeof(cp_time0);
if (sysctl(mib_cpu0, 2, &cp_time0, &size, nullptr, 0) != 0) {
NORM_ERR("unable to get kern.cp_time for cpu0");
return;
}

for (int j = 0; j < CPUSTATES; ++j) {
total += cp_time0[j];
}
used = total - cp_time0[CP_IDLE];

if ((total - cpu_loads[0].old_total) != 0) {
const float diff_used = (float)(used - cpu_loads[0].old_used);
const float diff_total = (float)(total - cpu_loads[0].old_total);
(*cpu_usage)[0] = diff_used / diff_total;
} else {
(*cpu_usage)[0] = 0;
}
cpu_loads[0].old_used = used;
cpu_loads[0].old_total = total;

for (int i = 0; i < *cpu_count; ++i) {
mib_cpun[2] = i;
size = sizeof(cp_timen);
if (sysctl(mib_cpun, 3, &cp_timen, &size, nullptr, 0) != 0) {
NORM_ERR("unable to get kern.cp_time for cpu%d", i);
return;
}

total = 0;
used = 0;
for (int j = 0; j < CPUSTATES; ++j) {
total += cp_timen[j];
}
used = total - cp_timen[CP_IDLE];

const int n = i + 1; // [0] is the total CPU, must shift by 1
if ((total - cpu_loads[n].old_total) != 0) {
const float diff_used = (float)(used - cpu_loads[n].old_used);
const float diff_total = (float)(total - cpu_loads[n].old_total);
(*cpu_usage)[n] = diff_used / diff_total;
} else {
(*cpu_usage)[n] = 0;
}

cpu_loads[n].old_used = used;
cpu_loads[n].old_total = total;
}
}
49 changes: 49 additions & 0 deletions src/bsdcommon.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
*
* Conky, a system monitor, based on torsmo
*
* Please see COPYING for details
*
* Copyright (c) 2005-2024 Brenden Matthews, Philip Kovacs, et. al.
* (see AUTHORS)
* All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

/*
* Shared or very similar code across BSDs.
*/

#ifndef BSDCOMMON_H_
#define BSDCOMMON_H_

#define BSD_COMMON

#include <stdint.h>

namespace bsdcommon {
struct cpu_load {
uint64_t old_used;
uint64_t old_total;
};

bool init_kvm();
void deinit_kvm();

void get_cpu_count(float **cpu_usage, unsigned int *cpu_count);
void update_cpu_usage(float **cpu_usage, unsigned int *cpu_count);
};

#endif /*BSDCOMMON_H_*/
9 changes: 9 additions & 0 deletions src/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@
#include "freebsd.h"
#endif /* FreeBSD */

#if defined(__NetBSD__)
#include "netbsd.h"
#endif /* NetBSD */

#if defined(__HAIKU__)
#include "haiku.h"
#endif /* Haiku */
Expand Down Expand Up @@ -411,6 +415,11 @@ int main(int argc, char **argv) {

conky::shutdown_display_outputs();

#ifdef BSD_COMMON
bsdcommon::deinit_kvm();
#endif

//TODO(gmb): Move this to bsdcommon and remove external kd.
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
kvm_close(kd);
#endif
Expand Down
68 changes: 11 additions & 57 deletions src/netbsd.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

#include "netbsd.h"
#include "net_stat.h"
#include "bsdcommon.h"

#include <err.h>
#include <fcntl.h>
Expand All @@ -53,23 +54,10 @@
#include <net/if.h>
#include <net/if_types.h>

static kvm_t *kd = nullptr;
static int kd_init = 0, nkd_init = 0, cpu_setup = 0;
static int nkd_init = 0;
static u_int32_t sensvalue;
static char errbuf[_POSIX2_LINE_MAX];

static int init_kvm(void) {
if (kd_init) { return 0; }

kd = kvm_openfiles(nullptr, NULL, NULL, KVM_NO_FILES, errbuf);
if (kd == nullptr) {
NORM_ERR("cannot kvm_openfiles: %s", errbuf);
return -1;
}
kd_init = 1;
return 0;
}

static int swapmode(int *retavail, int *retfree) {
int n;
struct swapent *sep;
Expand Down Expand Up @@ -243,6 +231,8 @@ int update_net_stats() {
int update_total_processes() {
/* It's easier to use kvm here than sysctl */

// TODO(gmb): Use bsdcommon.
/*
int n_processes;
info.procs = 0;
Expand All @@ -255,10 +245,14 @@ int update_total_processes() {
}
info.procs = n_processes;
*/
return 1;
}

int update_running_processes() {

// TODO(gmb): Use bsdcommon.
/*
struct kinfo_proc2 *p;
int n_processes;
int i, cnt = 0;
Expand All @@ -279,56 +273,16 @@ int update_running_processes() {
}
info.run_procs = cnt;

*/
return 1;
}

struct cpu_load_struct {
unsigned long load[5];
};

struct cpu_load_struct fresh = {{0, 0, 0, 0, 0}};

long cpu_used, oldtotal, oldused;

// TODO(gmb): Implement support for multiple processors.
void get_cpu_count(void) {
int cpu_count = 1;
info.cpu_count = cpu_count;
info.cpu_usage = (float *)malloc((info.cpu_count + 1) * sizeof(float));
if (info.cpu_usage == nullptr) { CRIT_ERR("malloc"); }
bsdcommon::get_cpu_count(&info.cpu_usage, &info.cpu_count);
}

// TODO(gmb): Implement support for multiple processors.
int update_cpu_usage() {
long used, total;
static u_int64_t cp_time[CPUSTATES];
size_t len = sizeof(cp_time);

info.cpu_usage[0] = 0;

if (sysctlbyname("kern.cp_time", &cp_time, &len, nullptr, 0) < 0) {
NORM_ERR("cannot get kern.cp_time");
return 1;
}

fresh.load[0] = cp_time[CP_USER];
fresh.load[1] = cp_time[CP_NICE];
fresh.load[2] = cp_time[CP_SYS];
fresh.load[3] = cp_time[CP_IDLE];
fresh.load[4] = cp_time[CP_IDLE];

used = fresh.load[0] + fresh.load[1] + fresh.load[2];
total = fresh.load[0] + fresh.load[1] + fresh.load[2] + fresh.load[3];

if ((total - oldtotal) != 0) {
info.cpu_usage[0] = ((float)(used - oldused)) / (float)(total - oldtotal);
} else {
info.cpu_usage[0] = 0;
}

oldused = used;
oldtotal = total;
bsdcommon::update_cpu_usage(&info.cpu_usage, &info.cpu_count);
return 1;
}

Expand Down
2 changes: 2 additions & 0 deletions src/netbsd.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#include "common.h"
#include "conky.h"

#include "bsdcommon.h"

int get_entropy_avail(unsigned int *);
int get_entropy_poolsize(unsigned int *);

Expand Down

0 comments on commit 005d830

Please sign in to comment.