summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathan Scott <nathans@redhat.com>2023-05-02 16:56:18 +1000
committerNathan Scott <nathans@redhat.com>2023-05-08 13:06:38 +1000
commit72235d8e098d9d79029dca65122605741e1aafad (patch)
tree96593b8bd9dc95dc5ab321bd363d36351cbd0a99
parent0bdade1b6cb40c5bd374a93ac0489058a7421bb5 (diff)
Adapt platform code for the new Machine base class
Move host-centric data to new derived <Platform>Machine classes, separate from process-list-centric data.
-rw-r--r--CommandLine.c6
-rw-r--r--Machine.h2
-rw-r--r--Makefile.am18
-rw-r--r--ProcessList.c10
-rw-r--r--ProcessList.h6
-rw-r--r--ScreenManager.c7
-rw-r--r--darwin/DarwinMachine.c113
-rw-r--r--darwin/DarwinMachine.h28
-rw-r--r--darwin/DarwinProcess.c5
-rw-r--r--darwin/DarwinProcessList.c102
-rw-r--r--darwin/DarwinProcessList.h21
-rw-r--r--darwin/Platform.c23
-rw-r--r--dragonflybsd/DragonFlyBSDMachine.c341
-rw-r--r--dragonflybsd/DragonFlyBSDMachine.h61
-rw-r--r--dragonflybsd/DragonFlyBSDProcessList.c353
-rw-r--r--dragonflybsd/DragonFlyBSDProcessList.h47
-rw-r--r--dragonflybsd/Platform.c27
-rw-r--r--freebsd/FreeBSDMachine.c396
-rw-r--r--freebsd/FreeBSDMachine.h54
-rw-r--r--freebsd/FreeBSDProcessList.c386
-rw-r--r--freebsd/FreeBSDProcessList.h41
-rw-r--r--freebsd/Platform.c32
-rw-r--r--linux/HugePageMeter.c8
-rw-r--r--linux/LibSensors.c2
-rw-r--r--linux/LibSensors.h2
-rw-r--r--linux/LinuxMachine.c707
-rw-r--r--linux/LinuxMachine.h110
-rw-r--r--linux/LinuxProcess.c14
-rw-r--r--linux/LinuxProcessList.c763
-rw-r--r--linux/LinuxProcessList.h92
-rw-r--r--linux/Platform.c53
-rw-r--r--netbsd/NetBSDMachine.c282
-rw-r--r--netbsd/NetBSDMachine.h54
-rw-r--r--netbsd/NetBSDProcessList.c280
-rw-r--r--netbsd/NetBSDProcessList.h40
-rw-r--r--netbsd/Platform.c7
-rw-r--r--openbsd/OpenBSDMachine.c286
-rw-r--r--openbsd/OpenBSDMachine.h53
-rw-r--r--openbsd/OpenBSDProcessList.c299
-rw-r--r--openbsd/OpenBSDProcessList.h43
-rw-r--r--openbsd/Platform.c9
-rw-r--r--pcp/PCPMachine.c332
-rw-r--r--pcp/PCPMachine.h68
-rw-r--r--pcp/PCPProcessList.c369
-rw-r--r--pcp/PCPProcessList.h52
-rw-r--r--pcp/Platform.c32
-rw-r--r--solaris/Platform.c21
-rw-r--r--solaris/SolarisMachine.c332
-rw-r--r--solaris/SolarisMachine.h59
-rw-r--r--solaris/SolarisProcessList.c332
-rw-r--r--solaris/SolarisProcessList.h36
-rw-r--r--unsupported/UnsupportedMachine.c56
-rw-r--r--unsupported/UnsupportedMachine.h17
-rw-r--r--unsupported/UnsupportedProcessList.c35
-rw-r--r--unsupported/UnsupportedProcessList.h14
55 files changed, 3672 insertions, 3266 deletions
diff --git a/CommandLine.c b/CommandLine.c
index 9e2018ef..8095fa8f 100644
--- a/CommandLine.c
+++ b/CommandLine.c
@@ -383,9 +383,11 @@ int CommandLine_run(int argc, char** argv) {
ScreenManager* scr = ScreenManager_new(header, host, &state, true);
ScreenManager_add(scr, (Panel*) panel, -1);
- ProcessList_scan(pl, false);
+ Machine_scan(host);
+ ProcessList_scan(pl);
CommandLine_delay(host, 75);
- ProcessList_scan(pl, false);
+ Machine_scan(host);
+ ProcessList_scan(pl);
if (settings->ss->allBranchesCollapsed)
ProcessList_collapseAllBranches(pl);
diff --git a/Machine.h b/Machine.h
index 3683701a..4628d686 100644
--- a/Machine.h
+++ b/Machine.h
@@ -86,4 +86,6 @@ bool Machine_isCPUonline(const Machine* this, unsigned int id);
void Machine_addList(Machine* this, struct ProcessList_ *pl);
+void Machine_scan(Machine* this);
+
#endif
diff --git a/Makefile.am b/Makefile.am
index 94db4d77..b25d1cb8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -166,6 +166,7 @@ linux_platform_headers = \
linux/IOPriority.h \
linux/IOPriorityPanel.h \
linux/LibSensors.h \
+ linux/LinuxMachine.h \
linux/LinuxProcess.h \
linux/LinuxProcessList.h \
linux/Platform.h \
@@ -188,6 +189,7 @@ linux_platform_sources = \
linux/HugePageMeter.c \
linux/IOPriorityPanel.c \
linux/LibSensors.c \
+ linux/LinuxMachine.c \
linux/LinuxProcess.c \
linux/LinuxProcessList.c \
linux/Platform.c \
@@ -208,6 +210,7 @@ endif
# -------
freebsd_platform_headers = \
+ freebsd/FreeBSDMachine.h \
freebsd/FreeBSDProcessList.h \
freebsd/FreeBSDProcess.h \
freebsd/Platform.h \
@@ -223,6 +226,7 @@ freebsd_platform_headers = \
freebsd_platform_sources = \
freebsd/Platform.c \
+ freebsd/FreeBSDMachine.c \
freebsd/FreeBSDProcessList.c \
freebsd/FreeBSDProcess.c \
generic/fdstat_sysctl.c \
@@ -242,6 +246,7 @@ endif
# ------------
dragonflybsd_platform_headers = \
+ dragonflybsd/DragonFlyBSDMachine.h \
dragonflybsd/DragonFlyBSDProcessList.h \
dragonflybsd/DragonFlyBSDProcess.h \
dragonflybsd/Platform.h \
@@ -252,6 +257,7 @@ dragonflybsd_platform_headers = \
generic/uname.h
dragonflybsd_platform_sources = \
+ dragonflybsd/DragonFlyBSDMachine.c \
dragonflybsd/DragonFlyBSDProcessList.c \
dragonflybsd/DragonFlyBSDProcess.c \
dragonflybsd/Platform.c \
@@ -275,6 +281,7 @@ netbsd_platform_headers = \
generic/uname.h \
netbsd/Platform.h \
netbsd/ProcessField.h \
+ netbsd/NetBSDMachine.h \
netbsd/NetBSDProcess.h \
netbsd/NetBSDProcessList.h
@@ -284,6 +291,7 @@ netbsd_platform_sources = \
generic/hostname.c \
generic/uname.c \
netbsd/Platform.c \
+ netbsd/NetBSDMachine.c \
netbsd/NetBSDProcess.c \
netbsd/NetBSDProcessList.c
@@ -299,6 +307,7 @@ openbsd_platform_headers = \
generic/gettime.h \
generic/hostname.h \
generic/uname.h \
+ openbsd/OpenBSDMachine.h \
openbsd/OpenBSDProcessList.h \
openbsd/OpenBSDProcess.h \
openbsd/Platform.h \
@@ -308,6 +317,7 @@ openbsd_platform_sources = \
generic/gettime.c \
generic/hostname.c \
generic/uname.c \
+ openbsd/OpenBSDMachine.c \
openbsd/OpenBSDProcessList.c \
openbsd/OpenBSDProcess.c \
openbsd/Platform.c
@@ -321,6 +331,7 @@ endif
# ------
darwin_platform_headers = \
+ darwin/DarwinMachine.h \
darwin/DarwinProcess.h \
darwin/DarwinProcessList.h \
darwin/Platform.h \
@@ -338,6 +349,7 @@ darwin_platform_headers = \
darwin_platform_sources = \
darwin/Platform.c \
darwin/PlatformHelpers.c \
+ darwin/DarwinMachine.c \
darwin/DarwinProcess.c \
darwin/DarwinProcessList.c \
generic/fdstat_sysctl.c \
@@ -363,6 +375,7 @@ solaris_platform_headers = \
generic/uname.h \
solaris/ProcessField.h \
solaris/Platform.h \
+ solaris/SolarisMachine.h \
solaris/SolarisProcess.h \
solaris/SolarisProcessList.h \
zfs/ZfsArcMeter.h \
@@ -374,6 +387,7 @@ solaris_platform_sources = \
generic/hostname.c \
generic/uname.c \
solaris/Platform.c \
+ solaris/SolarisMachine.c \
solaris/SolarisProcess.c \
solaris/SolarisProcessList.c \
zfs/ZfsArcMeter.c \
@@ -393,6 +407,7 @@ pcp_platform_headers = \
linux/ZramStats.h \
pcp/PCPDynamicColumn.h \
pcp/PCPDynamicMeter.h \
+ pcp/PCPMachine.h \
pcp/PCPMetric.h \
pcp/PCPProcess.h \
pcp/PCPProcessList.h \
@@ -407,6 +422,7 @@ pcp_platform_sources = \
linux/ZramMeter.c \
pcp/PCPDynamicColumn.c \
pcp/PCPDynamicMeter.c \
+ pcp/PCPMachine.c \
pcp/PCPMetric.c \
pcp/PCPProcess.c \
pcp/PCPProcessList.c \
@@ -427,12 +443,14 @@ unsupported_platform_headers = \
generic/gettime.h \
unsupported/Platform.h \
unsupported/ProcessField.h \
+ unsupported/UnsupportedMachine.h \
unsupported/UnsupportedProcess.h \
unsupported/UnsupportedProcessList.h
unsupported_platform_sources = \
generic/gettime.c \
unsupported/Platform.c \
+ unsupported/UnsupportedMachine.c \
unsupported/UnsupportedProcess.c \
unsupported/UnsupportedProcessList.c
diff --git a/ProcessList.c b/ProcessList.c
index 49217b8c..58e63d03 100644
--- a/ProcessList.c
+++ b/ProcessList.c
@@ -410,13 +410,7 @@ Process* ProcessList_getProcess(ProcessList* this, pid_t pid, bool* preExisting,
return proc;
}
-void ProcessList_scan(ProcessList* this, bool pauseProcessUpdate) {
- // in pause mode only gather global data for meters (CPU/memory/...)
- if (pauseProcessUpdate) {
- ProcessList_goThroughEntries(this, true);
- return;
- }
-
+void ProcessList_scan(ProcessList* this) {
// mark all process as "dirty"
for (int i = 0; i < Vector_size(this->processes); i++) {
Process* p = (Process*) Vector_get(this->processes, i);
@@ -442,7 +436,7 @@ void ProcessList_scan(ProcessList* this, bool pauseProcessUpdate) {
firstScanDone = true;
}
- ProcessList_goThroughEntries(this, false);
+ ProcessList_goThroughEntries(this);
uid_t maxUid = 0;
const Settings* settings = host->settings;
diff --git a/ProcessList.h b/ProcessList.h
index d09cc072..0f0f7d51 100644
--- a/ProcessList.h
+++ b/ProcessList.h
@@ -49,8 +49,8 @@ typedef struct ProcessList_ {
/* Implemented by platforms */
ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList);
-void ProcessList_delete(ProcessList* pl);
-void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
+void ProcessList_delete(ProcessList* this);
+void ProcessList_goThroughEntries(ProcessList* this);
void ProcessList_init(ProcessList* this, const ObjectClass* klass, Machine* host, Hashtable* pidMatchList);
@@ -74,7 +74,7 @@ void ProcessList_rebuildPanel(ProcessList* this);
Process* ProcessList_getProcess(ProcessList* this, pid_t pid, bool* preExisting, Process_New constructor);
-void ProcessList_scan(ProcessList* this, bool pauseProcessUpdate);
+void ProcessList_scan(ProcessList* this);
static inline Process* ProcessList_findProcess(ProcessList* this, pid_t pid) {
return (Process*) Hashtable_get(this->processTable, pid);
diff --git a/ScreenManager.c b/ScreenManager.c
index f1897893..18e09343 100644
--- a/ScreenManager.c
+++ b/ScreenManager.c
@@ -16,6 +16,7 @@ in the source distribution for its full text.
#include "CRT.h"
#include "FunctionBar.h"
+#include "Machine.h"
#include "Macros.h"
#include "Object.h"
#include "Platform.h"
@@ -135,8 +136,10 @@ static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTi
host->pl->needsSort = true;
*sortTimeout = 1;
}
- // scan processes first - some header values are calculated there
- ProcessList_scan(host->pl, this->state->pauseUpdate);
+ // sample current values for system metrics and processes if not paused
+ Machine_scan(host);
+ if (!this->state->pauseUpdate)
+ ProcessList_scan(host->pl);
// always update header, especially to avoid gaps in graph meters
Header_updateData(this->header);
// force redraw if the number of UID digits was changed
diff --git a/darwin/DarwinMachine.c b/darwin/DarwinMachine.c
new file mode 100644
index 00000000..6bf52b76
--- /dev/null
+++ b/darwin/DarwinMachine.c
@@ -0,0 +1,113 @@
+/*
+htop - DarwinMachine.c
+(C) 2014 Hisham H. Muhammad
+Released under the GNU GPLv2+, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "darwin/DarwinMachine.h"
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+
+#include "CRT.h"
+#include "Machine.h"
+#include "darwin/Platform.h"
+#include "darwin/PlatformHelpers.h"
+#include "generic/openzfs_sysctl.h"
+#include "zfs/ZfsArcStats.h"
+
+
+static void DarwinMachine_getHostInfo(host_basic_info_data_t* p) {
+ mach_msg_type_number_t info_size = HOST_BASIC_INFO_COUNT;
+
+ if (0 != host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)p, &info_size)) {
+ CRT_fatalError("Unable to retrieve host info");
+ }
+}
+
+static void DarwinMachine_freeCPULoadInfo(processor_cpu_load_info_t* p) {
+ if (NULL != p && NULL != *p) {
+ if (0 != munmap(*p, vm_page_size)) {
+ CRT_fatalError("Unable to free old CPU load information");
+ }
+ *p = NULL;
+ }
+}
+
+static unsigned DarwinMachine_allocateCPULoadInfo(processor_cpu_load_info_t* p) {
+ mach_msg_type_number_t info_size = sizeof(processor_cpu_load_info_t);
+ unsigned cpu_count;
+
+ // TODO Improving the accuracy of the load counts would help a lot.
+ if (0 != host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &cpu_count, (processor_info_array_t*)p, &info_size)) {
+ CRT_fatalError("Unable to retrieve CPU info");
+ }
+
+ return cpu_count;
+}
+
+static void DarwinMachine_getVMStats(vm_statistics_t p) {
+ mach_msg_type_number_t info_size = HOST_VM_INFO_COUNT;
+
+ if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)p, &info_size) != 0) {
+ CRT_fatalError("Unable to retrieve VM statistics");
+ }
+}
+
+void Machine_scan(Machine* super) {
+ DarwinMachine* host = (DarwinMachine*) super;
+
+ /* Update the global data (CPU times and VM stats) */
+ DarwinMachine_freeCPULoadInfo(&host->prev_load);
+ host->prev_load = host->curr_load;
+ DarwinMachine_allocateCPULoadInfo(&host->curr_load);
+ DarwinMachine_getVMStats(&host->vm_stats);
+ openzfs_sysctl_updateArcStats(&host->zfs);
+}
+
+Machine* Machine_new(UsersTable* usersTable, uid_t userId) {
+ DarwinMachine* this = xCalloc(1, sizeof(DarwinMachine));
+ Machine* super = &this->super;
+
+ Machine_init(super, usersTable, userId);
+
+ /* Initialize the CPU information */
+ super->activeCPUs = DarwinMachine_allocateCPULoadInfo(&this->prev_load);
+ super->existingCPUs = super->activeCPUs;
+ DarwinMachine_getHostInfo(&this->host_info);
+ DarwinMachine_allocateCPULoadInfo(&this->curr_load);
+
+ /* Initialize the VM statistics */
+ DarwinMachine_getVMStats(&this->vm_stats);
+
+ /* Initialize the ZFS kstats, if zfs.kext loaded */
+ openzfs_sysctl_init(&this->zfs);
+ openzfs_sysctl_updateArcStats(&this->zfs);
+
+ return super;
+}
+
+void Machine_delete(Machine* super) {
+ DarwinMachine* host = (DarwinMachine*) super;
+
+ DarwinMachine_freeCPULoadInfo(&host->prev_load);
+
+ Machine_done(super);
+ free(super);
+}
+
+bool Machine_isCPUonline(const Machine* host, unsigned int id) {
+ assert(id < host->existingCPUs);
+
+ // TODO: support offline CPUs and hot swapping
+ (void) host; (void) id;
+
+ return true;
+}
diff --git a/darwin/DarwinMachine.h b/darwin/DarwinMachine.h
new file mode 100644
index 00000000..3135b589
--- /dev/null
+++ b/darwin/DarwinMachine.h
@@ -0,0 +1,28 @@
+#ifndef HEADER_DarwinMachine
+#define HEADER_DarwinMachine
+/*
+htop - DarwinMachine.h
+(C) 2014 Hisham H. Muhammad
+Released under the GNU GPLv2+, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include <mach/mach_host.h>
+#include <sys/sysctl.h>
+
+#include "Machine.h"
+#include "zfs/ZfsArcStats.h"
+
+
+typedef struct DarwinMachine_ {
+ Machine super;
+
+ host_basic_info_data_t host_info;
+ vm_statistics_data_t vm_stats;
+ processor_cpu_load_info_t prev_load;
+ processor_cpu_load_info_t curr_load;
+
+ ZfsArcStats zfs;
+} DarwinMachine;
+
+#endif
diff --git a/darwin/DarwinProcess.c b/darwin/DarwinProcess.c
index 22004e36..e6366d70 100644
--- a/darwin/DarwinProcess.c
+++ b/darwin/DarwinProcess.c
@@ -16,6 +16,7 @@ in the source distribution for its full text.
#include "CRT.h"
#include "Process.h"
+#include "darwin/DarwinMachine.h"
#include "darwin/Platform.h"
@@ -365,6 +366,8 @@ void DarwinProcess_setFromLibprocPidinfo(DarwinProcess* proc, DarwinProcessList*
struct proc_taskinfo pti;
if (sizeof(pti) == proc_pidinfo(proc->super.pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti))) {
+ const DarwinMachine* dhost = (const DarwinMachine*) proc->super.host;
+
uint64_t total_existing_time_ns = proc->stime + proc->utime;
uint64_t user_time_ns = Platform_machTicksToNanoseconds(pti.pti_total_user);
@@ -386,7 +389,7 @@ void DarwinProcess_setFromLibprocPidinfo(DarwinProcess* proc, DarwinProcessList*
proc->super.m_resident = pti.pti_resident_size / ONE_K;
proc->super.majflt = pti.pti_faults;
proc->super.percent_mem = (double)pti.pti_resident_size * 100.0
- / (double)dpl->host_info.max_mem;
+ / (double)dhost->host_info.max_mem;
proc->stime = system_time_ns;
proc->utime = user_time_ns;
diff --git a/darwin/DarwinProcessList.c b/darwin/DarwinProcessList.c
index 16c44d2c..bf311dc7 100644
--- a/darwin/DarwinProcessList.c
+++ b/darwin/DarwinProcessList.c
@@ -20,6 +20,7 @@ in the source distribution for its full text.
#include "CRT.h"
#include "ProcessList.h"
+#include "darwin/DarwinMachine.h"
#include "darwin/DarwinProcess.h"
#include "darwin/Platform.h"
#include "darwin/PlatformHelpers.h"
@@ -27,43 +28,6 @@ in the source distribution for its full text.
#include "zfs/ZfsArcStats.h"
-static void ProcessList_getHostInfo(host_basic_info_data_t* p) {
- mach_msg_type_number_t info_size = HOST_BASIC_INFO_COUNT;
-
- if (0 != host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)p, &info_size)) {
- CRT_fatalError("Unable to retrieve host info");
- }
-}
-
-static void ProcessList_freeCPULoadInfo(processor_cpu_load_info_t* p) {
- if (NULL != p && NULL != *p) {
- if (0 != munmap(*p, vm_page_size)) {
- CRT_fatalError("Unable to free old CPU load information");
- }
- *p = NULL;
- }
-}
-
-static unsigned ProcessList_allocateCPULoadInfo(processor_cpu_load_info_t* p) {
- mach_msg_type_number_t info_size = sizeof(processor_cpu_load_info_t);
- unsigned cpu_count;
-
- // TODO Improving the accuracy of the load counts woule help a lot.
- if (0 != host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &cpu_count, (processor_info_array_t*)p, &info_size)) {
- CRT_fatalError("Unable to retrieve CPU info");
- }
-
- return cpu_count;
-}
-
-static void ProcessList_getVMStats(vm_statistics_t p) {
- mach_msg_type_number_t info_size = HOST_VM_INFO_COUNT;
-
- if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)p, &info_size) != 0) {
- CRT_fatalError("Unable to retrieve VM statistics");
- }
-}
-
static struct kinfo_proc* ProcessList_getKInfoProcs(size_t* count) {
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
struct kinfo_proc* processes = NULL;
@@ -91,29 +55,11 @@ static struct kinfo_proc* ProcessList_getKInfoProcs(size_t* count) {
ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList) {
DarwinProcessList* this = xCalloc(1, sizeof(DarwinProcessList));
+ ProcessList* super = &this->super;
- ProcessList_init(&this->super, Class(DarwinProcess), host, pidMatchList);
-
- /* Initialize the CPU information */
- host->activeCPUs = ProcessList_allocateCPULoadInfo(&this->prev_load);
- // TODO: support offline CPUs and hot swapping
- host->existingCPUs = host->activeCPUs;
- ProcessList_getHostInfo(&this->host_info);
- ProcessList_allocateCPULoadInfo(&this->curr_load);
-
- /* Initialize the VM statistics */
- ProcessList_getVMStats(&this->vm_stats);
-
- /* Initialize the ZFS kstats, if zfs.kext loaded */
- openzfs_sysctl_init(&this->zfs);
- openzfs_sysctl_updateArcStats(&this->zfs);
+ ProcessList_init(super, Class(DarwinProcess), host, pidMatchList);
- this->super.kernelThreads = 0;
- this->super.userlandThreads = 0;
- this->super.totalTasks = 0;
- this->super.runningTasks = 0;
-
- return &this->super;
+ return super;
}
void ProcessList_delete(ProcessList* this) {
@@ -121,31 +67,20 @@ void ProcessList_delete(ProcessList* this) {
free(this);
}
-void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
- DarwinProcessList* dpl = (DarwinProcessList*)super;
+void ProcessList_goThroughEntries(ProcessList* super) {
const Machine* host = super->host;
+ const DarwinMachine* dhost = (const DarwinMachine*) host;
+ DarwinProcessList* dpl = (DarwinProcessList*) super;
bool preExisting = true;
struct kinfo_proc* ps;
size_t count;
DarwinProcess* proc;
- /* Update the global data (CPU times and VM stats) */
- ProcessList_freeCPULoadInfo(&dpl->prev_load);
- dpl->prev_load = dpl->curr_load;
- ProcessList_allocateCPULoadInfo(&dpl->curr_load);
- ProcessList_getVMStats(&dpl->vm_stats);
- openzfs_sysctl_updateArcStats(&dpl->zfs);
-
- // in pause mode only gather global data for meters (CPU/memory/...)
- if (pauseProcessUpdate) {
- return;
- }
-
/* Get the time difference */
dpl->global_diff = 0;
for (unsigned int i = 0; i < host->existingCPUs; ++i) {
for (size_t j = 0; j < CPU_STATE_MAX; ++j) {
- dpl->global_diff += dpl->curr_load[i].cpu_ticks[j] - dpl->prev_load[i].cpu_ticks[j];
+ dpl->global_diff += dhost->curr_load[i].cpu_ticks[j] - dhost->prev_load[i].cpu_ticks[j];
}
}
@@ -178,7 +113,7 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
}
// Disabled for High Sierra due to bug in macOS High Sierra
- bool isScanThreadSupported = !Platform_KernelVersionIsBetween((KernelVersion) {17, 0, 0}, (KernelVersion) {17, 5, 0});
+ bool isScanThreadSupported = !Platform_KernelVersionIsBetween((KernelVersion) {17, 0, 0}, (KernelVersion) {17, 5, 0});
if (isScanThreadSupported) {
DarwinProcess_scanThreads(proc);
@@ -193,22 +128,3 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
free(ps);
}
-
-Machine* Machine_new(UsersTable* usersTable, uid_t userId) {
- Machine* this = xCalloc(1, sizeof(Machine));
- Machine_init(this, usersTable, userId);
- return this;
-}
-
-void Machine_delete(Machine* host) {
- free(host);
-}
-
-bool Machine_isCPUonline(const Machine* host, unsigned int id) {
- assert(id < host->existingCPUs);
-
- // TODO: support offline CPUs and hot swapping
- (void) host; (void) id;
-
- return true;
-}
diff --git a/darwin/DarwinProcessList.h b/darwin/DarwinProcessList.h
index 128896ae..56d6c1b5 100644
--- a/darwin/DarwinProcessList.h
+++ b/darwin/DarwinProcessList.h
@@ -11,33 +11,12 @@ in the source distribution for its full text.
#include <sys/sysctl.h>
#include "ProcessList.h"
-#include "zfs/ZfsArcStats.h"
typedef struct DarwinProcessList_ {
ProcessList super;
- host_basic_info_data_t host_info;
- vm_statistics_data_t vm_stats;
- processor_cpu_load_info_t prev_load;
- processor_cpu_load_info_t curr_load;
- uint64_t kernel_threads;
- uint64_t user_threads;
uint64_t global_diff;
-
- ZfsArcStats zfs;
} DarwinProcessList;
-ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList);
-
-void ProcessList_delete(ProcessList* this);
-
-void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
-
-Machine* Machine_new(UsersTable* usersTable, uid_t userId);
-
-bool Machine_isCPUonline(const Machine* host, unsigned int id);
-
-void Machine_delete(Machine* host);
-
#endif
diff --git a/darwin/Platform.c b/darwin/Platform.c
index 71d08247..bb1ae92f 100644
--- a/darwin/Platform.c
+++ b/darwin/Platform.c
@@ -44,7 +44,7 @@ in the source distribution for its full text.
#include "SysArchMeter.h"
#include "TasksMeter.h"
#include "UptimeMeter.h"
-#include "darwin/DarwinProcessList.h"
+#include "darwin/DarwinMachine.h"
#include "darwin/PlatformHelpers.h"
#include "generic/fdstat_sysctl.h"
#include "zfs/ZfsArcMeter.h"
@@ -257,9 +257,9 @@ double Platform_setCPUValues(Meter* mtr, unsigned int cpu) {
return Platform_setCPUAverageValues(mtr);
}
- const DarwinProcessList* dpl = (const DarwinProcessList*)mtr->host->pl;
- const processor_cpu_load_info_t prev = &dpl->prev_load[cpu - 1];
- const processor_cpu_load_info_t curr = &dpl->curr_load[cpu - 1];
+ const DarwinMachine* dhost = (const DarwinMachine*) mtr->host;
+ const processor_cpu_load_info_t prev = &dhost->prev_load[cpu - 1];
+ const processor_cpu_load_info_t curr = &dhost->curr_load[cpu - 1];
double total = 0;
/* Take the sums */
@@ -286,12 +286,11 @@ double Platform_setCPUValues(Meter* mtr, unsigned int cpu) {
}
void Platform_setMemoryValues(Meter* mtr) {
- const Machine* host = mtr->host;
- const DarwinProcessList* dpl = (const DarwinProcessList*) host->pl;
- const struct vm_statistics* vm = &dpl->vm_stats;
+ const DarwinMachine* dhost = (const DarwinMachine*) mtr->host;
+ const struct vm_statistics* vm = &dhost->vm_stats;
double page_K = (double)vm_page_size / (double)1024;
- mtr->total = dpl->host_info.max_mem / 1024;
+ mtr->total = dhost->host_info.max_mem / 1024;
mtr->values[MEMORY_METER_USED] = (double)(vm->active_count + vm->wire_count) * page_K;
mtr->values[MEMORY_METER_BUFFERS] = (double)vm->purgeable_count * page_K;
// mtr->values[MEMORY_METER_SHARED] = "shared memory, like tmpfs and shm"
@@ -313,15 +312,15 @@ void Platform_setSwapValues(Meter* mtr) {
}
void Platform_setZfsArcValues(Meter* this) {
- const DarwinProcessList* dpl = (const DarwinProcessList*) this->host->pl;
+ const DarwinMachine* dhost = (const DarwinMachine*) this->host;
- ZfsArcMeter_readStats(this, &(dpl->zfs));
+ ZfsArcMeter_readStats(this, &dhost->zfs);
}
void Platform_setZfsCompressedArcValues(Meter* this) {
- const DarwinProcessList* dpl = (const DarwinProcessList*) this->host->pl;
+ const DarwinMachine* dhost = (const DarwinMachine*) this->host;
- ZfsCompressedArcMeter_readStats(this, &(dpl->zfs));
+ ZfsCompressedArcMeter_readStats(this, &dhost->zfs);
}
char* Platform_getProcessEnv(pid_t pid) {
diff --git a/dragonflybsd/DragonFlyBSDMachine.c b/dragonflybsd/DragonFlyBSDMachine.c
new file mode 100644
index 00000000..fc7eb3b0
--- /dev/null
+++ b/dragonflybsd/DragonFlyBSDMachine.c
@@ -0,0 +1,341 @@
+/*
+htop - DragonFlyBSDMachine.c
+(C) 2014 Hisham H. Muhammad
+(C) 2017 Diederik de Groot
+Released under the GNU GPLv2+, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "dragonflybsd/DragonFlyBSDMachine.h"
+
+#include <fcntl.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <sys/param.h>
+
+#include "CRT.h"
+#include "Macros.h"
+
+#include "dragonflybsd/DragonFlyBSDProcess.h"
+
+
+static int MIB_hw_physmem[2];
+static int MIB_vm_stats_vm_v_page_count[4];
+
+static int MIB_vm_stats_vm_v_wire_count[4];
+static int MIB_vm_stats_vm_v_active_count[4];
+static int MIB_vm_stats_vm_v_cache_count[4];
+static int MIB_vm_stats_vm_v_inactive_count[4];
+static int MIB_vm_stats_vm_v_free_count[4];
+
+static int MIB_vfs_bufspace[2];
+
+static int MIB_kern_cp_time[2];
+static int MIB_kern_cp_times[2];
+
+Machine* Machine_new(UsersTable* usersTable, uid_t userId) {
+ size_t len;
+ char errbuf[_POSIX2_LINE_MAX];
+ DragonFlyBSDMachine* this = xCalloc(1, sizeof(DragonFlyBSDMachine));
+ Machine* super = &this->super;
+
+ Machine_init(this, usersTable, userId);
+
+ // physical memory in system: hw.physmem
+ // physical page size: hw.pagesize
+ // usable pagesize : vm.stats.vm.v_page_size
+ len = 2; sysctlnametomib("hw.physmem", MIB_hw_physmem, &len);
+
+ len = sizeof(this->pageSize);
+ if (sysctlbyname("vm.stats.vm.v_page_size", &this->pageSize, &len, NULL, 0) == -1)
+ CRT_fatalError("Cannot get pagesize by sysctl");
+ this->pageSizeKb = this->pageSize / ONE_K;
+
+ // usable page count vm.stats.vm.v_page_count
+ // actually usable memory : vm.stats.vm.v_page_count * vm.stats.vm.v_page_size
+ len = 4; sysctlnametomib("vm.stats.vm.v_page_count", MIB_vm_stats_vm_v_page_count, &len);
+
+ len = 4; sysctlnametomib("vm.stats.vm.v_wire_count", MIB_vm_stats_vm_v_wire_count, &len);
+ len = 4; sysctlnametomib("vm.stats.vm.v_active_count", MIB_vm_stats_vm_v_active_count, &len);
+ len = 4; sysctlnametomib("vm.stats.vm.v_cache_count", MIB_vm_stats_vm_v_cache_count, &len);
+ len = 4; sysctlnametomib("vm.stats.vm.v_inactive_count", MIB_vm_stats_vm_v_inactive_count, &len);
+ len = 4; sysctlnametomib("vm.stats.vm.v_free_count", MIB_vm_stats_vm_v_free_count, &len);
+
+ len = 2; sysctlnametomib("vfs.bufspace", MIB_vfs_bufspace, &len);
+
+ int cpus = 1;
+ len = sizeof(cpus);
+ if (sysctlbyname("hw.ncpu", &cpus, &len, NULL, 0) != 0) {
+ cpus = 1;
+ }
+
+ size_t sizeof_cp_time_array = sizeof(unsigned long) * CPUSTATES;
+ len = 2; sysctlnametomib("kern.cp_time", MIB_kern_cp_time, &len);
+ this->cp_time_o = xCalloc(CPUSTATES, sizeof(unsigned long));
+ this->cp_time_n = xCalloc(CPUSTATES, sizeof(unsigned long));
+ len = sizeof_cp_time_array;
+
+ // fetch initial single (or average) CPU clicks from kernel
+ sysctl(MIB_kern_cp_time, 2, this->cp_time_o, &len, NULL, 0);
+
+ // on smp box, fetch rest of initial CPU's clicks
+ if (cpus > 1) {
+ len = 2; sysctlnametomib("kern.cp_times", MIB_kern_cp_times, &len);
+ this->cp_times_o = xCalloc(cpus, sizeof_cp_time_array);
+ this->cp_times_n = xCalloc(cpus, sizeof_cp_time_array);
+ len = cpus * sizeof_cp_time_array;
+ sysctl(MIB_kern_cp_times, 2, this->cp_times_o, &len, NULL, 0);
+ }
+
+ super->existingCPUs = MAXIMUM(cpus, 1);
+ // TODO: support offline CPUs and hot swapping
+ super->activeCPUs = super->existingCPUs;
+
+ if (cpus == 1 ) {
+ this->cpus = xRealloc(this->cpus, sizeof(CPUData));
+ } else {
+ // on smp we need CPUs + 1 to store averages too (as kernel kindly provides that as well)
+ this->cpus = xRealloc(this->cpus, (super->existingCPUs + 1) * sizeof(CPUData));
+ }
+
+ len = sizeof(kernelFScale);
+ if (sysctlbyname("kern.fscale", &kernelFScale, &len, NULL, 0) == -1) {
+ //sane default for kernel provided CPU percentage scaling, at least on x86 machines, in case this sysctl call failed
+ kernelFScale = 2048;
+ }
+
+ this->kd = kvm_openfiles(NULL, "/dev/null", NULL, 0, errbuf);
+ if (this->kd == NULL) {
+ CRT_fatalError("kvm_openfiles() failed");
+ }
+
+ return super;
+}
+
+void Machine_delete(Machine* super) {
+ const DragonFlyBSDMachine* this = (DragonFlyBSDProcessList*) super;
+
+ Machine_done(this);
+
+ if (this->kd) {
+ kvm_close(this->kd);
+ }
+
+ if (this->jails) {
+ Hashtable_delete(this->jails);
+ }
+
+ free(this->cp_time_o);
+ free(this->cp_time_n);
+ free(this->cp_times_o);
+ free(this->cp_times_n);
+ free(this->cpus);
+
+ free(this);
+}
+
+static void DragonFlyBSDMachine_scanCPUTime(Machine* super) {
+ const DragonFlyBSDMachine* this = (DragonFlyBSDMachine*) super;
+
+ unsigned int cpus = super->existingCPUs; // actual CPU count
+ unsigned int maxcpu = cpus; // max iteration (in case we have average + smp)
+ int cp_times_offset;
+
+ assert(cpus > 0);
+
+ size_t sizeof_cp_time_array;
+
+ unsigned long* cp_time_n; // old clicks state
+ unsigned long* cp_time_o; // current clicks state
+
+ unsigned long cp_time_d[CPUSTATES];
+ double cp_time_p[CPUSTATES];
+
+ // get averages or single CPU clicks
+ sizeof_cp_time_array = sizeof(unsigned long) * CPUSTATES;
+ sysctl(MIB_kern_cp_time, 2, this->cp_time_n, &sizeof_cp_time_array, NULL, 0);
+
+ // get rest of CPUs
+ if (cpus > 1) {
+ // on smp systems DragonFlyBSD kernel concats all CPU states into one long array in
+ // kern.cp_times sysctl OID
+ // we store averages in dfpl->cpus[0], and actual cores after that
+ maxcpu = cpus + 1;
+ sizeof_cp_time_array = cpus * sizeof(unsigned long) * CPUSTATES;
+ sysctl(MIB_kern_cp_times, 2, this->cp_times_n, &sizeof_cp_time_array, NULL, 0);
+ }
+
+ for (unsigned int i = 0; i < maxcpu; i++) {
+ if (cpus == 1) {
+ // single CPU box
+ cp_time_n = this->cp_time_n;
+ cp_time_o = this->cp_time_o;
+ } else {
+ if (i == 0 ) {
+ // average
+ cp_time_n = this->cp_time_n;
+ cp_time_o = this->cp_time_o;
+ } else {
+ // specific smp cores
+ cp_times_offset = i - 1;
+ cp_time_n = this->cp_times_n + (cp_times_offset * CPUSTATES);
+ cp_time_o = this->cp_times_o + (cp_times_offset * CPUSTATES);
+ }
+ }
+
+ // diff old vs new
+ unsigned long long total_o = 0;
+ unsigned long long total_n = 0;
+ unsigned long long total_d = 0;
+ for (int s = 0; s < CPUSTATES; s++) {
+ cp_time_d[s] = cp_time_n[s] - cp_time_o[s];
+ total_o += cp_time_o[s];
+ total_n += cp_time_n[s];
+ }
+
+ // totals
+ total_d = total_n - total_o;
+ if (total_d < 1 ) {
+ total_d = 1;
+ }
+
+ // save current state as old and calc percentages
+ for (int s = 0; s < CPUSTATES; ++s) {
+ cp_time_o[s] = cp_time_n[s];
+ cp_time_p[s] = ((double)cp_time_d[s]) / ((double)total_d) * 100;
+ }
+
+ CPUData* cpuData = &(this->cpus[i]);
+ cpuData->userPercent = cp_time_p[CP_USER];
+ cpuData->nicePercent = cp_time_p[CP_NICE];
+ cpuData->systemPercent = cp_time_p[CP_SYS];
+ cpuData->irqPercent = cp_time_p[CP_INTR];
+ cpuData->systemAllPercent = cp_time_p[CP_SYS] + cp_time_p[CP_INTR];
+ // this one is not really used, but we store it anyway
+ cpuData->idlePercent = cp_time_p[CP_IDLE];
+ }
+}
+
+static void DragonFlyBSDMachine_scanMemoryInfo(Machine* super) {
+ DragonFlyBSDMachine* this = (DragonFlyBSDProcessList*) super;
+
+ // @etosan:
+ // memory counter relationships seem to be these:
+ // total = active + wired + inactive + cache + free
+ // htop_used (unavail to anybody) = active + wired
+ // htop_cache (for cache meter) = buffers + cache
+ // user_free (avail to procs) = buffers + inactive + cache + free
+ size_t len = sizeof(super->totalMem);
+
+ //disabled for now, as it is always smaller than phycal amount of memory...
+ //...to avoid "where is my memory?" questions
+ //sysctl(MIB_vm_stats_vm_v_page_count, 4, &(pl->totalMem), &len, NULL, 0);
+ //pl->totalMem *= pageSizeKb;
+ sysctl(MIB_hw_physmem, 2, &(super->totalMem), &len, NULL, 0);
+ pl->totalMem /= 1024;
+
+ sysctl(MIB_vm_stats_vm_v_active_count, 4, &(this->memActive), &len, NULL, 0);
+ this->memActive *= this->pageSizeKb;
+
+ sysctl(MIB_vm_stats_vm_v_wire_count, 4, &(this->memWire), &len, NULL, 0);
+ this->memWire *= this->pageSizeKb;
+
+ sysctl(MIB_vfs_bufspace, 2, &(super->buffersMem), &len, NULL, 0);
+ super->buffersMem /= 1024;
+
+ sysctl(MIB_vm_stats_vm_v_cache_count, 4, &(super->cachedMem), &len, NULL, 0);
+ super->cachedMem *= this->pageSizeKb;
+ super->usedMem = this->memActive + this->memWire;
+
+ struct kvm_swap swap[16];
+ int nswap = kvm_getswapinfo(this->kd, swap, ARRAYSIZE(swap), 0);
+ super->totalSwap = 0;
+ super->usedSwap = 0;
+ for (int i = 0; i < nswap; i++) {
+ super->totalSwap += swap[i].ksw_total;
+ super->usedSwap += swap[i].ksw_used;
+ }
+ super->totalSwap *= this->pageSizeKb;
+ super->usedSwap *= this->pageSizeKb;
+}
+
+static void DragonFlyBSDMachine_scanJails(DragonFlyBSDMachine* this) {
+ size_t len;
+ char* jails; /* Jail list */
+ char* curpos;
+ char* nextpos;
+
+ if (sysctlbyname("jail.list", NULL, &len, NULL, 0) == -1) {
+ CRT_fatalError("initial sysctlbyname / jail.list failed");
+ }
+
+retry:
+ if (len == 0)
+ return;
+
+ jails = xMalloc(len);
+
+ if (sysctlbyname("jail.list", jails, &len, NULL, 0) == -1) {
+ if (errno == ENOMEM) {
+ free(jails);
+ goto retry;
+ }
+ CRT_fatalError("sysctlbyname / jail.list failed");
+ }
+
+ if (this->jails) {
+ Hashtable_delete(this->jails);
+ }
+
+ this->jails = Hashtable_new(20, true);
+ curpos = jails;
+ while (curpos) {
+ int jailid;
+ char* str_hostname;
+
+ nextpos = strchr(curpos, '\n');
+ if (nextpos) {
+ *nextpos++ = 0;
+ }
+
+ jailid = atoi(strtok(curpos, " "));
+ str_hostname = strtok(NULL, " ");
+
+ char* jname = (char*) (Hashtable_get(this->jails, jailid));
+ if (jname == NULL) {
+ jname = xStrdup(str_hostname);
+ Hashtable_put(this->jails, jailid, jname);
+ }
+
+ curpos = nextpos;
+ }
+
+ free(jails);
+}
+
+char* DragonFlyBSDMachine_readJailName(DragonFlyBSDMachine* host, int jailid) {
+ char* hostname;
+ char* jname;
+
+ if (jailid != 0 && host->jails && (hostname = (char*)Hashtable_get(host->jails, jailid))) {
+ jname = xStrdup(hostname);
+ } else {
+ jname = xStrdup("-");
+ }
+
+ return jname;
+}
+
+void Machine_scan(Machine* super) {
+ DragonFlyBSDMachine* this = (DragonFlyBSDMachine*) super;
+
+ DragonFlyBSDMachine_scanMemoryInfo(super);
+ DragonFlyBSDMachine_scanCPUTime(super);
+ DragonFlyBSDMachine_scanJails(this);
+}
diff --git a/dragonflybsd/DragonFlyBSDMachine.h b/dragonflybsd/DragonFlyBSDMachine.h
new file mode 100644
index 00000000..276a73d7
--- /dev/null
+++ b/dragonflybsd/DragonFlyBSDMachine.h
@@ -0,0 +1,61 @@
+#ifndef HEADER_DragonFlyBSDMachine
+#define HEADER_DragonFlyBSDMachine
+/*
+htop - DragonFlyBSDMachine.h
+(C) 2014 Hisham H. Muhammad
+(C) 2017 Diederik de Groot
+Released under the GNU GPLv2+, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include <sys/types.h> // required for kvm.h
+#include <kvm.h>
+#include <osreldate.h>
+#include <stdbool.h>
+#include <sys/jail.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/uio.h>
+
+#include "Hashtable.h"
+#include "Machine.h"
+#include "ProcessList.h"
+#include "UsersTable.h"
+
+
+typedef struct CPUData_ {
+ double userPercent;
+ double nicePercent;
+ double systemPercent;
+ double irqPercent;
+ double idlePercent;
+ double systemAllPercent;
+} CPUData;
+
+typedef struct DragonFlyBSDMachine_ {
+ Machine super;
+ kvm_t* kd;
+
+ Hashtable* jails;
+
+ int pageSize;
+ int pageSizeKb;
+ int kernelFScale;
+
+ unsigned long long int memWire;
+ unsigned long long int memActive;
+ unsigned long long int memInactive;
+ unsigned long long int memFree;
+
+ CPUData* cpus;
+
+ unsigned long* cp_time_o;
+ unsigned long* cp_time_n;
+
+ unsigned long* cp_times_o;
+ unsigned long* cp_times_n;
+} DragonFlyBSDMachine;
+
+char* DragonFlyBSDMachine_readJailName(DragonFlyBSDMachine* host, int jailid);
+
+#endif
diff --git a/dragonflybsd/DragonFlyBSDProcessList.c b/dragonflybsd/DragonFlyBSDProcessList.c
index c66917fb..4ff17932 100644
--- a/dragonflybsd/DragonFlyBSDProcessList.c
+++ b/dragonflybsd/DragonFlyBSDProcessList.c
@@ -22,248 +22,25 @@ in the source distribution for its full text.
#include "CRT.h"
#include "Macros.h"
+#include "dragonflybsd/DragonFlyBSDMachine.h"
#include "dragonflybsd/DragonFlyBSDProcess.h"
-static int MIB_hw_physmem[2];
-static int MIB_vm_stats_vm_v_page_count[4];
-static int pageSize;
-static int pageSizeKb;
-
-static int MIB_vm_stats_vm_v_wire_count[4];
-static int MIB_vm_stats_vm_v_active_count[4];
-static int MIB_vm_stats_vm_v_cache_count[4];
-static int MIB_vm_stats_vm_v_inactive_count[4];
-static int MIB_vm_stats_vm_v_free_count[4];
-
-static int MIB_vfs_bufspace[2];
-
-static int MIB_kern_cp_time[2];
-static int MIB_kern_cp_times[2];
-static int kernelFScale;
-
ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList) {
- size_t len;
- char errbuf[_POSIX2_LINE_MAX];
- DragonFlyBSDProcessList* dfpl = xCalloc(1, sizeof(DragonFlyBSDProcessList));
- ProcessList* pl = (ProcessList*) dfpl;
- ProcessList_init(pl, Class(DragonFlyBSDProcess), host, pidMatchList);
-
- // physical memory in system: hw.physmem
- // physical page size: hw.pagesize
- // usable pagesize : vm.stats.vm.v_page_size
- len = 2; sysctlnametomib("hw.physmem", MIB_hw_physmem, &len);
-
- len = sizeof(pageSize);
- if (sysctlbyname("vm.stats.vm.v_page_size", &pageSize, &len, NULL, 0) == -1)
- CRT_fatalError("Cannot get pagesize by sysctl");
- pageSizeKb = pageSize / ONE_K;
-
- // usable page count vm.stats.vm.v_page_count
- // actually usable memory : vm.stats.vm.v_page_count * vm.stats.vm.v_page_size
- len = 4; sysctlnametomib("vm.stats.vm.v_page_count", MIB_vm_stats_vm_v_page_count, &len);
-
- len = 4; sysctlnametomib("vm.stats.vm.v_wire_count", MIB_vm_stats_vm_v_wire_count, &len);
- len = 4; sysctlnametomib("vm.stats.vm.v_active_count", MIB_vm_stats_vm_v_active_count, &len);
- len = 4; sysctlnametomib("vm.stats.vm.v_cache_count", MIB_vm_stats_vm_v_cache_count, &len);
- len = 4; sysctlnametomib("vm.stats.vm.v_inactive_count", MIB_vm_stats_vm_v_inactive_count, &len);
- len = 4; sysctlnametomib("vm.stats.vm.v_free_count", MIB_vm_stats_vm_v_free_count, &len);
-
- len = 2; sysctlnametomib("vfs.bufspace", MIB_vfs_bufspace, &len);
-
- int cpus = 1;
- len = sizeof(cpus);
- if (sysctlbyname("hw.ncpu", &cpus, &len, NULL, 0) != 0) {
- cpus = 1;
- }
+ DragonFlyBSDProcessList* this = xCalloc(1, sizeof(DragonFlyBSDProcessList));
+ ProcessList* super = (ProcessList*) this;
- size_t sizeof_cp_time_array = sizeof(unsigned long) * CPUSTATES;
- len = 2; sysctlnametomib("kern.cp_time", MIB_kern_cp_time, &len);
- dfpl->cp_time_o = xCalloc(CPUSTATES, sizeof(unsigned long));
- dfpl->cp_time_n = xCalloc(CPUSTATES, sizeof(unsigned long));
- len = sizeof_cp_time_array;
-
- // fetch initial single (or average) CPU clicks from kernel
- sysctl(MIB_kern_cp_time, 2, dfpl->cp_time_o, &len, NULL, 0);
-
- // on smp box, fetch rest of initial CPU's clicks
- if (cpus > 1) {
- len = 2; sysctlnametomib("kern.cp_times", MIB_kern_cp_times, &len);
- dfpl->cp_times_o = xCalloc(cpus, sizeof_cp_time_array);
- dfpl->cp_times_n = xCalloc(cpus, sizeof_cp_time_array);
- len = cpus * sizeof_cp_time_array;
- sysctl(MIB_kern_cp_times, 2, dfpl->cp_times_o, &len, NULL, 0);
- }
-
- host->existingCPUs = MAXIMUM(cpus, 1);
- // TODO: support offline CPUs and hot swapping
- host->activeCPUs = host->existingCPUs;
-
- if (cpus == 1 ) {
- dfpl->cpus = xRealloc(dfpl->cpus, sizeof(CPUData));
- } else {
- // on smp we need CPUs + 1 to store averages too (as kernel kindly provides that as well)
- dfpl->cpus = xRealloc(dfpl->cpus, (host->existingCPUs + 1) * sizeof(CPUData));
- }
-
- len = sizeof(kernelFScale);
- if (sysctlbyname("kern.fscale", &kernelFScale, &len, NULL, 0) == -1) {
- //sane default for kernel provided CPU percentage scaling, at least on x86 machines, in case this sysctl call failed
- kernelFScale = 2048;
- }
+ ProcessList_init(super, Class(DragonFlyBSDProcess), host, pidMatchList);
- dfpl->kd = kvm_openfiles(NULL, "/dev/null", NULL, 0, errbuf);
- if (dfpl->kd == NULL) {
- CRT_fatalError("kvm_openfiles() failed");
- }
-
- return pl;
+ return super;
}
-void ProcessList_delete(ProcessList* this) {
- const DragonFlyBSDProcessList* dfpl = (DragonFlyBSDProcessList*) this;
- if (dfpl->kd) {
- kvm_close(dfpl->kd);
- }
-
- if (dfpl->jails) {
- Hashtable_delete(dfpl->jails);
- }
- free(dfpl->cp_time_o);
- free(dfpl->cp_time_n);
- free(dfpl->cp_times_o);
- free(dfpl->cp_times_n);
- free(dfpl->cpus);
-
- ProcessList_done(this);
+void ProcessList_delete(ProcessList* super) {
+ const DragonFlyBSDProcessList* this = (DragonFlyBSDProcessList*) super;
+ ProcessList_done(super);
free(this);
}
-static inline void DragonFlyBSDProcessList_scanCPUTime(ProcessList* pl) {
- const DragonFlyBSDProcessList* dfpl = (DragonFlyBSDProcessList*) pl;
-
- unsigned int cpus = pl->existingCPUs; // actual CPU count
- unsigned int maxcpu = cpus; // max iteration (in case we have average + smp)
- int cp_times_offset;
-
- assert(cpus > 0);
-
- size_t sizeof_cp_time_array;
-
- unsigned long* cp_time_n; // old clicks state
- unsigned long* cp_time_o; // current clicks state
-
- unsigned long cp_time_d[CPUSTATES];
- double cp_time_p[CPUSTATES];
-
- // get averages or single CPU clicks
- sizeof_cp_time_array = sizeof(unsigned long) * CPUSTATES;
- sysctl(MIB_kern_cp_time, 2, dfpl->cp_time_n, &sizeof_cp_time_array, NULL, 0);
-
- // get rest of CPUs
- if (cpus > 1) {
- // on smp systems DragonFlyBSD kernel concats all CPU states into one long array in
- // kern.cp_times sysctl OID
- // we store averages in dfpl->cpus[0], and actual cores after that
- maxcpu = cpus + 1;
- sizeof_cp_time_array = cpus * sizeof(unsigned long) * CPUSTATES;
- sysctl(MIB_kern_cp_times, 2, dfpl->cp_times_n, &sizeof_cp_time_array, NULL, 0);
- }
-
- for (unsigned int i = 0; i < maxcpu; i++) {
- if (cpus == 1) {
- // single CPU box
- cp_time_n = dfpl->cp_time_n;
- cp_time_o = dfpl->cp_time_o;
- } else {
- if (i == 0 ) {
- // average
- cp_time_n = dfpl->cp_time_n;
- cp_time_o = dfpl->cp_time_o;
- } else {
- // specific smp cores
- cp_times_offset = i - 1;
- cp_time_n = dfpl->cp_times_n + (cp_times_offset * CPUSTATES);
- cp_time_o = dfpl->cp_times_o + (cp_times_offset * CPUSTATES);
- }
- }
-
- // diff old vs new
- unsigned long long total_o = 0;
- unsigned long long total_n = 0;
- unsigned long long total_d = 0;
- for (int s = 0; s < CPUSTATES; s++) {
- cp_time_d[s] = cp_time_n[s] - cp_time_o[s];
- total_o += cp_time_o[s];
- total_n += cp_time_n[s];
- }
-
- // totals
- total_d = total_n - total_o;
- if (total_d < 1 ) {
- total_d = 1;
- }
-
- // save current state as old and calc percentages
- for (int s = 0; s < CPUSTATES; ++s) {
- cp_time_o[s] = cp_time_n[s];
- cp_time_p[s] = ((double)cp_time_d[s]) / ((double)total_d) * 100;
- }
-
- CPUData* cpuData = &(dfpl->cpus[i]);
- cpuData->userPercent = cp_time_p[CP_USER];
- cpuData->nicePercent = cp_time_p[CP_NICE];
- cpuData->systemPercent = cp_time_p[CP_SYS];
- cpuData->irqPercent = cp_time_p[CP_INTR];
- cpuData->systemAllPercent = cp_time_p[CP_SYS] + cp_time_p[CP_INTR];
- // this one is not really used, but we store it anyway
- cpuData->idlePercent = cp_time_p[CP_IDLE];
- }
-}
-
-static inline void DragonFlyBSDProcessList_scanMemoryInfo(ProcessList* pl) {
- DragonFlyBSDProcessList* dfpl = (DragonFlyBSDProcessList*) pl;
-
- // @etosan:
- // memory counter relationships seem to be these:
- // total = active + wired + inactive + cache + free
- // htop_used (unavail to anybody) = active + wired
- // htop_cache (for cache meter) = buffers + cache
- // user_free (avail to procs) = buffers + inactive + cache + free
- size_t len = sizeof(pl->totalMem);
-
- //disabled for now, as it is always smaller than phycal amount of memory...
- //...to avoid "where is my memory?" questions
- //sysctl(MIB_vm_stats_vm_v_page_count, 4, &(pl->totalMem), &len, NULL, 0);
- //pl->totalMem *= pageSizeKb;
- sysctl(MIB_hw_physmem, 2, &(pl->totalMem), &len, NULL, 0);
- pl->totalMem /= 1024;
-
- sysctl(MIB_vm_stats_vm_v_active_count, 4, &(dfpl->memActive), &len, NULL, 0);
- dfpl->memActive *= pageSizeKb;
-
- sysctl(MIB_vm_stats_vm_v_wire_count, 4, &(dfpl->memWire), &len, NULL, 0);
- dfpl->memWire *= pageSizeKb;
-
- sysctl(MIB_vfs_bufspace, 2, &(pl->buffersMem), &len, NULL, 0);
- pl->buffersMem /= 1024;
-
- sysctl(MIB_vm_stats_vm_v_cache_count, 4, &(pl->cachedMem), &len, NULL, 0);
- pl->cachedMem *= pageSizeKb;
- pl->usedMem = dfpl->memActive + dfpl->memWire;
-
- struct kvm_swap swap[16];
- int nswap = kvm_getswapinfo(dfpl->kd, swap, ARRAYSIZE(swap), 0);
- pl->totalSwap = 0;
- pl->usedSwap = 0;
- for (int i = 0; i < nswap; i++) {
- pl->totalSwap += swap[i].ksw_total;
- pl->usedSwap += swap[i].ksw_used;
- }
- pl->totalSwap *= pageSizeKb;
- pl->usedSwap *= pageSizeKb;
-}
-
//static void DragonFlyBSDProcessList_updateExe(const struct kinfo_proc* kproc, Process* proc) {
// const int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, kproc->kp_pid };
// char buffer[2048];
@@ -351,92 +128,17 @@ static void DragonFlyBSDProcessList_updateProcessName(kvm_t* kd, const struct ki
free(cmdline);
}
-static inline void DragonFlyBSDProcessList_scanJails(DragonFlyBSDProcessList* dfpl) {
- size_t len;
- char* jls; /* Jail list */
- char* curpos;
- char* nextpos;
-
- if (sysctlbyname("jail.list", NULL, &len, NULL, 0) == -1) {
- CRT_fatalError("initial sysctlbyname / jail.list failed");
- }
-
-retry:
- if (len == 0)
- return;
-
- jls = xMalloc(len);
-
- if (sysctlbyname("jail.list", jls, &len, NULL, 0) == -1) {
- if (errno == ENOMEM) {
- free(jls);
- goto retry;
- }
- CRT_fatalError("sysctlbyname / jail.list failed");
- }
-
- if (dfpl->jails) {
- Hashtable_delete(dfpl->jails);
- }
-
- dfpl->jails = Hashtable_new(20, true);
- curpos = jls;
- while (curpos) {
- int jailid;
- char* str_hostname;
-
- nextpos = strchr(curpos, '\n');
- if (nextpos) {
- *nextpos++ = 0;
- }
-
- jailid = atoi(strtok(curpos, " "));
- str_hostname = strtok(NULL, " ");
-
- char* jname = (char*) (Hashtable_get(dfpl->jails, jailid));
- if (jname == NULL) {
- jname = xStrdup(str_hostname);
- Hashtable_put(dfpl->jails, jailid, jname);
- }
-
- curpos = nextpos;
- }
-
- free(jls);
-}
-
-static char* DragonFlyBSDProcessList_readJailName(DragonFlyBSDProcessList* dfpl, int jailid) {
- char* hostname;
- char* jname;
-
- if (jailid != 0 && dfpl->jails && (hostname = (char*)Hashtable_get(dfpl->jails, jailid))) {
- jname = xStrdup(hostname);
- } else {
- jname = xStrdup("-");
- }
-
- return jname;
-}
-
-void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
- DragonFlyBSDProcessList* dfpl = (DragonFlyBSDProcessList*) super;
+void ProcessList_goThroughEntries(ProcessList* super) {
const Machine* host = super->host;
+ const DragonFlyMachine* dhost = (const DragonFlyMachine*) host;
const Settings* settings = host->settings;
+
bool hideKernelThreads = settings->hideKernelThreads;
bool hideUserlandThreads = settings->hideUserlandThreads;
- DragonFlyBSDProcessList_scanMemoryInfo(super);
- DragonFlyBSDProcessList_scanCPUTime(super);
- DragonFlyBSDProcessList_scanJails(dfpl);
-
- // in pause mode only gather global data for meters (CPU/memory/...)
- if (pauseProcessUpdate) {
- return;
- }
-
int count = 0;
- const struct kinfo_proc* kprocs = kvm_getprocs(dfpl->kd, KERN_PROC_ALL | (!hideUserlandThreads ? KERN_PROC_FLAG_LWP : 0), 0, &count);
+ const struct kinfo_proc* kprocs = kvm_getprocs(dhost->kd, KERN_PROC_ALL | (!hideUserlandThreads ? KERN_PROC_FLAG_LWP : 0), 0, &count);
for (int i = 0; i < count; i++) {
const struct kinfo_proc* kproc = &kprocs[i];
@@ -480,7 +182,7 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
}
DragonFlyBSDProcessList_updateExe(kproc, proc);
- DragonFlyBSDProcessList_updateProcessName(dfpl->kd, kproc, proc);
+ DragonFlyBSDProcessList_updateProcessName(dhost->kd, kproc, proc);
if (settings->ss->flags & PROCESS_FLAG_CWD) {
DragonFlyBSDProcessList_updateCwd(kproc, proc);
@@ -488,13 +190,13 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
ProcessList_add(super, proc);
- dfp->jname = DragonFlyBSDProcessList_readJailName(dfpl, kproc->kp_jailid);
+ dfp->jname = DragonFlyBSDMachine_readJailName(dhost, kproc->kp_jailid);
} else {
proc->processor = kproc->kp_lwp.kl_cpuid;
if (dfp->jid != kproc->kp_jailid) { // process can enter jail anytime
dfp->jid = kproc->kp_jailid;
free(dfp->jname);
- dfp->jname = DragonFlyBSDProcessList_readJailName(dfpl, kproc->kp_jailid);
+ dfp->jname = DragonFlyBSDMachine_readJailName(dhost, kproc->kp_jailid);
}
// if there are reapers in the system, process can get reparented anytime
proc->ppid = kproc->kp_ppid;
@@ -503,16 +205,16 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
proc->user = UsersTable_getRef(host->usersTable, proc->st_uid);
}
if (settings->updateProcessNames) {
- DragonFlyBSDProcessList_updateProcessName(dfpl->kd, kproc, proc);
+ DragonFlyBSDProcessList_updateProcessName(dhost->kd, kproc, proc);
}
}
proc->m_virt = kproc->kp_vm_map_size / ONE_K;
- proc->m_resident = kproc->kp_vm_rssize * pageSizeKb;
+ proc->m_resident = kproc->kp_vm_rssize * dhost->pageSizeKb;
proc->nlwp = kproc->kp_nthreads; // number of lwp thread
proc->time = (kproc->kp_lwp.kl_uticks + kproc->kp_lwp.kl_sticks + kproc->kp_lwp.kl_iticks) / 10000;
- proc->percent_cpu = 100.0 * ((double)kproc->kp_lwp.kl_pctcpu / (double)kernelFScale);
+ proc->percent_cpu = 100.0 * ((double)kproc->kp_lwp.kl_pctcpu / (double)dhost->kernelFScale);
proc->percent_mem = 100.0 * proc->m_resident / (double)(super->totalMem);
Process_updateCPUFieldWidths(proc->percent_cpu);
@@ -605,22 +307,3 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
proc->updated = true;
}
}
-
-Machine* Machine_new(UsersTable* usersTable, uid_t userId) {
- Machine* this = xCalloc(1, sizeof(Machine));
- Machine_init(this, usersTable, userId);
- return this;
-}
-
-void Machine_delete(Machine* host) {
- free(host);
-}
-
-bool Machine_isCPUonline(const Machine* host, unsigned int id) {
- assert(id < host->existingCPUs);
-
- // TODO: support offline CPUs and hot swapping
- (void) host; (void) id;
-
- return true;
-}
diff --git a/dragonflybsd/DragonFlyBSDProcessList.h b/dragonflybsd/DragonFlyBSDProcessList.h
index 406722e0..3f5cdc3e 100644
--- a/dragonflybsd/DragonFlyBSDProcessList.h
+++ b/dragonflybsd/DragonFlyBSDProcessList.h
@@ -8,61 +8,14 @@ Released under the GNU GPLv2+, see the COPYING file
in the source distribution for its full text.
*/
-#include <sys/types.h> // required for kvm.h
-#include <kvm.h>
-#include <osreldate.h>
#include <stdbool.h>
-#include <sys/jail.h>
#include <sys/param.h>
-#include <sys/resource.h>
-#include <sys/uio.h>
-#include "Hashtable.h"
#include "ProcessList.h"
-#include "UsersTable.h"
-#include "dragonflybsd/DragonFlyBSDProcess.h"
-
-
-typedef struct CPUData_ {
- double userPercent;
- double nicePercent;
- double systemPercent;
- double irqPercent;
- double idlePercent;
- double systemAllPercent;
-} CPUData;
typedef struct DragonFlyBSDProcessList_ {
ProcessList super;
- kvm_t* kd;
-
- unsigned long long int memWire;
- unsigned long long int memActive;
- unsigned long long int memInactive;
- unsigned long long int memFree;
-
- CPUData* cpus;
-
- unsigned long* cp_time_o;
- unsigned long* cp_time_n;
-
- unsigned long* cp_times_o;
- unsigned long* cp_times_n;
-
- Hashtable* jails;
} DragonFlyBSDProcessList;
-ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList);
-
-void ProcessList_delete(ProcessList* this);
-
-void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
-
-Machine* Machine_new(UsersTable* usersTable, uid_t userId);
-
-bool Machine_isCPUonline(const Machine* host, unsigned int id);
-
-void Machine_delete(Machine* host);
-
#endif
diff --git a/dragonflybsd/Platform.c b/dragonflybsd/Platform.c
index 1c0ef0a4..36307e93 100644
--- a/dragonflybsd/Platform.c
+++ b/dragonflybsd/Platform.c
@@ -173,15 +173,15 @@ int Platform_getMaxPid(void) {
double Platform_setCPUValues(Meter* this, unsigned int cpu) {
const Machine* host = this->host;
- const DragonFlyBSDProcessList* fpl = (const DragonFlyBSDProcessList*) host->pl;
- unsigned int cpus = this->host->activeCPUs;
+ const DragonFlyBSDMachine* dhost = (const DragonFlyBSDMachine*) host;
+ unsigned int cpus = host->activeCPUs;
const CPUData* cpuData;
if (cpus == 1) {
// single CPU box has everything in fpl->cpus[0]
- cpuData = &(fpl->cpus[0]);
+ cpuData = &(dhost->cpus[0]);
} else {
- cpuData = &(fpl->cpus[cpu]);
+ cpuData = &(dhost->cpus[cpu]);
}
double percent;
@@ -189,7 +189,7 @@ double Platform_setCPUValues(Meter* this, unsigned int cpu) {
v[CPU_METER_NICE] = cpuData->nicePercent;
v[CPU_METER_NORMAL] = cpuData->userPercent;
- if (host->settings->detailedCPUTime) {
+ if (super->settings->detailedCPUTime) {
v[CPU_METER_KERNEL] = cpuData->systemPercent;
v[CPU_METER_IRQ] = cpuData->irqPercent;
this->curItems = 4;
@@ -209,22 +209,21 @@ double Platform_setCPUValues(Meter* this, unsigned int cpu) {
}
void Platform_setMemoryValues(Meter* this) {
- // TODO
- const ProcessList* pl = this->host->pl;
+ const Machine* host = this->host;
- this->total = pl->totalMem;
- this->values[MEMORY_METER_USED] = pl->usedMem;
- this->values[MEMORY_METER_BUFFERS] = pl->buffersMem;
+ this->total = host->totalMem;
+ this->values[MEMORY_METER_USED] = host->usedMem;
+ this->values[MEMORY_METER_BUFFERS] = host->buffersMem;
// this->values[MEMORY_METER_SHARED] = "shared memory, like tmpfs and shm"
// mtr->values[MEMORY_METER_COMPRESSED] = "compressed memory, like zswap on linux"
- this->values[MEMORY_METER_CACHE] = pl->cachedMem;
+ this->values[MEMORY_METER_CACHE] = host->cachedMem;
// this->values[MEMORY_METER_AVAILABLE] = "available memory"
}
void Platform_setSwapValues(Meter* this) {
- const ProcessList* pl = this->host->pl;
- this->total = pl->totalSwap;
- this->values[SWAP_METER_USED] = pl->usedSwap;
+ const Machine* host = this->host;
+ this->total = host->totalSwap;
+ this->values[SWAP_METER_USED] = host->usedSwap;
// mtr->values[SWAP_METER_CACHE] = "pages that are both in swap and RAM, like SwapCached on linux"
// mtr->values[SWAP_METER_FRONTSWAP] = "pages that are accounted to swap but stored elsewhere, like frontswap on linux"
}
diff --git a/freebsd/FreeBSDMachine.c b/freebsd/FreeBSDMachine.c
new file mode 100644
index 00000000..b8d5d87f
--- /dev/null
+++ b/freebsd/FreeBSDMachine.c
@@ -0,0 +1,396 @@
+/*
+htop - FreeBSDMachine.c
+(C) 2014 Hisham H. Muhammad
+Released under the GNU GPLv2+, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "config.h" // IWYU pragma: keep
+
+#include "freebsd/FreeBSDMachine.h"
+
+#include <assert.h>
+#include <limits.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/_iovec.h>
+#include <sys/errno.h>
+#include <sys/param.h> // needs to be included before <sys/jail.h> for MAXPATHLEN
+#include <sys/jail.h>
+#include <sys/priority.h>
+#include <sys/proc.h>
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/vmmeter.h>
+
+#include "CRT.h"
+#include "Compat.h"
+#include "Macros.h"
+#include "Object.h"
+#include "Scheduling.h"
+#include "Settings.h"
+#include "XUtils.h"
+#include "generic/openzfs_sysctl.h"
+#include "zfs/ZfsArcStats.h"
+
+
+static int MIB_hw_physmem[2];
+static int MIB_vm_stats_vm_v_page_count[4];
+
+static int MIB_vm_stats_vm_v_wire_count[4];
+static int MIB_vm_stats_vm_v_active_count[4];
+static int MIB_vm_stats_vm_v_cache_count[4];
+static int MIB_vm_stats_vm_v_inactive_count[4];
+static int MIB_vm_stats_vm_v_free_count[4];
+static int MIB_vm_vmtotal[2];
+
+static int MIB_vfs_bufspace[2];
+
+static int MIB_kern_cp_time[2];
+static int MIB_kern_cp_times[2];
+
+Machine* Machine_new(UsersTable* usersTable, uid_t userId) {
+ FreeBSDMachine* this = xCalloc(1, sizeof(FreeBSDMachine));
+ Machine* super = &this->super;
+ char errbuf[_POSIX2_LINE_MAX];
+ size_t len;
+
+ Machine_init(this, usersTable, userId);
+
+ // physical memory in system: hw.physmem
+ // physical page size: hw.pagesize
+ // usable pagesize : vm.stats.vm.v_page_size
+ len = 2; sysctlnametomib("hw.physmem", MIB_hw_physmem, &len);
+
+ len = sizeof(this->pageSize);
+ if (sysctlbyname("vm.stats.vm.v_page_size", &this->pageSize, &len, NULL, 0) == -1)
+ CRT_fatalError("Cannot get pagesize by sysctl");
+ this->pageSizeKb = this->pageSize / ONE_K;
+
+ // usable page count vm.stats.vm.v_page_count
+ // actually usable memory : vm.stats.vm.v_page_count * vm.stats.vm.v_page_size
+ len = 4; sysctlnametomib("vm.stats.vm.v_page_count", MIB_vm_stats_vm_v_page_count, &len);
+
+ len = 4; sysctlnametomib("vm.stats.vm.v_wire_count", MIB_vm_stats_vm_v_wire_count, &len);
+ len = 4; sysctlnametomib("vm.stats.vm.v_active_count", MIB_vm_stats_vm_v_active_count, &len);
+ len = 4; sysctlnametomib("vm.stats.vm.v_cache_count", MIB_vm_stats_vm_v_cache_count, &len);
+ len = 4; sysctlnametomib("vm.stats.vm.v_inactive_count", MIB_vm_stats_vm_v_inactive_count, &len);
+ len = 4; sysctlnametomib("vm.stats.vm.v_free_count", MIB_vm_stats_vm_v_free_count, &len);
+ len = 2; sysctlnametomib("vm.vmtotal", MIB_vm_vmtotal, &len);
+
+ len = 2; sysctlnametomib("vfs.bufspace", MIB_vfs_bufspace, &len);
+
+ openzfs_sysctl_init(&this->zfs);
+ openzfs_sysctl_updateArcStats(&this->zfs);
+
+ int smp = 0;
+ len = sizeof(smp);
+
+ if (sysctlbyname("kern.smp.active", &smp, &len, NULL, 0) != 0 || len != sizeof(smp)) {
+ smp = 0;
+ }
+
+ int cpus = 1;
+ len = sizeof(cpus);
+
+ if (smp) {
+ int err = sysctlbyname("kern.smp.cpus", &cpus, &len, NULL, 0);
+ if (err) {
+ cpus = 1;
+ }
+ } else {
+ cpus = 1;
+ }
+
+ size_t sizeof_cp_time_array = sizeof(unsigned long) * CPUSTATES;
+ len = 2; sysctlnametomib("kern.cp_time", MIB_kern_cp_time, &len);
+ this->cp_time_o = xCalloc(CPUSTATES, sizeof(unsigned long));
+ this->cp_time_n = xCalloc(CPUSTATES, sizeof(unsigned long));
+ len = sizeof_cp_time_array;
+
+ // fetch initial single (or average) CPU clicks from kernel
+ sysctl(MIB_kern_cp_time, 2, this->cp_time_o, &len, NULL, 0);
+
+ // on smp box, fetch rest of initial CPU's clicks
+ if (cpus > 1) {
+ len = 2; sysctlnametomib("kern.cp_times", MIB_kern_cp_times, &len);
+ this->cp_times_o = xCalloc(cpus, sizeof_cp_time_array);
+ this->cp_times_n = xCalloc(cpus, sizeof_cp_time_array);
+ len = cpus * sizeof_cp_time_array;
+ sysctl(MIB_kern_cp_times, 2, this->cp_times_o, &len, NULL, 0);
+ }
+
+ super->existingCPUs = MAXIMUM(cpus, 1);
+ // TODO: support offline CPUs and hot swapping
+ super->activeCPUs = super->existingCPUs;
+
+ if (cpus == 1 ) {
+ this->cpus = xRealloc(this->cpus, sizeof(CPUData));
+ } else {
+ // on smp we need CPUs + 1 to store averages too (as kernel kindly provides that as well)
+ this->cpus = xRealloc(this->cpus, (super->existingCPUs + 1) * sizeof(CPUData));
+ }
+
+ len = sizeof(this->kernelFScale);
+ if (sysctlbyname("kern.fscale", &this->kernelFScale, &len, NULL, 0) == -1) {
+ //sane default for kernel provided CPU percentage scaling, at least on x86 machines, in case this sysctl call failed
+ this->kernelFScale = 2048;
+ }
+
+ this->kd = kvm_openfiles(NULL, "/dev/null", NULL, 0, errbuf);
+ if (this->kd == NULL) {
+ CRT_fatalError("kvm_openfiles() failed");
+ }
+
+ return this;
+}
+
+void Machine_delete(Machine* super) {
+ FreeBSDMachine* this = (FreeBSDMachine*) super;
+
+ ProcessList_done(this);
+
+ if (this->kd) {
+ kvm_close(this->kd);
+ }
+
+ free(this->cp_time_o);
+ free(this->cp_time_n);
+ free(this->cp_times_o);
+ free(this->cp_times_n);
+ free(this->cpus);
+
+ free(this);
+}
+
+static inline void FreeBSDMachine_scanCPU(Machine* super) {
+ const FreeBSDMachine* this = (FreeBSDMachine*) super;
+
+ unsigned int cpus = super->existingCPUs; // actual CPU count
+ unsigned int maxcpu = cpus; // max iteration (in case we have average + smp)
+ int cp_times_offset;
+
+ assert(cpus > 0);
+
+ size_t sizeof_cp_time_array;
+
+ unsigned long* cp_time_n; // old clicks state
+ unsigned long* cp_time_o; // current clicks state
+
+ unsigned long cp_time_d[CPUSTATES];
+ double cp_time_p[CPUSTATES];
+
+ // get averages or single CPU clicks
+ sizeof_cp_time_array = sizeof(unsigned long) * CPUSTATES;
+ sysctl(MIB_kern_cp_time, 2, this->cp_time_n, &sizeof_cp_time_array, NULL, 0);
+
+ // get rest of CPUs
+ if (cpus > 1) {
+ // on smp systems FreeBSD kernel concats all CPU states into one long array in
+ // kern.cp_times sysctl OID
+ // we store averages in this->cpus[0], and actual cores after that
+ maxcpu = cpus + 1;
+ sizeof_cp_time_array = cpus * sizeof(unsigned long) * CPUSTATES;
+ sysctl(MIB_kern_cp_times, 2, this->cp_times_n, &sizeof_cp_time_array, NULL, 0);
+ }
+
+ for (unsigned int i = 0; i < maxcpu; i++) {
+ if (cpus == 1) {
+ // single CPU box
+ cp_time_n = this->cp_time_n;
+ cp_time_o = this->cp_time_o;
+ } else {
+ if (i == 0 ) {
+ // average
+ cp_time_n = this->cp_time_n;
+ cp_time_o = this->cp_time_o;
+ } else {
+ // specific smp cores
+ cp_times_offset = i - 1;
+ cp_time_n = this->cp_times_n + (cp_times_offset * CPUSTATES);
+ cp_time_o = this->cp_times_o + (cp_times_offset * CPUSTATES);
+ }
+ }
+
+ // diff old vs new
+ unsigned long long total_o = 0;
+ unsigned long long total_n = 0;
+ unsigned long long total_d = 0;
+ for (int s = 0; s < CPUSTATES; s++) {
+ cp_time_d[s] = cp_time_n[s] - cp_time_o[s];
+ total_o += cp_time_o[s];
+ total_n += cp_time_n[s];
+ }
+
+ // totals
+ total_d = total_n - total_o;
+ if (total_d < 1 ) {
+ total_d = 1;
+ }
+
+ // save current state as old and calc percentages
+ for (int s = 0; s < CPUSTATES; ++s) {
+ cp_time_o[s] = cp_time_n[s];
+ cp_time_p[s] = ((double)cp_time_d[s]) / ((double)total_d) * 100;
+ }
+
+ CPUData* cpuData = &(this->cpus[i]);
+ cpuData->userPercent = cp_time_p[CP_USER];
+ cpuData->nicePercent = cp_time_p[CP_NICE];
+ cpuData->systemPercent = cp_time_p[CP_SYS];
+ cpuData->irqPercent = cp_time_p[CP_INTR];
+ cpuData->systemAllPercent = cp_time_p[CP_SYS] + cp_time_p[CP_INTR];
+ // this one is not really used
+ //cpuData->idlePercent = cp_time_p[CP_IDLE];
+
+ cpuData->temperature = NAN;
+ cpuData->frequency = NAN;
+
+ const int coreId = (cpus == 1) ? 0 : ((int)i - 1);
+ if (coreId < 0)
+ continue;
+
+ // TODO: test with hyperthreading and multi-cpu systems
+ if (super->settings->showCPUTemperature) {
+ int temperature;
+ size_t len = sizeof(temperature);
+ char mibBuffer[32];
+ xSnprintf(mibBuffer, sizeof(mibBuffer), "dev.cpu.%d.temperature", coreId);
+ int r = sysctlbyname(mibBuffer, &temperature, &len, NULL, 0);
+ if (r == 0)
+ cpuData->temperature = (double)(temperature - 2732) / 10.0; // convert from deci-Kelvin to Celsius
+ }
+
+ // TODO: test with hyperthreading and multi-cpu systems
+ if (super->settings->showCPUFrequency) {
+ int frequency;
+ size_t len = sizeof(frequency);
+ char mibBuffer[32];
+ xSnprintf(mibBuffer, sizeof(mibBuffer), "dev.cpu.%d.freq", coreId);
+ int r = sysctlbyname(mibBuffer, &frequency, &len, NULL, 0);
+ if (r == 0)
+ cpuData->frequency = frequency; // keep in MHz
+ }
+ }
+
+ // calculate max temperature and avg frequency for average meter and
+ // propagate frequency to all cores if only supplied for CPU 0
+ if (cpus > 1) {
+ if (super->settings->showCPUTemperature) {
+ double maxTemp = NAN;
+ for (unsigned int i = 1; i < maxcpu; i++) {
+ const double coreTemp = this->cpus[i].temperature;
+ if (isnan(coreTemp))
+ continue;
+
+ maxTemp = MAXIMUM(maxTemp, coreTemp);
+ }
+
+ this->cpus[0].temperature = maxTemp;
+ }
+
+ if (super->settings->showCPUFrequency) {
+ const double coreZeroFreq = this->cpus[1].frequency;
+ double freqSum = coreZeroFreq;
+ if (!isnan(coreZeroFreq)) {
+ for (unsigned int i = 2; i < maxcpu; i++) {
+ if (isnan(this->cpus[i].frequency))
+ this->cpus[i].frequency = coreZeroFreq;
+
+ freqSum += this->cpus[i].frequency;
+ }
+
+ this->cpus[0].frequency = freqSum / (maxcpu - 1);
+ }
+ }
+ }
+}
+
+static void FreeBSDMachine_scanMemoryInfo(Machine* super) {
+ FreeBSDMachine* this = (FreeBSDMachine*) super;
+
+ // @etosan:
+ // memory counter relationships seem to be these:
+ // total = active + wired + inactive + cache + free
+ // htop_used (unavail to anybody) = active + wired
+ // htop_cache (for cache meter) = buffers + cache
+ // user_free (avail to procs) = buffers + inactive + cache + free
+ //
+ // with ZFS ARC situation becomes bit muddled, as ARC behaves like "user_free"
+ // and belongs into cache, but is reported as wired by kernel
+ //
+ // htop_used = active + (wired - arc)
+ // htop_cache = buffers + cache + arc
+ u_long totalMem;
+ u_int memActive, memWire, cachedMem;
+ long buffersMem;
+ size_t len;
+ struct vmtotal vmtotal;
+
+ //disabled for now, as it is always smaller than phycal amount of memory...
+ //...to avoid "where is my memory?" questions
+ //sysctl(MIB_vm_stats_vm_v_page_count, 4, &(super->totalMem), &len, NULL, 0);
+ //super->totalMem *= this->pageSizeKb;
+ len = sizeof(totalMem);
+ sysctl(MIB_hw_physmem, 2, &(totalMem), &len, NULL, 0);
+ totalMem /= 1024;
+ super->totalMem = totalMem;
+
+ len = sizeof(memActive);
+ sysctl(MIB_vm_stats_vm_v_active_count, 4, &(memActive), &len, NULL, 0);
+ memActive *= this->pageSizeKb;
+ this->memActive = memActive;
+
+ len = sizeof(memWire);
+ sysctl(MIB_vm_stats_vm_v_wire_count, 4, &(memWire), &len, NULL, 0);
+ memWire *= this->pageSizeKb;
+ this->memWire = memWire;
+
+ len = sizeof(buffersMem);
+ sysctl(MIB_vfs_bufspace, 2, &(buffersMem), &len, NULL, 0);
+ buffersMem /= 1024;
+ super->buffersMem = buffersMem;
+
+ len = sizeof(cachedMem);
+ sysctl(MIB_vm_stats_vm_v_cache_count, 4, &(cachedMem), &len, NULL, 0);
+ cachedMem *= this->pageSizeKb;
+ super->cachedMem = cachedMem;
+
+ len = sizeof(vmtotal);
+ sysctl(MIB_vm_vmtotal, 2, &(vmtotal), &len, NULL, 0);
+ super->sharedMem = vmtotal.t_rmshr * this->pageSizeKb;
+
+ super->usedMem = this->memActive + this->memWire;
+
+ struct kvm_swap swap[16];
+ int nswap = kvm_getswapinfo(this->kd, swap, ARRAYSIZE(swap), 0);
+ super->totalSwap = 0;
+ super->usedSwap = 0;
+ for (int i = 0; i < nswap; i++) {
+ super->totalSwap += swap[i].ksw_total;
+ super->usedSwap += swap[i].ksw_used;
+ }
+ super->totalSwap *= this->pageSizeKb;
+ super->usedSwap *= this->pageSizeKb;
+}
+
+void Machine_scan(Machine* super) {
+ FreeBSDMachine* this = (FreeBSDMachine*) super;
+
+ openzfs_sysctl_updateArcStats(&this->zfs);
+ FreeBSDMachine_scanMemoryInfo(super);
+ FreeBSDMachine_scanCPU(super);
+}
+
+bool Machine_isCPUonline(const Machine* host, unsigned int id) {
+ assert(id < host->existingCPUs);
+
+ // TODO: support offline CPUs and hot swapping
+ (void) host; (void) id;
+
+ return true;
+}
diff --git a/freebsd/FreeBSDMachine.h b/freebsd/FreeBSDMachine.h
new file mode 100644
index 00000000..1a90534e
--- /dev/null
+++ b/freebsd/FreeBSDMachine.h
@@ -0,0 +1,54 @@
+#ifndef HEADER_FreeBSDMachine
+#define HEADER_FreeBSDMachine
+/*
+htop - FreeBSDMachine.h
+(C) 2014 Hisham H. Muhammad
+Released under the GNU GPLv2+, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include <kvm.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+#include "Hashtable.h"
+#include "Machine.h"
+#include "UsersTable.h"
+#include "zfs/ZfsArcStats.h"
+
+
+typedef struct CPUData_ {
+ double userPercent;
+ double nicePercent;
+ double systemPercent;
+ double irqPercent;
+ double systemAllPercent;
+
+ double frequency;
+ double temperature;
+} CPUData;
+
+typedef struct FreeBSDProcessList_ {
+ Machine super;
+ kvm_t* kd;
+
+ int pageSize;
+ int pageSizeKb;
+ int kernelFScale;
+
+ unsigned long long int memWire;
+ unsigned long long int memActive;
+
+ ZfsArcStats zfs;
+
+ CPUData* cpus;
+
+ unsigned long* cp_time_o;
+ unsigned long* cp_time_n;
+
+ unsigned long* cp_times_o;
+ unsigned long* cp_times_n;
+
+} FreeBSDProcessList;
+
+#endif
diff --git a/freebsd/FreeBSDProcessList.c b/freebsd/FreeBSDProcessList.c
index bd6e3aac..1cf32502 100644
--- a/freebsd/FreeBSDProcessList.c
+++ b/freebsd/FreeBSDProcessList.c
@@ -37,354 +37,25 @@ in the source distribution for its full text.
#include "Scheduling.h"
#include "Settings.h"
#include "XUtils.h"
-#include "generic/openzfs_sysctl.h"
-#include "zfs/ZfsArcStats.h"
-static int MIB_hw_physmem[2];
-static int MIB_vm_stats_vm_v_page_count[4];
-static int pageSize;
-static int pageSizeKb;
-
-static int MIB_vm_stats_vm_v_wire_count[4];
-static int MIB_vm_stats_vm_v_active_count[4];
-static int MIB_vm_stats_vm_v_cache_count[4];
-static int MIB_vm_stats_vm_v_inactive_count[4];
-static int MIB_vm_stats_vm_v_free_count[4];
-static int MIB_vm_vmtotal[2];
-
-static int MIB_vfs_bufspace[2];
-
-static int MIB_kern_cp_time[2];
-static int MIB_kern_cp_times[2];
-static int kernelFScale;
-
ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList) {
- size_t len;
- char errbuf[_POSIX2_LINE_MAX];
- FreeBSDProcessList* fpl = xCalloc(1, sizeof(FreeBSDProcessList));
- ProcessList* pl = (ProcessList*) fpl;
- ProcessList_init(pl, Class(FreeBSDProcess), host, pidMatchList);
-
- // physical memory in system: hw.physmem
- // physical page size: hw.pagesize
- // usable pagesize : vm.stats.vm.v_page_size
- len = 2; sysctlnametomib("hw.physmem", MIB_hw_physmem, &len);
-
- len = sizeof(pageSize);
- if (sysctlbyname("vm.stats.vm.v_page_size", &pageSize, &len, NULL, 0) == -1)
- CRT_fatalError("Cannot get pagesize by sysctl");
- pageSizeKb = pageSize / ONE_K;
-
- // usable page count vm.stats.vm.v_page_count
- // actually usable memory : vm.stats.vm.v_page_count * vm.stats.vm.v_page_size
- len = 4; sysctlnametomib("vm.stats.vm.v_page_count", MIB_vm_stats_vm_v_page_count, &len);
-
- len = 4; sysctlnametomib("vm.stats.vm.v_wire_count", MIB_vm_stats_vm_v_wire_count, &len);
- len = 4; sysctlnametomib("vm.stats.vm.v_active_count", MIB_vm_stats_vm_v_active_count, &len);
- len = 4; sysctlnametomib("vm.stats.vm.v_cache_count", MIB_vm_stats_vm_v_cache_count, &len);
- len = 4; sysctlnametomib("vm.stats.vm.v_inactive_count", MIB_vm_stats_vm_v_inactive_count, &len);
- len = 4; sysctlnametomib("vm.stats.vm.v_free_count", MIB_vm_stats_vm_v_free_count, &len);
- len = 2; sysctlnametomib("vm.vmtotal", MIB_vm_vmtotal, &len);
-
- len = 2; sysctlnametomib("vfs.bufspace", MIB_vfs_bufspace, &len);
-
- openzfs_sysctl_init(&fpl->zfs);
- openzfs_sysctl_updateArcStats(&fpl->zfs);
-
- int smp = 0;
- len = sizeof(smp);
-
- if (sysctlbyname("kern.smp.active", &smp, &len, NULL, 0) != 0 || len != sizeof(smp)) {
- smp = 0;
- }
+ FreeBSDProcessList* this = xCalloc(1, sizeof(FreeBSDProcessList));
+ ProcessList* super = &this->super;
- int cpus = 1;
- len = sizeof(cpus);
-
- if (smp) {
- int err = sysctlbyname("kern.smp.cpus", &cpus, &len, NULL, 0);
- if (err) {
- cpus = 1;
- }
- } else {
- cpus = 1;
- }
-
- size_t sizeof_cp_time_array = sizeof(unsigned long) * CPUSTATES;
- len = 2; sysctlnametomib("kern.cp_time", MIB_kern_cp_time, &len);
- fpl->cp_time_o = xCalloc(CPUSTATES, sizeof(unsigned long));
- fpl->cp_time_n = xCalloc(CPUSTATES, sizeof(unsigned long));
- len = sizeof_cp_time_array;
-
- // fetch initial single (or average) CPU clicks from kernel
- sysctl(MIB_kern_cp_time, 2, fpl->cp_time_o, &len, NULL, 0);
-
- // on smp box, fetch rest of initial CPU's clicks
- if (cpus > 1) {
- len = 2; sysctlnametomib("kern.cp_times", MIB_kern_cp_times, &len);
- fpl->cp_times_o = xCalloc(cpus, sizeof_cp_time_array);
- fpl->cp_times_n = xCalloc(cpus, sizeof_cp_time_array);
- len = cpus * sizeof_cp_time_array;
- sysctl(MIB_kern_cp_times, 2, fpl->cp_times_o, &len, NULL, 0);
- }
+ ProcessList_init(super, Class(FreeBSDProcess), host, pidMatchList);
- host->existingCPUs = MAXIMUM(cpus, 1);
- // TODO: support offline CPUs and hot swapping
- host->activeCPUs = host->existingCPUs;
-
- if (cpus == 1 ) {
- fpl->cpus = xRealloc(fpl->cpus, sizeof(CPUData));
- } else {
- // on smp we need CPUs + 1 to store averages too (as kernel kindly provides that as well)
- fpl->cpus = xRealloc(fpl->cpus, (host->existingCPUs + 1) * sizeof(CPUData));
- }
-
-
- len = sizeof(kernelFScale);
- if (sysctlbyname("kern.fscale", &kernelFScale, &len, NULL, 0) == -1) {
- //sane default for kernel provided CPU percentage scaling, at least on x86 machines, in case this sysctl call failed
- kernelFScale = 2048;
- }
-
- fpl->kd = kvm_openfiles(NULL, "/dev/null", NULL, 0, errbuf);
- if (fpl->kd == NULL) {
- CRT_fatalError("kvm_openfiles() failed");
- }
-
- return pl;
+ return this;
}
-void ProcessList_delete(ProcessList* this) {
- const FreeBSDProcessList* fpl = (FreeBSDProcessList*) this;
+void ProcessList_delete(ProcessList* super) {
+ FreeBSDProcessList* this = (FreeBSDProcessList*) super;
- if (fpl->kd) {
- kvm_close(fpl->kd);
- }
-
- free(fpl->cp_time_o);
- free(fpl->cp_time_n);
- free(fpl->cp_times_o);
- free(fpl->cp_times_n);
- free(fpl->cpus);
+ ProcessList_done(super);
- ProcessList_done(this);
free(this);
}
-static inline void FreeBSDProcessList_scanCPU(ProcessList* pl) {
- const FreeBSDProcessList* fpl = (FreeBSDProcessList*) pl;
- const Machine* host = pl->host;
-
- unsigned int cpus = host->existingCPUs; // actual CPU count
- unsigned int maxcpu = cpus; // max iteration (in case we have average + smp)
- int cp_times_offset;
-
- assert(cpus > 0);
-
- size_t sizeof_cp_time_array;
-
- unsigned long* cp_time_n; // old clicks state
- unsigned long* cp_time_o; // current clicks state
-
- unsigned long cp_time_d[CPUSTATES];
- double cp_time_p[CPUSTATES];
-
- // get averages or single CPU clicks
- sizeof_cp_time_array = sizeof(unsigned long) * CPUSTATES;
- sysctl(MIB_kern_cp_time, 2, fpl->cp_time_n, &sizeof_cp_time_array, NULL, 0);
-
- // get rest of CPUs
- if (cpus > 1) {
- // on smp systems FreeBSD kernel concats all CPU states into one long array in
- // kern.cp_times sysctl OID
- // we store averages in fpl->cpus[0], and actual cores after that
- maxcpu = cpus + 1;
- sizeof_cp_time_array = cpus * sizeof(unsigned long) * CPUSTATES;
- sysctl(MIB_kern_cp_times, 2, fpl->cp_times_n, &sizeof_cp_time_array, NULL, 0);
- }
-
- for (unsigned int i = 0; i < maxcpu; i++) {
- if (cpus == 1) {
- // single CPU box
- cp_time_n = fpl->cp_time_n;
- cp_time_o = fpl->cp_time_o;
- } else {
- if (i == 0 ) {
- // average
- cp_time_n = fpl->cp_time_n;
- cp_time_o = fpl->cp_time_o;
- } else {
- // specific smp cores
- cp_times_offset = i - 1;
- cp_time_n = fpl->cp_times_n + (cp_times_offset * CPUSTATES);
- cp_time_o = fpl->cp_times_o + (cp_times_offset * CPUSTATES);
- }
- }
-
- // diff old vs new
- unsigned long long total_o = 0;
- unsigned long long total_n = 0;
- unsigned long long total_d = 0;
- for (int s = 0; s < CPUSTATES; s++) {
- cp_time_d[s] = cp_time_n[s] - cp_time_o[s];
- total_o += cp_time_o[s];
- total_n += cp_time_n[s];
- }
-
- // totals
- total_d = total_n - total_o;
- if (total_d < 1 ) {
- total_d = 1;
- }
-
- // save current state as old and calc percentages
- for (int s = 0; s < CPUSTATES; ++s) {
- cp_time_o[s] = cp_time_n[s];
- cp_time_p[s] = ((double)cp_time_d[s]) / ((double)total_d) * 100;
- }
-
- CPUData* cpuData = &(fpl->cpus[i]);
- cpuData->userPercent = cp_time_p[CP_USER];
- cpuData->nicePercent = cp_time_p[CP_NICE];
- cpuData->systemPercent = cp_time_p[CP_SYS];
- cpuData->irqPercent = cp_time_p[CP_INTR];
- cpuData->systemAllPercent = cp_time_p[CP_SYS] + cp_time_p[CP_INTR];
- // this one is not really used
- //cpuData->idlePercent = cp_time_p[CP_IDLE];
-
- cpuData->temperature = NAN;
- cpuData->frequency = NAN;
-
- const int coreId = (cpus == 1) ? 0 : ((int)i - 1);
- if (coreId < 0)
- continue;
-
- // TODO: test with hyperthreading and multi-cpu systems
- if (host->settings->showCPUTemperature) {
- int temperature;
- size_t len = sizeof(temperature);
- char mibBuffer[32];
- xSnprintf(mibBuffer, sizeof(mibBuffer), "dev.cpu.%d.temperature", coreId);
- int r = sysctlbyname(mibBuffer, &temperature, &len, NULL, 0);
- if (r == 0)
- cpuData->temperature = (double)(temperature - 2732) / 10.0; // convert from deci-Kelvin to Celsius
- }
-
- // TODO: test with hyperthreading and multi-cpu systems
- if (host->settings->showCPUFrequency) {
- int frequency;
- size_t len = sizeof(frequency);
- char mibBuffer[32];
- xSnprintf(mibBuffer, sizeof(mibBuffer), "dev.cpu.%d.freq", coreId);
- int r = sysctlbyname(mibBuffer, &frequency, &len, NULL, 0);
- if (r == 0)
- cpuData->frequency = frequency; // keep in MHz
- }
- }
-
- // calculate max temperature and avg frequency for average meter and
- // propagate frequency to all cores if only supplied for CPU 0
- if (cpus > 1) {
- if (host->settings->showCPUTemperature) {
- double maxTemp = NAN;
- for (unsigned int i = 1; i < maxcpu; i++) {
- const double coreTemp = fpl->cpus[i].temperature;
- if (isnan(coreTemp))
- continue;
-
- maxTemp = MAXIMUM(maxTemp, coreTemp);
- }
-
- fpl->cpus[0].temperature = maxTemp;
- }
-
- if (host->settings->showCPUFrequency) {
- const double coreZeroFreq = fpl->cpus[1].frequency;
- double freqSum = coreZeroFreq;
- if (!isnan(coreZeroFreq)) {
- for (unsigned int i = 2; i < maxcpu; i++) {
- if (isnan(fpl->cpus[i].frequency))
- fpl->cpus[i].frequency = coreZeroFreq;
-
- freqSum += fpl->cpus[i].frequency;
- }
-
- fpl->cpus[0].frequency = freqSum / (maxcpu - 1);
- }
- }
- }
-}
-
-static inline void FreeBSDProcessList_scanMemoryInfo(ProcessList* pl) {
- FreeBSDProcessList* fpl = (FreeBSDProcessList*) pl;
- Machine* host = pl->host;
-
- // @etosan:
- // memory counter relationships seem to be these:
- // total = active + wired + inactive + cache + free
- // htop_used (unavail to anybody) = active + wired
- // htop_cache (for cache meter) = buffers + cache
- // user_free (avail to procs) = buffers + inactive + cache + free
- //
- // with ZFS ARC situation becomes bit muddled, as ARC behaves like "user_free"
- // and belongs into cache, but is reported as wired by kernel
- //
- // htop_used = active + (wired - arc)
- // htop_cache = buffers + cache + arc
- u_long totalMem;
- u_int memActive, memWire, cachedMem;
- long buffersMem;
- size_t len;
- struct vmtotal vmtotal;
-
- //disabled for now, as it is always smaller than phycal amount of memory...
- //...to avoid "where is my memory?" questions
- //sysctl(MIB_vm_stats_vm_v_page_count, 4, &(host->totalMem), &len, NULL, 0);
- //host->totalMem *= pageSizeKb;
- len = sizeof(totalMem);
- sysctl(MIB_hw_physmem, 2, &(totalMem), &len, NULL, 0);
- totalMem /= 1024;
- host->totalMem = totalMem;
-
- len = sizeof(memActive);
- sysctl(MIB_vm_stats_vm_v_active_count, 4, &(memActive), &len, NULL, 0);
- memActive *= pageSizeKb;
- fpl->memActive = memActive;
-
- len = sizeof(memWire);
- sysctl(MIB_vm_stats_vm_v_wire_count, 4, &(memWire), &len, NULL, 0);
- memWire *= pageSizeKb;
- fpl->memWire = memWire;
-
- len = sizeof(buffersMem);
- sysctl(MIB_vfs_bufspace, 2, &(buffersMem), &len, NULL, 0);
- buffersMem /= 1024;
- host->buffersMem = buffersMem;
-
- len = sizeof(cachedMem);
- sysctl(MIB_vm_stats_vm_v_cache_count, 4, &(cachedMem), &len, NULL, 0);
- cachedMem *= pageSizeKb;
- host->cachedMem = cachedMem;
-
- len = sizeof(vmtotal);
- sysctl(MIB_vm_vmtotal, 2, &(vmtotal), &len, NULL, 0);
- host->sharedMem = vmtotal.t_rmshr * pageSizeKb;
-
- host->usedMem = fpl->memActive + fpl->memWire;
-
- struct kvm_swap swap[16];
- int nswap = kvm_getswapinfo(fpl->kd, swap, ARRAYSIZE(swap), 0);
- host->totalSwap = 0;
- host->usedSwap = 0;
- for (int i = 0; i < nswap; i++) {
- host->totalSwap += swap[i].ksw_total;
- host->usedSwap += swap[i].ksw_used;
- }
- host->totalSwap *= pageSizeKb;
- host->usedSwap *= pageSizeKb;
-}
-
static void FreeBSDProcessList_updateExe(const struct kinfo_proc* kproc, Process* proc) {
if (Process_isKernelThread(proc)) {
Process_updateExe(proc, NULL);
@@ -483,22 +154,14 @@ IGNORE_WCASTQUAL_END
return NULL;
}
-void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
- FreeBSDProcessList* fpl = (FreeBSDProcessList*) super;
+void ProcessList_goThroughEntries(ProcessList* super) {
const Machine* host = super->host;
+ const FreeBSDMachine* fhost = (FreeBSDMachine*) host;
+ FreeBSDProcessList* fpl = (FreeBSDProcessList*) super;
const Settings* settings = host->settings;
bool hideKernelThreads = settings->hideKernelThreads;
bool hideUserlandThreads = settings->hideUserlandThreads;
- openzfs_sysctl_updateArcStats(&fpl->zfs);
- FreeBSDProcessList_scanMemoryInfo(super);
- FreeBSDProcessList_scanCPU(super);
-
- // in pause mode only gather global data for meters (CPU/memory/...)
- if (pauseProcessUpdate) {
- return;
- }
-
int count = 0;
const struct kinfo_proc* kprocs = kvm_getprocs(fpl->kd, KERN_PROC_PROC, 0, &count);
@@ -521,14 +184,14 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
proc->st_uid = kproc->ki_uid;
proc->starttime_ctime = kproc->ki_start.tv_sec;
if (proc->starttime_ctime < 0) {
- proc->starttime_ctime = super->host.realtimeMs / 1000;
+ proc->starttime_ctime = host->realtimeMs / 1000;
}
Process_fillStarttimeBuffer(proc);
proc->user = UsersTable_getRef(host->usersTable, proc->st_uid);
ProcessList_add(super, proc);
FreeBSDProcessList_updateExe(kproc, proc);
- FreeBSDProcessList_updateProcessName(fpl->kd, kproc, proc);
+ FreeBSDProcessList_updateProcessName(fhost->kd, kproc, proc);
if (settings->ss->flags & PROCESS_FLAG_CWD) {
FreeBSDProcessList_updateCwd(kproc, proc);
@@ -559,7 +222,7 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
proc->user = UsersTable_getRef(host->usersTable, proc->st_uid);
}
if (settings->updateProcessNames) {
- FreeBSDProcessList_updateProcessName(fpl->kd, kproc, proc);
+ FreeBSDProcessList_updateProcessName(fhost->kd, kproc, proc);
}
}
@@ -567,11 +230,11 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
// from FreeBSD source /src/usr.bin/top/machine.c
proc->m_virt = kproc->ki_size / ONE_K;
- proc->m_resident = kproc->ki_rssize * pageSizeKb;
+ proc->m_resident = kproc->ki_rssize * fhost->pageSizeKb;
proc->nlwp = kproc->ki_numthreads;
proc->time = (kproc->ki_runtime + 5000) / 10000;
- proc->percent_cpu = 100.0 * ((double)kproc->ki_pctcpu / (double)kernelFScale);
+ proc->percent_cpu = 100.0 * ((double)kproc->ki_pctcpu / (double)fhost->kernelFScale);
proc->percent_mem = 100.0 * proc->m_resident / (double)(host->totalMem);
Process_updateCPUFieldWidths(proc->percent_cpu);
@@ -623,22 +286,3 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
proc->updated = true;
}
}
-
-Machine* Machine_new(UsersTable* usersTable, uid_t userId) {
- Machine* this = xCalloc(1, sizeof(Machine));
- Machine_init(this, usersTable, userId);
- return this;
-}
-
-void Machine_delete(Machine* host) {
- free(host);
-}
-
-bool Machine_isCPUonline(const Machine* host, unsigned int id) {
- assert(id < host->existingCPUs);
-
- // TODO: support offline CPUs and hot swapping
- (void) host; (void) id;
-
- return true;
-}
diff --git a/freebsd/FreeBSDProcessList.h b/freebsd/FreeBSDProcessList.h
index b7e29f8b..55247eb7 100644
--- a/freebsd/FreeBSDProcessList.h
+++ b/freebsd/FreeBSDProcessList.h
@@ -7,56 +7,15 @@ Released under the GNU GPLv2+, see the COPYING file
in the source distribution for its full text.
*/
-#include <kvm.h>
#include <stdbool.h>
#include <sys/types.h>
#include "Hashtable.h"
#include "ProcessList.h"
#include "UsersTable.h"
-#include "zfs/ZfsArcStats.h"
-
-
-typedef struct CPUData_ {
- double userPercent;
- double nicePercent;
- double systemPercent;
- double irqPercent;
- double systemAllPercent;
-
- double frequency;
- double temperature;
-} CPUData;
typedef struct FreeBSDProcessList_ {
ProcessList super;
- kvm_t* kd;
-
- unsigned long long int memWire;
- unsigned long long int memActive;
-
- ZfsArcStats zfs;
-
- CPUData* cpus;
-
- unsigned long* cp_time_o;
- unsigned long* cp_time_n;
-
- unsigned long* cp_times_o;
- unsigned long* cp_times_n;
-
} FreeBSDProcessList;
-ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList);
-
-void ProcessList_delete(ProcessList* this);
-
-void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
-
-Machine* Machine_new(UsersTable* usersTable, uid_t userId);
-
-bool Machine_isCPUonline(const Machine* host, unsigned int id);
-
-void Machine_delete(Machine* host);
-
#endif
diff --git a/freebsd/Platform.c b/freebsd/Platform.c
index 3ba2778e..0588b0fa 100644
--- a/freebsd/Platform.c
+++ b/freebsd/Platform.c
@@ -34,20 +34,19 @@ in the source distribution for its full text.
#include "FileDescriptorMeter.h"
#include "HostnameMeter.h"
#include "LoadAverageMeter.h"
+#include "Machine.h"
#include "Macros.h"
#include "MemoryMeter.h"
#include "MemorySwapMeter.h"
#include "Meter.h"
#include "NetworkIOMeter.h"
-#include "ProcessList.h"
#include "Settings.h"
#include "SwapMeter.h"
#include "SysArchMeter.h"
#include "TasksMeter.h"
#include "UptimeMeter.h"
#include "XUtils.h"
-#include "freebsd/FreeBSDProcess.h"
-#include "freebsd/FreeBSDProcessList.h"
+#include "freebsd/FreeBSDMachine.h"
#include "generic/fdstat_sysctl.h"
#include "zfs/ZfsArcMeter.h"
#include "zfs/ZfsCompressedArcMeter.h"
@@ -194,15 +193,15 @@ int Platform_getMaxPid(void) {
double Platform_setCPUValues(Meter* this, unsigned int cpu) {
const Machine* host = this->host;
- const FreeBSDProcessList* fpl = (const FreeBSDProcessList*) host->pl;
+ const FreeBSDMachine* fhost = (const FreeBSDMachine*) host;
unsigned int cpus = host->activeCPUs;
const CPUData* cpuData;
if (cpus == 1) {
- // single CPU box has everything in fpl->cpus[0]
- cpuData = &(fpl->cpus[0]);
+ // single CPU box has everything in fhost->cpus[0]
+ cpuData = &(fhost->cpus[0]);
} else {
- cpuData = &(fpl->cpus[cpu]);
+ cpuData = &(fhost->cpus[cpu]);
}
double percent;
@@ -210,7 +209,7 @@ double Platform_setCPUValues(Meter* this, unsigned int cpu) {
v[CPU_METER_NICE] = cpuData->nicePercent;
v[CPU_METER_NORMAL] = cpuData->userPercent;
- if (host->settings->detailedCPUTime) {
+ if (super->settings->detailedCPUTime) {
v[CPU_METER_KERNEL] = cpuData->systemPercent;
v[CPU_METER_IRQ] = cpuData->irqPercent;
this->curItems = 4;
@@ -231,8 +230,7 @@ double Platform_setCPUValues(Meter* this, unsigned int cpu) {
void Platform_setMemoryValues(Meter* this) {
const Machine* host = this->host;
- const ProcessList* pl = host->pl;
- const FreeBSDProcessList* fpl = (const FreeBSDProcessList*) pl;
+ const FreeBSDMachine* fhost = (const FreeBSDMachine*) host;
this->total = host->totalMem;
this->values[MEMORY_METER_USED] = host->usedMem;
@@ -242,11 +240,11 @@ void Platform_setMemoryValues(Meter* this) {
this->values[MEMORY_METER_CACHE] = host->cachedMem;
// this->values[MEMORY_METER_AVAILABLE] = "available memory"
- if (fpl->zfs.enabled) {
+ if (dhost->zfs.enabled) {
// ZFS does not shrink below the value of zfs_arc_min.
unsigned long long int shrinkableSize = 0;
- if (fpl->zfs.size > fpl->zfs.min)
- shrinkableSize = fpl->zfs.size - fpl->zfs.min;
+ if (dhost->zfs.size > dhost->zfs.min)
+ shrinkableSize = dhost->zfs.size - dhost->zfs.min;
this->values[MEMORY_METER_USED] -= shrinkableSize;
this->values[MEMORY_METER_CACHE] += shrinkableSize;
// this->values[MEMORY_METER_AVAILABLE] += shrinkableSize;
@@ -263,15 +261,15 @@ void Platform_setSwapValues(Meter* this) {
}
void Platform_setZfsArcValues(Meter* this) {
- const FreeBSDProcessList* fpl = (const FreeBSDProcessList*) this->host->pl;
+ const FreeBSDMachine* fhost = (const FreeBSDMachine*) this->host;
- ZfsArcMeter_readStats(this, &(fpl->zfs));
+ ZfsArcMeter_readStats(this, &fhost->zfs);
}
void Platform_setZfsCompressedArcValues(Meter* this) {
- const FreeBSDProcessList* fpl = (const FreeBSDProcessList*) this->host->pl;
+ const FreeBSDMachine* fhost = (const FreeBSDMachine*) this->host;
- ZfsCompressedArcMeter_readStats(this, &(fpl->zfs));
+ ZfsCompressedArcMeter_readStats(this, &fhost->zfs);
}
char* Platform_getProcessEnv(pid_t pid) {
diff --git a/linux/HugePageMeter.c b/linux/HugePageMeter.c
index 0e429444..ec3804ee 100644
--- a/linux/HugePageMeter.c
+++ b/linux/HugePageMeter.c
@@ -16,7 +16,7 @@ in the source distribution for its full text.
#include "Object.h"
#include "ProcessList.h"
#include "RichString.h"
-#include "linux/LinuxProcessList.h"
+#include "linux/LinuxMachine.h"
static const char* HugePageMeter_active_labels[4] = { NULL, NULL, NULL, NULL };
@@ -43,8 +43,8 @@ static void HugePageMeter_updateValues(Meter* this) {
memory_t usedTotal = 0;
unsigned nextUsed = 0;
- const LinuxProcessList* lpl = (const LinuxProcessList*) this->host->pl;
- this->total = lpl->totalHugePageMem;
+ const LinuxMachine* host = (const LinuxMachine*) this->host;
+ this->total = host->totalHugePageMem;
this->values[0] = 0;
HugePageMeter_active_labels[0] = " used:";
for (unsigned i = 1; i < ARRAYSIZE(HugePageMeter_active_labels); i++) {
@@ -52,7 +52,7 @@ static void HugePageMeter_updateValues(Meter* this) {
HugePageMeter_active_labels[i] = NULL;
}
for (unsigned i = 0; i < HTOP_HUGEPAGE_COUNT; i++) {
- memory_t value = lpl->usedHugePageMem[i];
+ memory_t value = host->usedHugePageMem[i];
if (value != MEMORY_MAX) {
this->values[nextUsed] = value;
usedTotal += value;
diff --git a/linux/LibSensors.c b/linux/LibSensors.c
index 9a27fe57..ff084b64 100644
--- a/linux/LibSensors.c
+++ b/linux/LibSensors.c
@@ -16,7 +16,7 @@
#include "Macros.h"
#include "XUtils.h"
-#include "linux/LinuxProcessList.h"
+#include "linux/LinuxMachine.h"
#ifdef BUILD_STATIC
diff --git a/linux/LibSensors.h b/linux/LibSensors.h
index aa899793..2b9801bc 100644
--- a/linux/LibSensors.h
+++ b/linux/LibSensors.h
@@ -1,7 +1,7 @@
#ifndef HEADER_LibSensors
#define HEADER_LibSensors
-#include "linux/LinuxProcessList.h"
+#include "linux/LinuxMachine.h"
int LibSensors_init(void);
diff --git a/linux/LinuxMachine.c b/linux/LinuxMachine.c
new file mode 100644
index 00000000..48d0e80e
--- /dev/null
+++ b/linux/LinuxMachine.c
@@ -0,0 +1,707 @@
+/*
+htop - LinuxMachine.c
+(C) 2014 Hisham H. Muhammad
+Released under the GNU GPLv2+, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "config.h" // IWYU pragma: keep
+
+#include "linux/LinuxMachine.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <math.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include "Compat.h"
+#include "XUtils.h"
+#include "linux/LinuxMachine.h"
+#include "linux/Platform.h" // needed for GNU/hurd to get PATH_MAX // IWYU pragma: keep
+
+#ifdef HAVE_SENSORS_SENSORS_H
+#include "LibSensors.h"
+#endif
+
+#ifndef O_PATH
+#define O_PATH 010000000 // declare for ancient glibc versions
+#endif
+
+/* Similar to get_nprocs_conf(3) / _SC_NPROCESSORS_CONF
+ * https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/getsysstats.c;hb=HEAD
+ */
+static void LinuxMachine_updateCPUcount(LinuxMachine* this) {
+ unsigned int existing = 0, active = 0;
+ Machine* super = &this->super;
+
+ // Initialize the cpuData array before anything else.
+ if (!this->cpuData) {
+ this->cpuData = xCalloc(2, sizeof(CPUData));
+ this->cpuData[0].online = true; /* average is always "online" */
+ this->cpuData[1].online = true;
+ super->activeCPUs = 1;
+ super->existingCPUs = 1;
+ }
+
+ DIR* dir = opendir("/sys/devices/system/cpu");
+ if (!dir)
+ return;
+
+ unsigned int currExisting = super->existingCPUs;
+
+ const struct dirent* entry;
+ while ((entry = readdir(dir)) != NULL) {
+ if (entry->d_type != DT_DIR && entry->d_type != DT_UNKNOWN)
+ continue;
+
+ if (!String_startsWith(entry->d_name, "cpu"))
+ continue;
+
+ char* endp;
+ unsigned long int id = strtoul(entry->d_name + 3, &endp, 10);
+ if (id == ULONG_MAX || endp == entry->d_name + 3 || *endp != '\0')
+ continue;
+
+#ifdef HAVE_OPENAT
+ int cpuDirFd = openat(dirfd(dir), entry->d_name, O_DIRECTORY | O_PATH | O_NOFOLLOW);
+ if (cpuDirFd < 0)
+ continue;
+#else
+ char cpuDirFd[4096];
+ xSnprintf(cpuDirFd, sizeof(cpuDirFd), "/sys/devices/system/cpu/%s", entry->d_name);
+#endif
+
+ existing++;
+
+ /* readdir() iterates with no specific order */
+ unsigned int max = MAXIMUM(existing, id + 1);
+ if (max > currExisting) {
+ this->cpuData = xReallocArrayZero(this->cpuData, currExisting ? (currExisting + 1) : 0, max + /* aggregate */ 1, sizeof(CPUData));
+ this->cpuData[0].online = true; /* average is always "online" */
+ currExisting = max;
+ }
+
+ char buffer[8];
+ ssize_t res = xReadfileat(cpuDirFd, "online", buffer, sizeof(buffer));
+ /* If the file "online" does not exist or on failure count as active */
+ if (res < 1 || buffer[0] != '0') {
+ active++;
+ this->cpuData[id + 1].online = true;
+ } else {
+ this->cpuData[id + 1].online = false;
+ }
+
+ Compat_openatArgClose(cpuDirFd);
+ }
+
+ closedir(dir);
+
+ // return if no CPU is found
+ if (existing < 1)
+ return;
+
+#ifdef HAVE_SENSORS_SENSORS_H
+ /* When started with offline CPUs, libsensors does not monitor those,
+ * even when they become online. */
+ if (super->existingCPUs != 0 && (active > super->activeCPUs || currExisting > super->existingCPUs))
+ LibSensors_reload();
+#endif
+
+ super->activeCPUs = active;
+ assert(existing == currExisting);
+ super->existingCPUs = currExisting;
+}
+
+static void LinuxMachine_scanMemoryInfo(LinuxMachine* this) {
+ Machine* host = &this->super;
+ memory_t availableMem = 0;
+ memory_t freeMem = 0;
+ memory_t totalMem = 0;
+ memory_t buffersMem = 0;
+ memory_t cachedMem = 0;
+ memory_t sharedMem = 0;
+ memory_t swapTotalMem = 0;
+ memory_t swapCacheMem = 0;
+ memory_t swapFreeMem = 0;
+ memory_t sreclaimableMem = 0;
+ memory_t zswapCompMem = 0;
+ memory_t zswapOrigMem = 0;
+
+ FILE* file = fopen(PROCMEMINFOFILE, "r");
+ if (!file)
+ CRT_fatalError("Cannot open " PROCMEMINFOFILE);
+
+ char buffer[128];
+ while (fgets(buffer, sizeof(buffer), file)) {
+
+ #define tryRead(label, variable) \
+ if (String_startsWith(buffer, label)) { \
+ memory_t parsed_; \
+ if (sscanf(buffer + strlen(label), "%llu kB", &parsed_) == 1) { \
+ (variable) = parsed_; \
+ } \
+ break; \
+ } else (void) 0 /* Require a ";" after the macro use. */
+
+ switch (buffer[0]) {
+ case 'M':
+ tryRead("MemAvailable:", availableMem);
+ tryRead("MemFree:", freeMem);
+ tryRead("MemTotal:", totalMem);
+ break;
+ case 'B':
+ tryRead("Buffers:", buffersMem);
+ break;
+ case 'C':
+ tryRead("Cached:", cachedMem);
+ break;
+ case 'S':
+ switch (buffer[1]) {
+ case 'h':
+ tryRead("Shmem:", sharedMem);
+ break;
+ case 'w':
+ tryRead("SwapTotal:", swapTotalMem);
+ tryRead("SwapCached:", swapCacheMem);
+ tryRead("SwapFree:", swapFreeMem);
+ break;
+ case 'R':
+ tryRead("SReclaimable:", sreclaimableMem);
+ break;
+ }
+ break;
+ case 'Z':
+ tryRead("Zswap:", zswapCompMem);
+ tryRead("Zswapped:", zswapOrigMem);
+ break;
+ }
+
+ #undef tryRead
+ }
+
+ fclose(file);
+
+ /*
+ * Compute memory partition like procps(free)
+ * https://gitlab.com/procps-ng/procps/-/blob/master/proc/sysinfo.c
+ *
+ * Adjustments:
+ * - Shmem in part of Cached (see https://lore.kernel.org/patchwork/patch/648763/),
+ * do not show twice by subtracting from Cached and do not subtract twice from used.
+ */
+ host->totalMem = totalMem;
+ host->cachedMem = cachedMem + sreclaimableMem - sharedMem;
+ host->sharedMem = sharedMem;
+ const memory_t usedDiff = freeMem + cachedMem + sreclaimableMem + buffersMem;
+ host->usedMem = (totalMem >= usedDiff) ? totalMem - usedDiff : totalMem - freeMem;
+ host->buffersMem = buffersMem;
+ host->availableMem = availableMem != 0 ? MINIMUM(availableMem, totalMem) : freeMem;
+ host->totalSwap = swapTotalMem;
+ host->usedSwap = swapTotalMem - swapFreeMem - swapCacheMem;
+ host->cachedSwap = swapCacheMem;
+ this->zswap.usedZswapComp = zswapCompMem;
+ this->zswap.usedZswapOrig = zswapOrigMem;
+}
+
+static void LinuxMachine_scanHugePages(LinuxMachine* this) {
+ this->totalHugePageMem = 0;
+ for (unsigned i = 0; i < HTOP_HUGEPAGE_COUNT; i++) {
+ this->usedHugePageMem[i] = MEMORY_MAX;
+ }
+
+ DIR* dir = opendir("/sys/kernel/mm/hugepages");
+ if (!dir)
+ return;
+
+ const struct dirent* entry;
+ while ((entry = readdir(dir)) != NULL) {
+ const char* name = entry->d_name;
+
+ /* Ignore all non-directories */
+ if (entry->d_type != DT_DIR && entry->d_type != DT_UNKNOWN)
+ continue;
+
+ if (!String_startsWith(name, "hugepages-"))
+ continue;
+
+ char* endptr;
+ unsigned long int hugePageSize = strtoul(name + strlen("hugepages-"), &endptr, 10);
+ if (!endptr || *endptr != 'k')
+ continue;
+
+ char content[64];
+ char hugePagePath[128];
+ ssize_t r;
+
+ xSnprintf(hugePagePath, sizeof(hugePagePath), "/sys/kernel/mm/hugepages/%s/nr_hugepages", name);
+ r = xReadfile(hugePagePath, content, sizeof(content));
+ if (r <= 0)
+ continue;
+
+ memory_t total = strtoull(content, NULL, 10);
+ if (total == 0)
+ continue;
+
+ xSnprintf(hugePagePath, sizeof(hugePagePath), "/sys/kernel/mm/hugepages/%s/free_hugepages", name);
+ r = xReadfile(hugePagePath, content, sizeof(content));
+ if (r <= 0)
+ continue;
+
+ memory_t free = strtoull(content, NULL, 10);
+
+ int shift = ffsl(hugePageSize) - 1 - (HTOP_HUGEPAGE_BASE_SHIFT - 10);
+ assert(shift >= 0 && shift < HTOP_HUGEPAGE_COUNT);
+
+ this->totalHugePageMem += total * hugePageSize;
+ this->usedHugePageMem[shift] = (total - free) * hugePageSize;
+ }
+
+ closedir(dir);
+}
+
+static inline void LinuxMachine_scanZswapInfo(LinuxMachine* this) {
+ const Machine* host = &this->super;
+ long max_pool_percent = 0;
+ char buf[256];
+ int r;
+
+ r = xReadfile("/sys/module/zswap/parameters/max_pool_percent", buf, 256);
+ if (r <= 0) {
+ return;
+ }
+ max_pool_percent = strtol(buf, NULL, 10);
+ if (max_pool_percent < 0 || max_pool_percent > 100) {
+ return;
+ }
+
+ this->zswap.totalZswapPool = host->totalMem * max_pool_percent / 100;
+ /* the rest of the metrics are set in LinuxMachine_scanMemoryInfo() */
+}
+
+static void LinuxMachine_scanZramInfo(LinuxMachine* this) {
+ memory_t totalZram = 0;
+ memory_t usedZramComp = 0;
+ memory_t usedZramOrig = 0;
+
+ char mm_stat[34];
+ char disksize[34];
+
+ unsigned int i = 0;
+ for (;;) {
+ xSnprintf(mm_stat, sizeof(mm_stat), "/sys/block/zram%u/mm_stat", i);
+ xSnprintf(disksize, sizeof(disksize), "/sys/block/zram%u/disksize", i);
+ i++;
+ FILE* disksize_file = fopen(disksize, "r");
+ FILE* mm_stat_file = fopen(mm_stat, "r");
+ if (disksize_file == NULL || mm_stat_file == NULL) {
+ if (disksize_file) {
+ fclose(disksize_file);
+ }
+ if (mm_stat_file) {
+ fclose(mm_stat_file);
+ }
+ break;
+ }
+ memory_t size = 0;
+ memory_t orig_data_size = 0;
+ memory_t compr_data_size = 0;
+
+ if (!fscanf(disksize_file, "%llu\n", &size) ||
+ !fscanf(mm_stat_file, " %llu %llu", &orig_data_size, &compr_data_size)) {
+ fclose(disksize_file);
+ fclose(mm_stat_file);
+ break;
+ }
+
+ totalZram += size;
+ usedZramComp += compr_data_size;
+ usedZramOrig += orig_data_size;
+
+ fclose(disksize_file);
+ fclose(mm_stat_file);
+ }
+
+ this->zram.totalZram = totalZram / 1024;
+ this->zram.usedZramComp = usedZramComp / 1024;
+ this->zram.usedZramOrig = usedZramOrig / 1024;
+}
+
+static void LinuxMachine_scanZfsArcstats(LinuxMachine* this) {
+ memory_t dbufSize = 0;
+ memory_t dnodeSize = 0;
+ memory_t bonusSize = 0;
+
+ FILE* file = fopen(PROCARCSTATSFILE, "r");
+ if (file == NULL) {
+ this->zfs.enabled = 0;
+ return;
+ }
+ char buffer[128];
+ while (fgets(buffer, 128, file)) {
+ #define tryRead(label, variable) \
+ if (String_startsWith(buffer, label)) { \
+ sscanf(buffer + strlen(label), " %*2u %32llu", variable); \
+ break; \
+ } else (void) 0 /* Require a ";" after the macro use. */
+ #define tryReadFlag(label, variable, flag) \
+ if (String_startsWith(buffer, label)) { \
+ (flag) = sscanf(buffer + strlen(label), " %*2u %32llu", variable); \
+ break; \
+ } else (void) 0 /* Require a ";" after the macro use. */
+
+ switch (buffer[0]) {
+ case 'c':
+ tryRead("c_min", &this->zfs.min);
+ tryRead("c_max", &this->zfs.max);
+ tryReadFlag("compressed_size", &this->zfs.compressed, this->zfs.isCompressed);
+ break;
+ case 'u':
+ tryRead("uncompressed_size", &this->zfs.uncompressed);
+ break;
+ case 's':
+ tryRead("size", &this->zfs.size);
+ break;
+ case 'h':
+ tryRead("hdr_size", &this->zfs.header);
+ break;
+ case 'd':
+ tryRead("dbuf_size", &dbufSize);
+ tryRead("dnode_size", &dnodeSize);
+ break;
+ case 'b':
+ tryRead("bonus_size", &bonusSize);
+ break;
+ case 'a':
+ tryRead("anon_size", &this->zfs.anon);
+ break;
+ case 'm':
+ tryRead("mfu_size", &this->zfs.MFU);
+ tryRead("mru_size", &this->zfs.MRU);
+ break;
+ }
+ #undef tryRead
+ #undef tryReadFlag
+ }
+ fclose(file);
+
+ this->zfs.enabled = (this->zfs.size > 0 ? 1 : 0);
+ this->zfs.size /= 1024;
+ this->zfs.min /= 1024;
+ this->zfs.max /= 1024;
+ this->zfs.MFU /= 1024;
+ this->zfs.MRU /= 1024;
+ this->zfs.anon /= 1024;
+ this->zfs.header /= 1024;
+ this->zfs.other = (dbufSize + dnodeSize + bonusSize) / 1024;
+ if ( this->zfs.isCompressed ) {
+ this->zfs.compressed /= 1024;
+ this->zfs.uncompressed /= 1024;
+ }
+}
+
+static void LinuxMachine_scanCPUTime(LinuxMachine* this) {
+ const Machine* super = &this->super;
+
+ LinuxMachine_updateCPUcount(this);
+
+ FILE* file = fopen(PROCSTATFILE, "r");
+ if (!file)
+ CRT_fatalError("Cannot open " PROCSTATFILE);
+
+ unsigned int lastAdjCpuId = 0;
+
+ for (unsigned int i = 0; i <= super->existingCPUs; i++) {
+ char buffer[PROC_LINE_LENGTH + 1];
+ unsigned long long int usertime, nicetime, systemtime, idletime;
+ unsigned long long int ioWait = 0, irq = 0, softIrq = 0, steal = 0, guest = 0, guestnice = 0;
+
+ const char* ok = fgets(buffer, sizeof(buffer), file);
+ if (!ok)
+ break;
+
+ // cpu fields are sorted first
+ if (!String_startsWith(buffer, "cpu"))
+ break;
+
+ // Depending on your kernel version,
+ // 5, 7, 8 or 9 of these fields will be set.
+ // The rest will remain at zero.
+ unsigned int adjCpuId;
+ if (i == 0) {
+ (void) sscanf(buffer, "cpu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu", &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice);
+ adjCpuId = 0;
+ } else {
+ unsigned int cpuid;
+ (void) sscanf(buffer, "cpu%4u %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu", &cpuid, &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice);
+ adjCpuId = cpuid + 1;
+ }
+
+ if (adjCpuId > super->existingCPUs)
+ break;
+
+ for (unsigned int j = lastAdjCpuId + 1; j < adjCpuId; j++) {
+ // Skipped an ID, but /proc/stat is ordered => got offline CPU
+ memset(&(this->cpuData[j]), '\0', sizeof(CPUData));
+ }
+ lastAdjCpuId = adjCpuId;
+
+ // Guest time is already accounted in usertime
+ usertime -= guest;
+ nicetime -= guestnice;
+ // Fields existing on kernels >= 2.6
+ // (and RHEL's patched kernel 2.4...)
+ unsigned long long int idlealltime = idletime + ioWait;
+ unsigned long long int systemalltime = systemtime + irq + softIrq;
+ unsigned long long int virtalltime = guest + guestnice;
+ unsigned long long int totaltime = usertime + nicetime + systemalltime + idlealltime + steal + virtalltime;
+ CPUData* cpuData = &(this->cpuData[adjCpuId]);
+ // Since we do a subtraction (usertime - guest) and cputime64_to_clock_t()
+ // used in /proc/stat rounds down numbers, it can lead to a case where the
+ // integer overflow.
+ cpuData->userPeriod = saturatingSub(usertime, cpuData->userTime);
+ cpuData->nicePeriod = saturatingSub(nicetime, cpuData->niceTime);
+ cpuData->systemPeriod = saturatingSub(systemtime, cpuData->systemTime);
+ cpuData->systemAllPeriod = saturatingSub(systemalltime, cpuData->systemAllTime);
+ cpuData->idleAllPeriod = saturatingSub(idlealltime, cpuData->idleAllTime);
+ cpuData->idlePeriod = saturatingSub(idletime, cpuData->idleTime);
+ cpuData->ioWaitPeriod = saturatingSub(ioWait, cpuData->ioWaitTime);
+ cpuData->irqPeriod = saturatingSub(irq, cpuData->irqTime);
+ cpuData->softIrqPeriod = saturatingSub(softIrq, cpuData->softIrqTime);
+ cpuData->stealPeriod = saturatingSub(steal, cpuData->stealTime);
+ cpuData->guestPeriod = saturatingSub(virtalltime, cpuData->guestTime);
+ cpuData->totalPeriod = saturatingSub(totaltime, cpuData->totalTime);
+ cpuData->userTime = usertime;
+ cpuData->niceTime = nicetime;
+ cpuData->systemTime = systemtime;
+ cpuData->systemAllTime = systemalltime;
+ cpuData->idleAllTime = idlealltime;
+ cpuData->idleTime = idletime;
+ cpuData->ioWaitTime = ioWait;
+ cpuData->irqTime = irq;
+ cpuData->softIrqTime = softIrq;
+ cpuData->stealTime = steal;
+ cpuData->guestTime = virtalltime;
+ cpuData->totalTime = totaltime;
+ }
+
+ this->period = (double)this->cpuData[0].totalPeriod / super->activeCPUs;
+
+ char buffer[PROC_LINE_LENGTH + 1];
+ while (fgets(buffer, sizeof(buffer), file)) {
+ if (String_startsWith(buffer, "procs_running")) {
+ super->pl->runningTasks = strtoul(buffer + strlen("procs_running"), NULL, 10);
+ break;
+ }
+ }
+
+ fclose(file);
+}
+
+static int scanCPUFrequencyFromSysCPUFreq(LinuxMachine* this) {
+ const Machine* super = &this->super;
+ int numCPUsWithFrequency = 0;
+ unsigned long totalFrequency = 0;
+
+ /*
+ * On some AMD and Intel CPUs read()ing scaling_cur_freq is quite slow (> 1ms). This delay
+ * accumulates for every core. For details see issue#471.
+ * If the read on CPU 0 takes longer than 500us bail out and fall back to reading the
+ * frequencies from /proc/cpuinfo.
+ * Once the condition has been met, bail out early for the next couple of scans.
+ */
+ static int timeout = 0;
+
+ if (timeout > 0) {
+ timeout--;
+ return -1;
+ }
+
+ for (unsigned int i = 0; i < super->existingCPUs; ++i) {
+ if (!Machine_isCPUonline(super, i))
+ continue;
+
+ char pathBuffer[64];
+ xSnprintf(pathBuffer, sizeof(pathBuffer), "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq", i);
+
+ struct timespec start;
+ if (i == 0)
+ clock_gettime(CLOCK_MONOTONIC, &start);
+
+ FILE* file = fopen(pathBuffer, "r");
+ if (!file)
+ return -errno;
+
+ unsigned long frequency;
+ if (fscanf(file, "%lu", &frequency) == 1) {
+ /* convert kHz to MHz */
+ frequency = frequency / 1000;
+ this->cpuData[i + 1].frequency = frequency;
+ numCPUsWithFrequency++;
+ totalFrequency += frequency;
+ }
+
+ fclose(file);
+
+ if (i == 0) {
+ struct timespec end;
+ clock_gettime(CLOCK_MONOTONIC, &end);
+ const time_t timeTakenUs = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_nsec - start.tv_nsec) / 1000;
+ if (timeTakenUs > 500) {
+ timeout = 30;
+ return -1;
+ }
+ }
+ }
+
+ if (numCPUsWithFrequency > 0)
+ this->cpuData[0].frequency = (double)totalFrequency / numCPUsWithFrequency;
+
+ return 0;
+}
+
+static void scanCPUFrequencyFromCPUinfo(LinuxMachine* this) {
+ const Machine* super = &this->super;
+
+ FILE* file = fopen(PROCCPUINFOFILE, "r");
+ if (file == NULL)
+ return;
+
+ int numCPUsWithFrequency = 0;
+ double totalFrequency = 0;
+ int cpuid = -1;
+
+ while (!feof(file)) {
+ double frequency;
+ char buffer[PROC_LINE_LENGTH];
+
+ if (fgets(buffer, PROC_LINE_LENGTH, file) == NULL)
+ break;
+
+ if (sscanf(buffer, "processor : %d", &cpuid) == 1) {
+ continue;
+ } else if (
+ (sscanf(buffer, "cpu MHz : %lf", &frequency) == 1) ||
+ (sscanf(buffer, "clock : %lfMHz", &frequency) == 1)
+ ) {
+ if (cpuid < 0 || (unsigned int)cpuid > (super->existingCPUs - 1)) {
+ continue;
+ }
+
+ CPUData* cpuData = &(this->cpuData[cpuid + 1]);
+ /* do not override sysfs data */
+ if (isnan(cpuData->frequency)) {
+ cpuData->frequency = frequency;
+ }
+ numCPUsWithFrequency++;
+ totalFrequency += frequency;
+ } else if (buffer[0] == '\n') {
+ cpuid = -1;
+ }
+ }
+ fclose(file);
+
+ if (numCPUsWithFrequency > 0) {
+ this->cpuData[0].frequency = totalFrequency / numCPUsWithFrequency;
+ }
+}
+
+static void LinuxMachine_scanCPUFrequency(LinuxMachine* this) {
+ const Machine* super = &this->super;
+
+ for (unsigned int i = 0; i <= super->existingCPUs; i++)
+ this->cpuData[i].frequency = NAN;
+
+ if (scanCPUFrequencyFromSysCPUFreq(this) == 0)
+ return;
+
+ scanCPUFrequencyFromCPUinfo(this);
+}
+
+void Machine_scan(Machine* super) {
+ LinuxMachine* this = (LinuxMachine*) super;
+
+ LinuxMachine_scanMemoryInfo(this);
+ LinuxMachine_scanHugePages(this);
+ LinuxMachine_scanZfsArcstats(this);
+ LinuxMachine_scanZramInfo(this);
+ LinuxMachine_scanZswapInfo(this);
+ LinuxMachine_scanCPUTime(this);
+
+ const Settings* settings = super->settings;
+ if (settings->showCPUFrequency)
+ LinuxMachine_scanCPUFrequency(this);
+
+ #ifdef HAVE_SENSORS_SENSORS_H
+ if (settings->showCPUTemperature)
+ LibSensors_getCPUTemperatures(this->cpuData, super->existingCPUs, super->activeCPUs);
+ #endif
+}
+
+Machine* Machine_new(UsersTable* usersTable, uid_t userId) {
+ LinuxMachine* this = xCalloc(1, sizeof(LinuxMachine));
+ Machine* super = &this->super;
+
+ Machine_init(super, usersTable, userId);
+
+ // Initialize page size
+ if ((this->pageSize = sysconf(_SC_PAGESIZE)) == -1)
+ CRT_fatalError("Cannot get pagesize by sysconf(_SC_PAGESIZE)");
+ this->pageSizeKB = this->pageSize / ONE_K;
+
+ // Initialize clock ticks
+ if ((this->jiffies = sysconf(_SC_CLK_TCK)) == -1)
+ CRT_fatalError("Cannot get clock ticks by sysconf(_SC_CLK_TCK)");
+
+ // Read btime (the kernel boot time, as number of seconds since the epoch)
+ FILE* statfile = fopen(PROCSTATFILE, "r");
+ if (statfile == NULL)
+ CRT_fatalError("Cannot open " PROCSTATFILE);
+
+ this->boottime = -1;
+
+ while (true) {
+ char buffer[PROC_LINE_LENGTH + 1];
+ if (fgets(buffer, sizeof(buffer), statfile) == NULL)
+ break;
+ if (String_startsWith(buffer, "btime ") == false)
+ continue;
+ if (sscanf(buffer, "btime %lld\n", &this->boottime) == 1)
+ break;
+ CRT_fatalError("Failed to parse btime from " PROCSTATFILE);
+ }
+ fclose(statfile);
+
+ if (this->boottime == -1)
+ CRT_fatalError("No btime in " PROCSTATFILE);
+
+ // Initialize CPU count
+ LinuxMachine_updateCPUcount(this);
+
+ return super;
+}
+
+void Machine_delete(Machine* super) {
+ LinuxMachine* this = (LinuxMachine*) super;
+ Machine_done(super);
+ free(this->cpuData);
+ free(this);
+}
+
+bool Machine_isCPUonline(const Machine* super, unsigned int id) {
+ const LinuxMachine* this = (const LinuxMachine*) super;
+
+ assert(id < super->existingCPUs);
+ return this->cpuData[id + 1].online;
+}
diff --git a/linux/LinuxMachine.h b/linux/LinuxMachine.h
new file mode 100644
index 00000000..7dba905f
--- /dev/null
+++ b/linux/LinuxMachine.h
@@ -0,0 +1,110 @@
+#ifndef HEADER_LinuxMachine
+#define HEADER_LinuxMachine
+/*
+htop - LinuxMachine.h
+(C) 2014 Hisham H. Muhammad
+Released under the GNU GPLv2+, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "config.h"
+
+#include <stdbool.h>
+#include <sys/types.h>
+
+#include "Machine.h"
+#include "UsersTable.h"
+#include "linux/ZramStats.h"
+#include "linux/ZswapStats.h"
+#include "zfs/ZfsArcStats.h"
+
+#define HTOP_HUGEPAGE_BASE_SHIFT 16
+#define HTOP_HUGEPAGE_COUNT 24
+
+typedef struct CPUData_ {
+ unsigned long long int totalTime;
+ unsigned long long int userTime;
+ unsigned long long int systemTime;
+ unsigned long long int systemAllTime;
+ unsigned long long int idleAllTime;
+ unsigned long long int idleTime;
+ unsigned long long int niceTime;
+ unsigned long long int ioWaitTime;
+ unsigned long long int irqTime;
+ unsigned long long int softIrqTime;
+ unsigned long long int stealTime;
+ unsigned long long int guestTime;
+
+ unsigned long long int totalPeriod;
+ unsigned long long int userPeriod;
+ unsigned long long int systemPeriod;
+ unsigned long long int systemAllPeriod;
+ unsigned long long int idleAllPeriod;
+ unsigned long long int idlePeriod;
+ unsigned long long int nicePeriod;
+ unsigned long long int ioWaitPeriod;
+ unsigned long long int irqPeriod;
+ unsigned long long int softIrqPeriod;
+ unsigned long long int stealPeriod;
+ unsigned long long int guestPeriod;
+
+ double frequency;
+
+ #ifdef HAVE_SENSORS_SENSORS_H
+ double temperature;
+ #endif
+
+ bool online;
+} CPUData;
+
+typedef struct LinuxMachine_ {
+ Machine super;
+
+ long jiffies;
+ long long boottime;
+ int pageSize;
+ int pageSizeKB;
+
+ double period;
+
+ CPUData* cpuData;
+
+ memory_t totalHugePageMem;
+ memory_t usedHugePageMem[HTOP_HUGEPAGE_COUNT];
+
+ memory_t availableMem;
+
+ ZfsArcStats zfs;
+ ZramStats zram;
+ ZswapStats zswap;
+} LinuxMachine;
+
+#ifndef PROCDIR
+#define PROCDIR "/proc"
+#endif
+
+#ifndef PROCCPUINFOFILE
+#define PROCCPUINFOFILE PROCDIR "/cpuinfo"
+#endif
+
+#ifndef PROCSTATFILE
+#define PROCSTATFILE PROCDIR "/stat"
+#endif
+
+#ifndef PROCMEMINFOFILE
+#define PROCMEMINFOFILE PROCDIR "/meminfo"
+#endif
+
+#ifndef PROCARCSTATSFILE
+#define PROCARCSTATSFILE PROCDIR "/spl/kstat/zfs/arcstats"
+#endif
+
+#ifndef PROCTTYDRIVERSFILE
+#define PROCTTYDRIVERSFILE PROCDIR "/tty/drivers"
+#endif
+
+#ifndef PROC_LINE_LENGTH
+#define PROC_LINE_LENGTH 4096
+#endif
+
+#endif
diff --git a/linux/LinuxProcess.c b/linux/LinuxProcess.c
index a3a4c821..b815c5b5 100644
--- a/linux/LinuxProcess.c
+++ b/linux/LinuxProcess.c
@@ -22,12 +22,9 @@ in the source distribution for its full text.
#include "Scheduling.h"
#include "XUtils.h"
#include "linux/IOPriority.h"
+#include "linux/LinuxMachine.h"
-/* semi-global */
-int pageSize;
-int pageSizeKB;
-
const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = {
[0] = { .name = "", .title = NULL, .description = NULL, .flags = 0, },
[PID] = { .name = "PID", .title = "PID", .description = "Process/thread ID", .flags = 0, .pidColumn = true, },
@@ -197,6 +194,7 @@ bool LinuxProcess_changeAutogroupPriorityBy(Process* this, Arg delta) {
static void LinuxProcess_writeField(const Process* this, RichString* str, ProcessField field) {
const LinuxProcess* lp = (const LinuxProcess*) this;
+ const LinuxMachine* lhost = (const LinuxMachine*) this->host;
bool coloring = this->host->settings->highlightMegabytes;
char buffer[256]; buffer[255] = '\0';
int attr = CRT_colors[DEFAULT_COLOR];
@@ -204,18 +202,18 @@ static void LinuxProcess_writeField(const Process* this, RichString* str, Proces
switch (field) {
case CMINFLT: Process_printCount(str, lp->cminflt, coloring); return;
case CMAJFLT: Process_printCount(str, lp->cmajflt, coloring); return;
- case M_DRS: Process_printBytes(str, lp->m_drs * pageSize, coloring); return;
+ case M_DRS: Process_printBytes(str, lp->m_drs * lhost->pageSize, coloring); return;
case M_LRS:
if (lp->m_lrs) {
- Process_printBytes(str, lp->m_lrs * pageSize, coloring);
+ Process_printBytes(str, lp->m_lrs * lhost->pageSize, coloring);
return;
}
attr = CRT_colors[PROCESS_SHADOW];
xSnprintf(buffer, n, " N/A ");
break;
- case M_TRS: Process_printBytes(str, lp->m_trs * pageSize, coloring); return;
- case M_SHARE: Process_printBytes(str, lp->m_share * pageSize, coloring); return;
+ case M_TRS: Process_printBytes(str, lp->m_trs * lhost->pageSize, coloring); return;
+ case M_SHARE: Process_printBytes(str, lp->m_share * lhost->pageSize, coloring); return;
case M_PSS: Process_printKBytes(str, lp->m_pss, coloring); return;
case M_SWAP: Process_printKBytes(str, lp->m_swap, coloring); return;
case M_PSSWP: Process_printKBytes(str, lp->m_psswp, coloring); return;
diff --git a/linux/LinuxProcessList.c b/linux/LinuxProcessList.c
index 911fc3e1..e0a33e28 100644
--- a/linux/LinuxProcessList.c
+++ b/linux/LinuxProcessList.c
@@ -49,6 +49,7 @@ in the source distribution for its full text.
#include "Settings.h"
#include "XUtils.h"
#include "linux/CGroupUtils.h"
+#include "linux/LinuxMachine.h"
#include "linux/LinuxProcess.h"
#include "linux/Platform.h" // needed for GNU/hurd to get PATH_MAX // IWYU pragma: keep
@@ -58,23 +59,11 @@ in the source distribution for its full text.
#include <sys/sysmacros.h>
#endif
-#ifdef HAVE_SENSORS_SENSORS_H
-#include "LibSensors.h"
-#endif
-
-#ifndef O_PATH
-#define O_PATH 010000000 // declare for ancient glibc versions
-#endif
-
/* Not exposed yet. Defined at include/linux/sched.h */
#ifndef PF_KTHREAD
#define PF_KTHREAD 0x00200000
#endif
-static long long btime = -1;
-
-static long jiffy;
-
static FILE* fopenat(openat_arg_t openatArg, const char* pathname, const char* mode) {
assert(String_eq(mode, "r")); /* only currently supported mode */
@@ -211,144 +200,22 @@ static void LinuxProcessList_initNetlinkSocket(LinuxProcessList* this) {
#endif
-static void LinuxProcessList_updateCPUcount(ProcessList* super) {
- /* Similar to get_nprocs_conf(3) / _SC_NPROCESSORS_CONF
- * https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/getsysstats.c;hb=HEAD
- */
-
- Machine* host = super->host;
- LinuxProcessList* this = (LinuxProcessList*) super;
- unsigned int existing = 0, active = 0;
-
- // Initialize the cpuData array before anything else.
- if (!this->cpuData) {
- this->cpuData = xCalloc(2, sizeof(CPUData));
- this->cpuData[0].online = true; /* average is always "online" */
- this->cpuData[1].online = true;
- host->activeCPUs = 1;
- host->existingCPUs = 1;
- }
-
- DIR* dir = opendir("/sys/devices/system/cpu");
- if (!dir)
- return;
-
- unsigned int currExisting = host->existingCPUs;
-
- const struct dirent* entry;
- while ((entry = readdir(dir)) != NULL) {
- if (entry->d_type != DT_DIR && entry->d_type != DT_UNKNOWN)
- continue;
-
- if (!String_startsWith(entry->d_name, "cpu"))
- continue;
-
- char* endp;
- unsigned long int id = strtoul(entry->d_name + 3, &endp, 10);
- if (id == ULONG_MAX || endp == entry->d_name + 3 || *endp != '\0')
- continue;
-
-#ifdef HAVE_OPENAT
- int cpuDirFd = openat(dirfd(dir), entry->d_name, O_DIRECTORY | O_PATH | O_NOFOLLOW);
- if (cpuDirFd < 0)
- continue;
-#else
- char cpuDirFd[4096];
- xSnprintf(cpuDirFd, sizeof(cpuDirFd), "/sys/devices/system/cpu/%s", entry->d_name);
-#endif
-
- existing++;
-
- /* readdir() iterates with no specific order */
- unsigned int max = MAXIMUM(existing, id + 1);
- if (max > currExisting) {
- this->cpuData = xReallocArrayZero(this->cpuData, currExisting ? (currExisting + 1) : 0, max + /* aggregate */ 1, sizeof(CPUData));
- this->cpuData[0].online = true; /* average is always "online" */
- currExisting = max;
- }
-
- char buffer[8];
- ssize_t res = xReadfileat(cpuDirFd, "online", buffer, sizeof(buffer));
- /* If the file "online" does not exist or on failure count as active */
- if (res < 1 || buffer[0] != '0') {
- active++;
- this->cpuData[id + 1].online = true;
- } else {
- this->cpuData[id + 1].online = false;
- }
-
- Compat_openatArgClose(cpuDirFd);
- }
-
- closedir(dir);
-
- // return if no CPU is found
- if (existing < 1)
- return;
-
-#ifdef HAVE_SENSORS_SENSORS_H
- /* When started with offline CPUs, libsensors does not monitor those,
- * even when they become online. */
- if (host->existingCPUs != 0 && (active > host->activeCPUs || currExisting > host->existingCPUs))
- LibSensors_reload();
-#endif
-
- host->activeCPUs = active;
- assert(existing == currExisting);
- host->existingCPUs = currExisting;
-}
-
ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList) {
LinuxProcessList* this = xCalloc(1, sizeof(LinuxProcessList));
- ProcessList* pl = &(this->super);
+ ProcessList* super = &this->super;
- ProcessList_init(pl, Class(LinuxProcess), host, pidMatchList);
+ ProcessList_init(super, Class(LinuxProcess), host, pidMatchList);
LinuxProcessList_initTtyDrivers(this);
- // Initialize page size
- pageSize = sysconf(_SC_PAGESIZE);
- if (pageSize == -1)
- CRT_fatalError("Cannot get pagesize by sysconf(_SC_PAGESIZE)");
- pageSizeKB = pageSize / ONE_K;
-
- // Initialize clock ticks
- jiffy = sysconf(_SC_CLK_TCK);
- if (jiffy == -1)
- CRT_fatalError("Cannot get clock ticks by sysconf(_SC_CLK_TCK)");
-
// Test /proc/PID/smaps_rollup availability (faster to parse, Linux 4.14+)
this->haveSmapsRollup = (access(PROCDIR "/self/smaps_rollup", R_OK) == 0);
- // Read btime (the kernel boot time, as number of seconds since the epoch)
- FILE* statfile = fopen(PROCSTATFILE, "r");
- if (statfile == NULL)
- CRT_fatalError("Cannot open " PROCSTATFILE);
- while (true) {
- char buffer[PROC_LINE_LENGTH + 1];
- if (fgets(buffer, sizeof(buffer), statfile) == NULL)
- break;
- if (String_startsWith(buffer, "btime ") == false)
- continue;
- if (sscanf(buffer, "btime %lld\n", &btime) == 1)
- break;
- CRT_fatalError("Failed to parse btime from " PROCSTATFILE);
- }
-
- fclose(statfile);
-
- if (btime == -1)
- CRT_fatalError("No btime in " PROCSTATFILE);
-
- // Initialize CPU count
- LinuxProcessList_updateCPUcount(pl);
-
- return pl;
+ return super;
}
void ProcessList_delete(ProcessList* pl) {
LinuxProcessList* this = (LinuxProcessList*) pl;
ProcessList_done(pl);
- free(this->cpuData);
if (this->ttyDrivers) {
for (int i = 0; this->ttyDrivers[i].path; i++) {
free(this->ttyDrivers[i].path);
@@ -364,8 +231,8 @@ void ProcessList_delete(ProcessList* pl) {
free(this);
}
-static inline unsigned long long LinuxProcessList_adjustTime(unsigned long long t) {
- return t * 100 / jiffy;
+static inline unsigned long long LinuxProcessList_adjustTime(const LinuxMachine* lhost, unsigned long long t) {
+ return t * 100 / lhost->jiffies;
}
/* Taken from: https://github.com/torvalds/linux/blob/64570fbc14f8d7cb3fe3995f20e26bc25ce4b2cc/fs/proc/array.c#L120 */
@@ -384,7 +251,7 @@ static inline ProcessState LinuxProcessList_getProcessState(char state) {
}
}
-static bool LinuxProcessList_readStatFile(LinuxProcess* lp, openat_arg_t procFd, bool scanMainThread, char* command, size_t commLen) {
+static bool LinuxProcessList_readStatFile(LinuxProcess* lp, openat_arg_t procFd, const LinuxMachine* lhost, bool scanMainThread, char* command, size_t commLen) {
Process* process = &lp->super;
char buf[MAX_READ + 1];
@@ -457,19 +324,19 @@ static bool LinuxProcessList_readStatFile(LinuxProcess* lp, openat_arg_t procFd,
location += 1;
/* (14) utime - %lu */
- lp->utime = LinuxProcessList_adjustTime(strtoull(location, &location, 10));
+ lp->utime = LinuxProcessList_adjustTime(lhost, strtoull(location, &location, 10));
location += 1;
/* (15) stime - %lu */
- lp->stime = LinuxProcessList_adjustTime(strtoull(location, &location, 10));
+ lp->stime = LinuxProcessList_adjustTime(lhost, strtoull(location, &location, 10));
location += 1;
/* (16) cutime - %ld */
- lp->cutime = LinuxProcessList_adjustTime(strtoull(location, &location, 10));
+ lp->cutime = LinuxProcessList_adjustTime(lhost, strtoull(location, &location, 10));
location += 1;
/* (17) cstime - %ld */
- lp->cstime = LinuxProcessList_adjustTime(strtoull(location, &location, 10));
+ lp->cstime = LinuxProcessList_adjustTime(lhost, strtoull(location, &location, 10));
location += 1;
/* (18) priority - %ld */
@@ -489,7 +356,7 @@ static bool LinuxProcessList_readStatFile(LinuxProcess* lp, openat_arg_t procFd,
/* (22) starttime - %llu */
if (process->starttime_ctime == 0) {
- process->starttime_ctime = btime + LinuxProcessList_adjustTime(strtoll(location, &location, 10)) / 100;
+ process->starttime_ctime = lhost->boottime + LinuxProcessList_adjustTime(lhost, strtoll(location, &location, 10)) / 100;
} else {
location = strchr(location, ' ');
}
@@ -613,8 +480,9 @@ static bool LinuxProcessList_updateUser(const Machine* host, Process* process, o
return true;
}
-static void LinuxProcessList_readIoFile(LinuxProcess* lp, openat_arg_t procFd, bool scanMainThread, unsigned long long realtimeMs) {
+static void LinuxProcessList_readIoFile(LinuxProcess* lp, openat_arg_t procFd, bool scanMainThread) {
Process* process = &lp->super;
+ const Machine* host = process->host;
char path[20] = "io";
char buffer[1024];
if (scanMainThread) {
@@ -631,13 +499,13 @@ static void LinuxProcessList_readIoFile(LinuxProcess* lp, openat_arg_t procFd, b
lp->io_read_bytes = ULLONG_MAX;
lp->io_write_bytes = ULLONG_MAX;
lp->io_cancelled_write_bytes = ULLONG_MAX;
- lp->io_last_scan_time_ms = realtimeMs;
+ lp->io_last_scan_time_ms = host->realtimeMs;
return;
}
unsigned long long last_read = lp->io_read_bytes;
unsigned long long last_write = lp->io_write_bytes;
- unsigned long long time_delta = realtimeMs > lp->io_last_scan_time_ms ? realtimeMs - lp->io_last_scan_time_ms : 0;
+ unsigned long long time_delta = host->realtimeMs > lp->io_last_scan_time_ms ? host->realtimeMs - lp->io_last_scan_time_ms : 0;
char* buf = buffer;
const char* line;
@@ -673,7 +541,7 @@ static void LinuxProcessList_readIoFile(LinuxProcess* lp, openat_arg_t procFd, b
}
}
- lp->io_last_scan_time_ms = realtimeMs;
+ lp->io_last_scan_time_ms = host->realtimeMs;
}
typedef struct LibraryData_ {
@@ -696,7 +564,7 @@ static void LinuxProcessList_calcLibSize_helper(ATTR_UNUSED ht_key_t key, void*
*d += v->size;
}
-static void LinuxProcessList_readMaps(LinuxProcess* process, openat_arg_t procFd, bool calcSize, bool checkDeletedLib) {
+static void LinuxProcessList_readMaps(LinuxProcess* process, openat_arg_t procFd, const LinuxMachine* host, bool calcSize, bool checkDeletedLib) {
Process* proc = (Process*)process;
proc->usesDeletedLib = false;
@@ -801,11 +669,11 @@ static void LinuxProcessList_readMaps(LinuxProcess* process, openat_arg_t procFd
Hashtable_delete(ht);
- process->m_lrs = total_size / pageSize;
+ process->m_lrs = total_size / host->pageSize;
}
}
-static bool LinuxProcessList_readStatmFile(LinuxProcess* process, openat_arg_t procFd) {
+static bool LinuxProcessList_readStatmFile(LinuxProcess* process, openat_arg_t procFd, const LinuxMachine* host) {
FILE* statmfile = fopenat(procFd, "statm", "r");
if (!statmfile)
return false;
@@ -823,8 +691,8 @@ static bool LinuxProcessList_readStatmFile(LinuxProcess* process, openat_arg_t p
fclose(statmfile);
if (r == 7) {
- process->super.m_virt *= pageSizeKB;
- process->super.m_resident *= pageSizeKB;
+ process->super.m_virt *= host->pageSizeKB;
+ process->super.m_resident *= host->pageSizeKB;
}
return r == 7;
@@ -1422,14 +1290,14 @@ static char* LinuxProcessList_updateTtyDevice(TtyDriver* ttyDrivers, unsigned lo
return out;
}
-static bool isOlderThan(const Machine* host, const Process* proc, unsigned int seconds) {
- assert(host->realtimeMs > 0);
+static bool isOlderThan(const Process* proc, unsigned int seconds) {
+ assert(proc->host->realtimeMs > 0);
/* Starttime might not yet be parsed */
if (proc->starttime_ctime <= 0)
return false;
- uint64_t realtime = host->realtimeMs / 1000;
+ uint64_t realtime = proc->host->realtimeMs / 1000;
if (realtime < (uint64_t)proc->starttime_ctime)
return false;
@@ -1437,9 +1305,9 @@ static bool isOlderThan(const Machine* host, const Process* proc, unsigned int s
return realtime - proc->starttime_ctime > seconds;
}
-static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_t parentFd, const char* dirname, const Process* parent, double period) {
+static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_t parentFd, const LinuxMachine* lhost, const char* dirname, const Process* parent) {
ProcessList* pl = (ProcessList*) this;
- const Machine* host = pl->host;
+ const Machine* host = &lhost->super;
const Settings* settings = host->settings;
const ScreenSettings* ss = settings->ss;
const struct dirent* entry;
@@ -1459,7 +1327,6 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_
return false;
}
- const unsigned int activeCPUs = host->activeCPUs;
const bool hideKernelThreads = settings->hideKernelThreads;
const bool hideUserlandThreads = settings->hideUserlandThreads;
const bool hideRunningInContainer = settings->hideRunningInContainer;
@@ -1512,7 +1379,7 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_
proc->tgid = parent ? parent->pid : pid;
proc->isUserlandThread = proc->pid != proc->tgid;
- LinuxProcessList_recurseProcTree(this, procFd, "task", proc, period);
+ LinuxProcessList_recurseProcTree(this, procFd, lhost, "task", proc);
/*
* These conditions will not trigger on first occurrence, cause we need to
@@ -1545,16 +1412,16 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_
bool scanMainThread = !hideUserlandThreads && !Process_isKernelThread(proc) && !parent;
if (ss->flags & PROCESS_FLAG_IO)
- LinuxProcessList_readIoFile(lp, procFd, scanMainThread, host->realtimeMs);
+ LinuxProcessList_readIoFile(lp, procFd, scanMainThread);
- if (!LinuxProcessList_readStatmFile(lp, procFd))
+ if (!LinuxProcessList_readStatmFile(lp, procFd, lhost))
goto errorReadingProcess;
{
bool prev = proc->usesDeletedLib;
if (!proc->isKernelThread && !proc->isUserlandThread &&
- ((ss->flags & PROCESS_FLAG_LINUX_LRS_FIX) || (settings->highlightDeletedExe && !proc->procExeDeleted && isOlderThan(host, proc, 10)))) {
+ ((ss->flags & PROCESS_FLAG_LINUX_LRS_FIX) || (settings->highlightDeletedExe && !proc->procExeDeleted && isOlderThan(proc, 10)))) {
// Check if we really should recalculate the M_LRS value for this process
uint64_t passedTimeInMs = host->realtimeMs - lp->last_mlrs_calctime;
@@ -1563,7 +1430,7 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_
if (passedTimeInMs > recheck) {
lp->last_mlrs_calctime = host->realtimeMs;
- LinuxProcessList_readMaps(lp, procFd, ss->flags & PROCESS_FLAG_LINUX_LRS_FIX, settings->highlightDeletedExe);
+ LinuxProcessList_readMaps(lp, procFd, lhost, ss->flags & PROCESS_FLAG_LINUX_LRS_FIX, settings->highlightDeletedExe);
}
} else {
/* Copy from process structure in threads and reset if setting got disabled */
@@ -1593,7 +1460,7 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_
char statCommand[MAX_NAME + 1];
unsigned long long int lasttimes = (lp->utime + lp->stime);
unsigned long int tty_nr = proc->tty_nr;
- if (!LinuxProcessList_readStatFile(lp, procFd, scanMainThread, statCommand, sizeof(statCommand)))
+ if (!LinuxProcessList_readStatFile(lp, procFd, lhost, scanMainThread, statCommand, sizeof(statCommand)))
goto errorReadingProcess;
if (lp->flags & PF_KTHREAD) {
@@ -1610,8 +1477,8 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_
}
/* period might be 0 after system sleep */
- float percent_cpu = (period < 1E-6) ? 0.0F : ((lp->utime + lp->stime - lasttimes) / period * 100.0);
- proc->percent_cpu = CLAMP(percent_cpu, 0.0F, activeCPUs * 100.0F);
+ float percent_cpu = (lhost->period < 1E-6) ? 0.0F : ((lp->utime + lp->stime - lasttimes) / lhost->period * 100.0);
+ proc->percent_cpu = CLAMP(percent_cpu, 0.0F, host->activeCPUs * 100.0F);
proc->percent_mem = proc->m_resident / (double)(host->totalMem) * 100.0;
Process_updateCPUFieldWidths(proc->percent_cpu);
@@ -1706,7 +1573,7 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_
proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc)));
pl->totalTasks++;
- /* runningTasks is set in LinuxProcessList_scanCPUTime() from /proc/stat */
+ /* runningTasks is set in Machine_scanCPUTime() from /proc/stat */
continue;
// Exception handler.
@@ -1734,546 +1601,11 @@ errorReadingProcess:
return true;
}
-static inline void LinuxProcessList_scanMemoryInfo(ProcessList* this) {
- Machine* host = this->host;
- LinuxProcessList *lpl = (LinuxProcessList *)this;
- memory_t availableMem = 0;
- memory_t freeMem = 0;
- memory_t totalMem = 0;
- memory_t buffersMem = 0;
- memory_t cachedMem = 0;
- memory_t sharedMem = 0;
- memory_t swapTotalMem = 0;
- memory_t swapCacheMem = 0;
- memory_t swapFreeMem = 0;
- memory_t sreclaimableMem = 0;
- memory_t zswapCompMem = 0;
- memory_t zswapOrigMem = 0;
-
- FILE* file = fopen(PROCMEMINFOFILE, "r");
- if (!file)
- CRT_fatalError("Cannot open " PROCMEMINFOFILE);
-
- char buffer[128];
- while (fgets(buffer, sizeof(buffer), file)) {
-
- #define tryRead(label, variable) \
- if (String_startsWith(buffer, label)) { \
- memory_t parsed_; \
- if (sscanf(buffer + strlen(label), "%llu kB", &parsed_) == 1) { \
- (variable) = parsed_; \
- } \
- break; \
- } else (void) 0 /* Require a ";" after the macro use. */
-
- switch (buffer[0]) {
- case 'M':
- tryRead("MemAvailable:", availableMem);
- tryRead("MemFree:", freeMem);
- tryRead("MemTotal:", totalMem);
- break;
- case 'B':
- tryRead("Buffers:", buffersMem);
- break;
- case 'C':
- tryRead("Cached:", cachedMem);
- break;
- case 'S':
- switch (buffer[1]) {
- case 'h':
- tryRead("Shmem:", sharedMem);
- break;
- case 'w':
- tryRead("SwapTotal:", swapTotalMem);
- tryRead("SwapCached:", swapCacheMem);
- tryRead("SwapFree:", swapFreeMem);
- break;
- case 'R':
- tryRead("SReclaimable:", sreclaimableMem);
- break;
- }
- break;
- case 'Z':
- tryRead("Zswap:", zswapCompMem);
- tryRead("Zswapped:", zswapOrigMem);
- break;
- }
-
- #undef tryRead
- }
-
- fclose(file);
-
- /*
- * Compute memory partition like procps(free)
- * https://gitlab.com/procps-ng/procps/-/blob/master/proc/sysinfo.c
- *
- * Adjustments:
- * - Shmem in part of Cached (see https://lore.kernel.org/patchwork/patch/648763/),
- * do not show twice by subtracting from Cached and do not subtract twice from used.
- */
- host->totalMem = totalMem;
- host->cachedMem = cachedMem + sreclaimableMem - sharedMem;
- host->sharedMem = sharedMem;
- const memory_t usedDiff = freeMem + cachedMem + sreclaimableMem + buffersMem;
- host->usedMem = (totalMem >= usedDiff) ? totalMem - usedDiff : totalMem - freeMem;
- host->buffersMem = buffersMem;
- host->availableMem = availableMem != 0 ? MINIMUM(availableMem, totalMem) : freeMem;
- host->totalSwap = swapTotalMem;
- host->usedSwap = swapTotalMem - swapFreeMem - swapCacheMem;
- host->cachedSwap = swapCacheMem;
- lpl->zswap.usedZswapComp = zswapCompMem;
- lpl->zswap.usedZswapOrig = zswapOrigMem;
-}
-
-static void LinuxProcessList_scanHugePages(LinuxProcessList* this) {
- this->totalHugePageMem = 0;
- for (unsigned i = 0; i < HTOP_HUGEPAGE_COUNT; i++) {
- this->usedHugePageMem[i] = MEMORY_MAX;
- }
-
- DIR* dir = opendir("/sys/kernel/mm/hugepages");
- if (!dir)
- return;
-
- const struct dirent* entry;
- while ((entry = readdir(dir)) != NULL) {
- const char* name = entry->d_name;
-
- /* Ignore all non-directories */
- if (entry->d_type != DT_DIR && entry->d_type != DT_UNKNOWN)
- continue;
-
- if (!String_startsWith(name, "hugepages-"))
- continue;
-
- char* endptr;
- unsigned long int hugePageSize = strtoul(name + strlen("hugepages-"), &endptr, 10);
- if (!endptr || *endptr != 'k')
- continue;
-
- char content[64];
- char hugePagePath[128];
- ssize_t r;
-
- xSnprintf(hugePagePath, sizeof(hugePagePath), "/sys/kernel/mm/hugepages/%s/nr_hugepages", name);
- r = xReadfile(hugePagePath, content, sizeof(content));
- if (r <= 0)
- continue;
-
- memory_t total = strtoull(content, NULL, 10);
- if (total == 0)
- continue;
-
- xSnprintf(hugePagePath, sizeof(hugePagePath), "/sys/kernel/mm/hugepages/%s/free_hugepages", name);
- r = xReadfile(hugePagePath, content, sizeof(content));
- if (r <= 0)
- continue;
-
- memory_t free = strtoull(content, NULL, 10);
-
- int shift = ffsl(hugePageSize) - 1 - (HTOP_HUGEPAGE_BASE_SHIFT - 10);
- assert(shift >= 0 && shift < HTOP_HUGEPAGE_COUNT);
-
- this->totalHugePageMem += total * hugePageSize;
- this->usedHugePageMem[shift] = (total - free) * hugePageSize;
- }
-
- closedir(dir);
-}
-
-static inline void LinuxProcessList_scanZswapInfo(LinuxProcessList *this) {
- const Machine* host = this->super.host;
- long max_pool_percent = 0;
- int r;
- char buf[256];
-
- r = xReadfile("/sys/module/zswap/parameters/max_pool_percent", buf, 256);
- if (r <= 0) {
- return;
- }
- max_pool_percent = strtol(buf, NULL, 10);
- if (max_pool_percent < 0 || max_pool_percent > 100) {
- return;
- }
-
- this->zswap.totalZswapPool = host->totalMem * max_pool_percent / 100;
- /* the rest of the metrics are set in LinuxProcessList_scanMemoryInfo() */
-}
-
-static inline void LinuxProcessList_scanZramInfo(LinuxProcessList* this) {
- memory_t totalZram = 0;
- memory_t usedZramComp = 0;
- memory_t usedZramOrig = 0;
-
- char mm_stat[34];
- char disksize[34];
-
- unsigned int i = 0;
- for (;;) {
- xSnprintf(mm_stat, sizeof(mm_stat), "/sys/block/zram%u/mm_stat", i);
- xSnprintf(disksize, sizeof(disksize), "/sys/block/zram%u/disksize", i);
- i++;
- FILE* disksize_file = fopen(disksize, "r");
- FILE* mm_stat_file = fopen(mm_stat, "r");
- if (disksize_file == NULL || mm_stat_file == NULL) {
- if (disksize_file) {
- fclose(disksize_file);
- }
- if (mm_stat_file) {
- fclose(mm_stat_file);
- }
- break;
- }
- memory_t size = 0;
- memory_t orig_data_size = 0;
- memory_t compr_data_size = 0;
-
- if (!fscanf(disksize_file, "%llu\n", &size) ||
- !fscanf(mm_stat_file, " %llu %llu", &orig_data_size, &compr_data_size)) {
- fclose(disksize_file);
- fclose(mm_stat_file);
- break;
- }
-
- totalZram += size;
- usedZramComp += compr_data_size;
- usedZramOrig += orig_data_size;
-
- fclose(disksize_file);
- fclose(mm_stat_file);
- }
-
- this->zram.totalZram = totalZram / 1024;
- this->zram.usedZramComp = usedZramComp / 1024;
- this->zram.usedZramOrig = usedZramOrig / 1024;
-}
-
-static inline void LinuxProcessList_scanZfsArcstats(LinuxProcessList* lpl) {
- memory_t dbufSize = 0;
- memory_t dnodeSize = 0;
- memory_t bonusSize = 0;
-
- FILE* file = fopen(PROCARCSTATSFILE, "r");
- if (file == NULL) {
- lpl->zfs.enabled = 0;
- return;
- }
- char buffer[128];
- while (fgets(buffer, 128, file)) {
- #define tryRead(label, variable) \
- if (String_startsWith(buffer, label)) { \
- sscanf(buffer + strlen(label), " %*2u %32llu", variable); \
- break; \
- } else (void) 0 /* Require a ";" after the macro use. */
- #define tryReadFlag(label, variable, flag) \
- if (String_startsWith(buffer, label)) { \
- (flag) = sscanf(buffer + strlen(label), " %*2u %32llu", variable); \
- break; \
- } else (void) 0 /* Require a ";" after the macro use. */
-
- switch (buffer[0]) {
- case 'c':
- tryRead("c_min", &lpl->zfs.min);
- tryRead("c_max", &lpl->zfs.max);
- tryReadFlag("compressed_size", &lpl->zfs.compressed, lpl->zfs.isCompressed);
- break;
- case 'u':
- tryRead("uncompressed_size", &lpl->zfs.uncompressed);
- break;
- case 's':
- tryRead("size", &lpl->zfs.size);
- break;
- case 'h':
- tryRead("hdr_size", &lpl->zfs.header);
- break;
- case 'd':
- tryRead("dbuf_size", &dbufSize);
- tryRead("dnode_size", &dnodeSize);
- break;
- case 'b':
- tryRead("bonus_size", &bonusSize);
- break;
- case 'a':
- tryRead("anon_size", &lpl->zfs.anon);
- break;
- case 'm':
- tryRead("mfu_size", &lpl->zfs.MFU);
- tryRead("mru_size", &lpl->zfs.MRU);
- break;
- }
- #undef tryRead
- #undef tryReadFlag
- }
- fclose(file);
-
- lpl->zfs.enabled = (lpl->zfs.size > 0 ? 1 : 0);
- lpl->zfs.size /= 1024;
- lpl->zfs.min /= 1024;
- lpl->zfs.max /= 1024;
- lpl->zfs.MFU /= 1024;
- lpl->zfs.MRU /= 1024;
- lpl->zfs.anon /= 1024;
- lpl->zfs.header /= 1024;
- lpl->zfs.other = (dbufSize + dnodeSize + bonusSize) / 1024;
- if ( lpl->zfs.isCompressed ) {
- lpl->zfs.compressed /= 1024;
- lpl->zfs.uncompressed /= 1024;
- }
-}
-
-static inline double LinuxProcessList_scanCPUTime(ProcessList* super) {
+void ProcessList_goThroughEntries(ProcessList* super) {
LinuxProcessList* this = (LinuxProcessList*) super;
-
- LinuxProcessList_updateCPUcount(super);
-
- FILE* file = fopen(PROCSTATFILE, "r");
- if (!file)
- CRT_fatalError("Cannot open " PROCSTATFILE);
-
- Machine* host = super->host;
- unsigned int existingCPUs = host->existingCPUs;
- unsigned int lastAdjCpuId = 0;
-
- for (unsigned int i = 0; i <= existingCPUs; i++) {
- char buffer[PROC_LINE_LENGTH + 1];
- unsigned long long int usertime, nicetime, systemtime, idletime;
- unsigned long long int ioWait = 0, irq = 0, softIrq = 0, steal = 0, guest = 0, guestnice = 0;
-
- const char* ok = fgets(buffer, sizeof(buffer), file);
- if (!ok)
- break;
-
- // cpu fields are sorted first
- if (!String_startsWith(buffer, "cpu"))
- break;
-
- // Depending on your kernel version,
- // 5, 7, 8 or 9 of these fields will be set.
- // The rest will remain at zero.
- unsigned int adjCpuId;
- if (i == 0) {
- (void) sscanf(buffer, "cpu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu", &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice);
- adjCpuId = 0;
- } else {
- unsigned int cpuid;
- (void) sscanf(buffer, "cpu%4u %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu", &cpuid, &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice);
- adjCpuId = cpuid + 1;
- }
-
- if (adjCpuId > host->existingCPUs)
- break;
-
- for (unsigned int j = lastAdjCpuId + 1; j < adjCpuId; j++) {
- // Skipped an ID, but /proc/stat is ordered => got offline CPU
- memset(&(this->cpuData[j]), '\0', sizeof(CPUData));
- }
- lastAdjCpuId = adjCpuId;
-
- // Guest time is already accounted in usertime
- usertime -= guest;
- nicetime -= guestnice;
- // Fields existing on kernels >= 2.6
- // (and RHEL's patched kernel 2.4...)
- unsigned long long int idlealltime = idletime + ioWait;
- unsigned long long int systemalltime = systemtime + irq + softIrq;
- unsigned long long int virtalltime = guest + guestnice;
- unsigned long long int totaltime = usertime + nicetime + systemalltime + idlealltime + steal + virtalltime;
- CPUData* cpuData = &(this->cpuData[adjCpuId]);
- // Since we do a subtraction (usertime - guest) and cputime64_to_clock_t()
- // used in /proc/stat rounds down numbers, it can lead to a case where the
- // integer overflow.
- cpuData->userPeriod = saturatingSub(usertime, cpuData->userTime);
- cpuData->nicePeriod = saturatingSub(nicetime, cpuData->niceTime);
- cpuData->systemPeriod = saturatingSub(systemtime, cpuData->systemTime);
- cpuData->systemAllPeriod = saturatingSub(systemalltime, cpuData->systemAllTime);
- cpuData->idleAllPeriod = saturatingSub(idlealltime, cpuData->idleAllTime);
- cpuData->idlePeriod = saturatingSub(idletime, cpuData->idleTime);
- cpuData->ioWaitPeriod = saturatingSub(ioWait, cpuData->ioWaitTime);
- cpuData->irqPeriod = saturatingSub(irq, cpuData->irqTime);
- cpuData->softIrqPeriod = saturatingSub(softIrq, cpuData->softIrqTime);
- cpuData->stealPeriod = saturatingSub(steal, cpuData->stealTime);
- cpuData->guestPeriod = saturatingSub(virtalltime, cpuData->guestTime);
- cpuData->totalPeriod = saturatingSub(totaltime, cpuData->totalTime);
- cpuData->userTime = usertime;
- cpuData->niceTime = nicetime;
- cpuData->systemTime = systemtime;
- cpuData->systemAllTime = systemalltime;
- cpuData->idleAllTime = idlealltime;
- cpuData->idleTime = idletime;
- cpuData->ioWaitTime = ioWait;
- cpuData->irqTime = irq;
- cpuData->softIrqTime = softIrq;
- cpuData->stealTime = steal;
- cpuData->guestTime = virtalltime;
- cpuData->totalTime = totaltime;
- }
-
- double period = (double)this->cpuData[0].totalPeriod / host->activeCPUs;
-
- char buffer[PROC_LINE_LENGTH + 1];
- while (fgets(buffer, sizeof(buffer), file)) {
- if (String_startsWith(buffer, "procs_running")) {
- super->runningTasks = strtoul(buffer + strlen("procs_running"), NULL, 10);
- break;
- }
- }
-
- fclose(file);
-
- return period;
-}
-
-static int scanCPUFrequencyFromSysCPUFreq(LinuxProcessList* this) {
- const Machine* host = this->super.host;
- unsigned int existingCPUs = host->existingCPUs;
- int numCPUsWithFrequency = 0;
- unsigned long totalFrequency = 0;
-
- /*
- * On some AMD and Intel CPUs read()ing scaling_cur_freq is quite slow (> 1ms). This delay
- * accumulates for every core. For details see issue#471.
- * If the read on CPU 0 takes longer than 500us bail out and fall back to reading the
- * frequencies from /proc/cpuinfo.
- * Once the condition has been met, bail out early for the next couple of scans.
- */
- static int timeout = 0;
-
- if (timeout > 0) {
- timeout--;
- return -1;
- }
-
- for (unsigned int i = 0; i < existingCPUs; ++i) {
- if (!Machine_isCPUonline(host, i))
- continue;
-
- char pathBuffer[64];
- xSnprintf(pathBuffer, sizeof(pathBuffer), "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq", i);
-
- struct timespec start;
- if (i == 0)
- clock_gettime(CLOCK_MONOTONIC, &start);
-
- FILE* file = fopen(pathBuffer, "r");
- if (!file)
- return -errno;
-
- unsigned long frequency;
- if (fscanf(file, "%lu", &frequency) == 1) {
- /* convert kHz to MHz */
- frequency = frequency / 1000;
- this->cpuData[i + 1].frequency = frequency;
- numCPUsWithFrequency++;
- totalFrequency += frequency;
- }
-
- fclose(file);
-
- if (i == 0) {
- struct timespec end;
- clock_gettime(CLOCK_MONOTONIC, &end);
- const time_t timeTakenUs = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_nsec - start.tv_nsec) / 1000;
- if (timeTakenUs > 500) {
- timeout = 30;
- return -1;
- }
- }
-
- }
-
- if (numCPUsWithFrequency > 0)
- this->cpuData[0].frequency = (double)totalFrequency / numCPUsWithFrequency;
-
- return 0;
-}
-
-static void scanCPUFrequencyFromCPUinfo(LinuxProcessList* this) {
- FILE* file = fopen(PROCCPUINFOFILE, "r");
- if (file == NULL)
- return;
-
- unsigned int existingCPUs = this->super.host->existingCPUs;
- int numCPUsWithFrequency = 0;
- double totalFrequency = 0;
- int cpuid = -1;
-
- while (!feof(file)) {
- double frequency;
- char buffer[PROC_LINE_LENGTH];
-
- if (fgets(buffer, PROC_LINE_LENGTH, file) == NULL)
- break;
-
- if (sscanf(buffer, "processor : %d", &cpuid) == 1) {
- continue;
- } else if (
- (sscanf(buffer, "cpu MHz : %lf", &frequency) == 1) ||
- (sscanf(buffer, "clock : %lfMHz", &frequency) == 1)
- ) {
- if (cpuid < 0 || (unsigned int)cpuid > (existingCPUs - 1)) {
- continue;
- }
-
- CPUData* cpuData = &(this->cpuData[cpuid + 1]);
- /* do not override sysfs data */
- if (isnan(cpuData->frequency)) {
- cpuData->frequency = frequency;
- }
- numCPUsWithFrequency++;
- totalFrequency += frequency;
- } else if (buffer[0] == '\n') {
- cpuid = -1;
- }
- }
- fclose(file);
-
- if (numCPUsWithFrequency > 0) {
- this->cpuData[0].frequency = totalFrequency / numCPUsWithFrequency;
- }
-}
-
-static void LinuxProcessList_scanCPUFrequency(LinuxProcessList* this) {
- unsigned int existingCPUs = this->super.host->existingCPUs;
-
- for (unsigned int i = 0; i <= existingCPUs; i++) {
- this->cpuData[i].frequency = NAN;
- }
-
- if (scanCPUFrequencyFromSysCPUFreq(this) == 0) {
- return;
- }
-
- scanCPUFrequencyFromCPUinfo(this);
-}
-
-void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
- LinuxProcessList* this = (LinuxProcessList*) super;
-
const Machine* host = super->host;
const Settings* settings = host->settings;
-
- LinuxProcessList_scanMemoryInfo(super);
- LinuxProcessList_scanHugePages(this);
- LinuxProcessList_scanZfsArcstats(this);
- LinuxProcessList_scanZramInfo(this);
- LinuxProcessList_scanZswapInfo(this);
-
- double period = LinuxProcessList_scanCPUTime(super);
-
- if (settings->showCPUFrequency) {
- LinuxProcessList_scanCPUFrequency(this);
- }
-
- #ifdef HAVE_SENSORS_SENSORS_H
- if (settings->showCPUTemperature)
- LibSensors_getCPUTemperatures(this->cpuData, host->existingCPUs, host->activeCPUs);
- #endif
-
- // in pause mode only gather global data for meters (CPU/memory/...)
- if (pauseProcessUpdate) {
- return;
- }
+ const LinuxMachine* lhost = (const LinuxMachine*) host;
if (settings->ss->flags & PROCESS_FLAG_LINUX_AUTOGROUP) {
// Refer to sched(7) 'autogroup feature' section
@@ -2293,22 +1625,5 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
openat_arg_t rootFd = "";
#endif
- LinuxProcessList_recurseProcTree(this, rootFd, PROCDIR, NULL, period);
-}
-
-Machine* Machine_new(UsersTable* usersTable, uid_t userId) {
- Machine* this = xCalloc(1, sizeof(Machine));
- Machine_init(this, usersTable, userId);
- return this;
-}
-
-void Machine_delete(Machine* host) {
- free(host);
-}
-
-bool Machine_isCPUonline(const Machine* host, unsigned int id) {
- assert(id < host->existingCPUs);
-
- const LinuxProcessList* this = (const LinuxProcessList*) host->pl;
- return this->cpuData[id + 1].online;
+ LinuxProcessList_recurseProcTree(this, rootFd, lhost, PROCDIR, NULL);
}
diff --git a/linux/LinuxProcessList.h b/linux/LinuxProcessList.h
index 69bae5c0..824de482 100644
--- a/linux/LinuxProcessList.h
+++ b/linux/LinuxProcessList.h
@@ -15,48 +15,7 @@ in the source distribution for its full text.
#include "Hashtable.h"
#include "ProcessList.h"
#include "UsersTable.h"
-#include "linux/ZramStats.h"
-#include "linux/ZswapStats.h"
-#include "zfs/ZfsArcStats.h"
-#define HTOP_HUGEPAGE_BASE_SHIFT 16
-#define HTOP_HUGEPAGE_COUNT 24
-
-typedef struct CPUData_ {
- unsigned long long int totalTime;
- unsigned long long int userTime;
- unsigned long long int systemTime;
- unsigned long long int systemAllTime;
- unsigned long long int idleAllTime;
- unsigned long long int idleTime;
- unsigned long long int niceTime;
- unsigned long long int ioWaitTime;
- unsigned long long int irqTime;
- unsigned long long int softIrqTime;
- unsigned long long int stealTime;
- unsigned long long int guestTime;
-
- unsigned long long int totalPeriod;
- unsigned long long int userPeriod;
- unsigned long long int systemPeriod;
- unsigned long long int systemAllPeriod;
- unsigned long long int idleAllPeriod;
- unsigned long long int idlePeriod;
- unsigned long long int nicePeriod;
- unsigned long long int ioWaitPeriod;
- unsigned long long int irqPeriod;
- unsigned long long int softIrqPeriod;
- unsigned long long int stealPeriod;
- unsigned long long int guestPeriod;
-
- double frequency;
-
- #ifdef HAVE_SENSORS_SENSORS_H
- double temperature;
- #endif
-
- bool online;
-} CPUData;
typedef struct TtyDriver_ {
char* path;
@@ -68,8 +27,6 @@ typedef struct TtyDriver_ {
typedef struct LinuxProcessList_ {
ProcessList super;
- CPUData* cpuData;
-
TtyDriver* ttyDrivers;
bool haveSmapsRollup;
bool haveAutogroup;
@@ -78,55 +35,6 @@ typedef struct LinuxProcessList_ {
struct nl_sock* netlink_socket;
int netlink_family;
#endif
-
- memory_t totalHugePageMem;
- memory_t usedHugePageMem[HTOP_HUGEPAGE_COUNT];
-
- memory_t availableMem;
-
- ZfsArcStats zfs;
- ZramStats zram;
- ZswapStats zswap;
} LinuxProcessList;
-#ifndef PROCDIR
-#define PROCDIR "/proc"
-#endif
-
-#ifndef PROCCPUINFOFILE
-#define PROCCPUINFOFILE PROCDIR "/cpuinfo"
-#endif
-
-#ifndef PROCSTATFILE
-#define PROCSTATFILE PROCDIR "/stat"
-#endif
-
-#ifndef PROCMEMINFOFILE
-#define PROCMEMINFOFILE PROCDIR "/meminfo"
-#endif
-
-#ifndef PROCARCSTATSFILE
-#define PROCARCSTATSFILE PROCDIR "/spl/kstat/zfs/arcstats"
-#endif
-
-#ifndef PROCTTYDRIVERSFILE
-#define PROCTTYDRIVERSFILE PROCDIR "/tty/drivers"
-#endif
-
-#ifndef PROC_LINE_LENGTH
-#define PROC_LINE_LENGTH 4096
-#endif
-
-ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList);
-
-void ProcessList_delete(ProcessList* pl);
-
-void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
-
-Machine* Machine_new(UsersTable* usersTable, uid_t userId);
-
-bool Machine_isCPUonline(const Machine* host, unsigned int id);
-
-void Machine_delete(Machine* host);
-
#endif
diff --git a/linux/Platform.c b/linux/Platform.c
index 68cefce9..693044af 100644
--- a/linux/Platform.c
+++ b/linux/Platform.c
@@ -36,6 +36,7 @@ in the source distribution for its full text.
#include "HostnameMeter.h"
#include "HugePageMeter.h"
#include "LoadAverageMeter.h"
+#include "Machine.h"
#include "Macros.h"
#include "MainPanel.h"
#include "Meter.h"
@@ -45,7 +46,6 @@ in the source distribution for its full text.
#include "Object.h"
#include "Panel.h"
#include "PressureStallMeter.h"
-#include "ProcessList.h"
#include "ProvideCurses.h"
#include "linux/SELinuxMeter.h"
#include "Settings.h"
@@ -56,8 +56,8 @@ in the source distribution for its full text.
#include "XUtils.h"
#include "linux/IOPriority.h"
#include "linux/IOPriorityPanel.h"
+#include "linux/LinuxMachine.h"
#include "linux/LinuxProcess.h"
-#include "linux/LinuxProcessList.h"
#include "linux/SystemdMeter.h"
#include "linux/ZramMeter.h"
#include "linux/ZramStats.h"
@@ -304,9 +304,9 @@ int Platform_getMaxPid(void) {
}
double Platform_setCPUValues(Meter* this, unsigned int cpu) {
- const Machine* host = this->host;
- const LinuxProcessList* pl = (const LinuxProcessList*) host->pl;
- const CPUData* cpuData = &(pl->cpuData[cpu]);
+ const LinuxMachine* lhost = (const LinuxMachine *) this->host;
+ const Settings* settings = this->host->settings;
+ const CPUData* cpuData = &(lhost->cpuData[cpu]);
double total = (double) ( cpuData->totalPeriod == 0 ? 1 : cpuData->totalPeriod);
double percent;
double* v = this->values;
@@ -318,7 +318,7 @@ double Platform_setCPUValues(Meter* this, unsigned int cpu) {
v[CPU_METER_NICE] = cpuData->nicePeriod / total * 100.0;
v[CPU_METER_NORMAL] = cpuData->userPeriod / total * 100.0;
- if (host->settings->detailedCPUTime) {
+ if (settings->detailedCPUTime) {
v[CPU_METER_KERNEL] = cpuData->systemPeriod / total * 100.0;
v[CPU_METER_IRQ] = cpuData->irqPeriod / total * 100.0;
v[CPU_METER_SOFTIRQ] = cpuData->softIrqPeriod / total * 100.0;
@@ -327,7 +327,7 @@ double Platform_setCPUValues(Meter* this, unsigned int cpu) {
v[CPU_METER_IOWAIT] = cpuData->ioWaitPeriod / total * 100.0;
this->curItems = 8;
percent = v[CPU_METER_NICE] + v[CPU_METER_NORMAL] + v[CPU_METER_KERNEL] + v[CPU_METER_IRQ] + v[CPU_METER_SOFTIRQ];
- if (host->settings->accountGuestInCPUMeter) {
+ if (settings->accountGuestInCPUMeter) {
percent += v[CPU_METER_STEAL] + v[CPU_METER_GUEST];
}
} else {
@@ -354,7 +354,7 @@ double Platform_setCPUValues(Meter* this, unsigned int cpu) {
void Platform_setMemoryValues(Meter* this) {
const Machine* host = this->host;
- const LinuxProcessList* lpl = (const LinuxProcessList*) host->pl;
+ const LinuxMachine* lhost = (const LinuxMachine*) host;
this->total = host->totalMem;
this->values[MEMORY_METER_USED] = host->usedMem;
@@ -364,32 +364,32 @@ void Platform_setMemoryValues(Meter* this) {
this->values[MEMORY_METER_CACHE] = host->cachedMem;
this->values[MEMORY_METER_AVAILABLE] = host->availableMem;
- if (lpl->zfs.enabled != 0 && !Running_containerized) {
+ if (lhost->zfs.enabled != 0 && !Running_containerized) {
// ZFS does not shrink below the value of zfs_arc_min.
unsigned long long int shrinkableSize = 0;
- if (lpl->zfs.size > lpl->zfs.min)
- shrinkableSize = lpl->zfs.size - lpl->zfs.min;
+ if (lhost->zfs.size > lhost->zfs.min)
+ shrinkableSize = lhost->zfs.size - lhost->zfs.min;
this->values[MEMORY_METER_USED] -= shrinkableSize;
this->values[MEMORY_METER_CACHE] += shrinkableSize;
this->values[MEMORY_METER_AVAILABLE] += shrinkableSize;
}
- if (lpl->zswap.usedZswapOrig > 0 || lpl->zswap.usedZswapComp > 0) {
- this->values[MEMORY_METER_USED] -= lpl->zswap.usedZswapComp;
- this->values[MEMORY_METER_COMPRESSED] += lpl->zswap.usedZswapComp;
+ if (lhost->zswap.usedZswapOrig > 0 || lhost->zswap.usedZswapComp > 0) {
+ this->values[MEMORY_METER_USED] -= lhost->zswap.usedZswapComp;
+ this->values[MEMORY_METER_COMPRESSED] += lhost->zswap.usedZswapComp;
}
}
void Platform_setSwapValues(Meter* this) {
const Machine* host = this->host;
- const LinuxProcessList* lpl = (const LinuxProcessList*) host->pl;
+ const LinuxMachine* lhost = (const LinuxMachine*) host;
this->total = host->totalSwap;
this->values[SWAP_METER_USED] = host->usedSwap;
this->values[SWAP_METER_CACHE] = host->cachedSwap;
this->values[SWAP_METER_FRONTSWAP] = 0; /* frontswap -- memory that is accounted to swap but resides elsewhere */
- if (lpl->zswap.usedZswapOrig > 0 || lpl->zswap.usedZswapComp > 0) {
+ if (lhost->zswap.usedZswapOrig > 0 || lhost->zswap.usedZswapComp > 0) {
/*
* FIXME: Zswapped pages can be both SwapUsed and SwapCached, and we do not know which.
*
@@ -400,33 +400,34 @@ void Platform_setSwapValues(Meter* this) {
* For now, subtract Zswapped from SwapUsed and only if Zswapped > SwapUsed, subtract the
* overflow from SwapCached.
*/
- this->values[SWAP_METER_USED] -= lpl->zswap.usedZswapOrig;
+ this->values[SWAP_METER_USED] -= lhost->zswap.usedZswapOrig;
if (this->values[SWAP_METER_USED] < 0) {
/* subtract the overflow from SwapCached */
this->values[SWAP_METER_CACHE] += this->values[SWAP_METER_USED];
this->values[SWAP_METER_USED] = 0;
}
- this->values[SWAP_METER_FRONTSWAP] += lpl->zswap.usedZswapOrig;
+ this->values[SWAP_METER_FRONTSWAP] += lhost->zswap.usedZswapOrig;
}
}
void Platform_setZramValues(Meter* this) {
- const LinuxProcessList* lpl = (const LinuxProcessList*) this->host->pl;
- this->total = lpl->zram.totalZram;
- this->values[ZRAM_METER_COMPRESSED] = lpl->zram.usedZramComp;
- this->values[ZRAM_METER_UNCOMPRESSED] = lpl->zram.usedZramOrig;
+ const LinuxMachine* lhost = (const LinuxMachine*) this->host;
+
+ this->total = lhost->zram.totalZram;
+ this->values[ZRAM_METER_COMPRESSED] = lhost->zram.usedZramComp;
+ this->values[ZRAM_METER_UNCOMPRESSED] = lhost->zram.usedZramOrig;
}
void Platform_setZfsArcValues(Meter* this) {
- const LinuxProcessList* lpl = (const LinuxProcessList*) this->host->pl;
+ const LinuxMachine* lhost = (const LinuxMachine*) this->host;
- ZfsArcMeter_readStats(this, &(lpl->zfs));
+ ZfsArcMeter_readStats(this, &(lhost->zfs));
}
void Platform_setZfsCompressedArcValues(Meter* this) {
- const LinuxProcessList* lpl = (const LinuxProcessList*) this->host->pl;
+ const LinuxMachine* lhost = (const LinuxMachine*) this->host;
- ZfsCompressedArcMeter_readStats(this, &(lpl->zfs));
+ ZfsCompressedArcMeter_readStats(this, &(lhost->zfs));
}
char* Platform_getProcessEnv(pid_t pid) {
diff --git a/netbsd/NetBSDMachine.c b/netbsd/NetBSDMachine.c
new file mode 100644
index 00000000..1e2a0a13
--- /dev/null
+++ b/netbsd/NetBSDMachine.c
@@ -0,0 +1,282 @@
+/*
+htop - NetBSDMachine.c
+(C) 2014 Hisham H. Muhammad
+(C) 2015 Michael McConville
+(C) 2021 Santhosh Raju
+(C) 2021 htop dev team
+Released under the GNU GPLv2+, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "netbsd/NetBSDMachine.h"
+
+#include <kvm.h>
+#include <math.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mount.h>
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/sched.h>
+#include <sys/swap.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <uvm/uvm_extern.h>
+
+#include "CRT.h"
+#include "Machine.h"
+#include "Macros.h"
+#include "Object.h"
+#include "Settings.h"
+#include "XUtils.h"
+
+
+static const struct {
+ const char* name;
+ long int scale;
+} freqSysctls[] = {
+ { "machdep.est.frequency.current", 1 },
+ { "machdep.powernow.frequency.current", 1 },
+ { "machdep.intrepid.frequency.current", 1 },
+ { "machdep.loongson.frequency.current", 1 },
+ { "machdep.cpu.frequency.current", 1 },
+ { "machdep.frequency.current", 1 },
+ { "machdep.tsc_freq", 1000000 },
+};
+
+static void NetBSDMachine_updateCPUcount(NetBSDMachine* this) {
+ Machine* super = &this->super;
+
+ // Definitions for sysctl(3), cf. https://nxr.netbsd.org/xref/src/sys/sys/sysctl.h#813
+ const int mib_ncpu_existing[] = { CTL_HW, HW_NCPU }; // Number of existing CPUs
+ const int mib_ncpu_online[] = { CTL_HW, HW_NCPUONLINE }; // Number of online/active CPUs
+
+ int r;
+ unsigned int value;
+ size_t size;
+
+ bool change = false;
+
+ // Query the number of active/online CPUs.
+ size = sizeof(value);
+ r = sysctl(mib_ncpu_online, 2, &value, &size, NULL, 0);
+ if (r < 0 || value < 1) {
+ value = 1;
+ }
+
+ if (value != super->activeCPUs) {
+ super->activeCPUs = value;
+ change = true;
+ }
+
+ // Query the total number of CPUs.
+ size = sizeof(value);
+ r = sysctl(mib_ncpu_existing, 2, &value, &size, NULL, 0);
+ if (r < 0 || value < 1) {
+ value = super->activeCPUs;
+ }
+
+ if (value != super->existingCPUs) {
+ opl->cpuData = xReallocArray(this->cpuData, value + 1, sizeof(CPUData));
+ super->existingCPUs = value;
+ change = true;
+ }
+
+ // Reset CPU stats when number of online/existing CPU cores changed
+ if (change) {
+ CPUData* dAvg = &this->cpuData[0];
+ memset(dAvg, '\0', sizeof(CPUData));
+ dAvg->totalTime = 1;
+ dAvg->totalPeriod = 1;
+
+ for (unsigned int i = 0; i < super->existingCPUs; i++) {
+ CPUData* d = &this->cpuData[i + 1];
+ memset(d, '\0', sizeof(CPUData));
+ d->totalTime = 1;
+ d->totalPeriod = 1;
+ }
+ }
+}
+
+Machine* Machine_new(UsersTable* usersTable, uid_t userId) {
+ const int fmib[] = { CTL_KERN, KERN_FSCALE };
+ size_t size;
+ char errbuf[_POSIX2_LINE_MAX];
+
+ NetBSDMachine* this = xCalloc(1, sizeof(NetBSDMachine));
+ Machine* super = &this->super;
+ Machine_init(super, usersTable, userId);
+
+ NetBSDMachine_updateCPUcount(this);
+
+ size = sizeof(this->fscale);
+ if (sysctl(fmib, 2, &this->fscale, &size, NULL, 0) < 0) {
+ CRT_fatalError("fscale sysctl call failed");
+ }
+
+ if ((this->pageSize = sysconf(_SC_PAGESIZE)) == -1)
+ CRT_fatalError("pagesize sysconf call failed");
+ this->pageSizeKB = this->pageSize / ONE_K;
+
+ this->kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
+ if (this->kd == NULL) {
+ CRT_fatalError("kvm_openfiles() failed");
+ }
+
+ return this;
+}
+
+void Machine_delete(Machine* super) {
+ NetBSDMachine* this = (NetBSDProcessList*) super;
+
+ Machine_done(super);
+
+ if (this->kd) {
+ kvm_close(this->kd);
+ }
+ free(this->cpuData);
+ free(this);
+}
+
+static void NetBSDMachine_scanMemoryInfo(NetBSDMachine* this) {
+ Machine* super = &this->super;
+
+ static int uvmexp_mib[] = {CTL_VM, VM_UVMEXP2};
+ struct uvmexp_sysctl uvmexp;
+ size_t size_uvmexp = sizeof(uvmexp);
+
+ if (sysctl(uvmexp_mib, 2, &uvmexp, &size_uvmexp, NULL, 0) < 0) {
+ CRT_fatalError("uvmexp sysctl call failed");
+ }
+
+ super->totalMem = uvmexp.npages * this->pageSizeKB;
+ super->buffersMem = 0;
+ super->cachedMem = (uvmexp.filepages + uvmexp.execpages) * this->pageSizeKB;
+ super->usedMem = (uvmexp.active + uvmexp.wired) * this->pageSizeKB;
+ super->totalSwap = uvmexp.swpages * this->pageSizeKB;
+ super->usedSwap = uvmexp.swpginuse * this->pageSizeKB;
+}
+
+static void getKernelCPUTimes(int cpuId, u_int64_t* times) {
+ const int mib[] = { CTL_KERN, KERN_CP_TIME, cpuId };
+ size_t length = sizeof(*times) * CPUSTATES;
+ if (sysctl(mib, 3, times, &length, NULL, 0) == -1 || length != sizeof(*times) * CPUSTATES) {
+ CRT_fatalError("sysctl kern.cp_time2 failed");
+ }
+}
+
+static void kernelCPUTimesToHtop(const u_int64_t* times, CPUData* cpu) {
+ unsigned long long totalTime = 0;
+ for (int i = 0; i < CPUSTATES; i++) {
+ totalTime += times[i];
+ }
+
+ unsigned long long sysAllTime = times[CP_INTR] + times[CP_SYS];
+
+ cpu->totalPeriod = saturatingSub(totalTime, cpu->totalTime);
+ cpu->userPeriod = saturatingSub(times[CP_USER], cpu->userTime);
+ cpu->nicePeriod = saturatingSub(times[CP_NICE], cpu->niceTime);
+ cpu->sysPeriod = saturatingSub(times[CP_SYS], cpu->sysTime);
+ cpu->sysAllPeriod = saturatingSub(sysAllTime, cpu->sysAllTime);
+ cpu->intrPeriod = saturatingSub(times[CP_INTR], cpu->intrTime);
+ cpu->idlePeriod = saturatingSub(times[CP_IDLE], cpu->idleTime);
+
+ cpu->totalTime = totalTime;
+ cpu->userTime = times[CP_USER];
+ cpu->niceTime = times[CP_NICE];
+ cpu->sysTime = times[CP_SYS];
+ cpu->sysAllTime = sysAllTime;
+ cpu->intrTime = times[CP_INTR];
+ cpu->idleTime = times[CP_IDLE];
+}
+
+static void NetBSDMachine_scanCPUTime(NetBSDMachine* this) {
+ const Machine* super = &this->super;
+
+ u_int64_t kernelTimes[CPUSTATES] = {0};
+ u_int64_t avg[CPUSTATES] = {0};
+
+ for (unsigned int i = 0; i < super->existingCPUs; i++) {
+ getKernelCPUTimes(i, kernelTimes);
+ CPUData* cpu = &this->cpuData[i + 1];
+ kernelCPUTimesToHtop(kernelTimes, cpu);
+
+ avg[CP_USER] += cpu->userTime;
+ avg[CP_NICE] += cpu->niceTime;
+ avg[CP_SYS] += cpu->sysTime;
+ avg[CP_INTR] += cpu->intrTime;
+ avg[CP_IDLE] += cpu->idleTime;
+ }
+
+ for (int i = 0; i < CPUSTATES; i++) {
+ avg[i] /= super->activeCPUs;
+ }
+
+ kernelCPUTimesToHtop(avg, &this->cpuData[0]);
+}
+
+static void NetBSDMachine_scanCPUFrequency(NetBSDMachine* this) {
+ const Machine* super = &this->super;
+ unsigned int cpus = super->existingCPUs;
+ bool match = false;
+ char name[64];
+ long int freq = 0;
+ size_t freqSize;
+
+ for (unsigned int i = 0; i < cpus; i++) {
+ this->cpuData[i + 1].frequency = NAN;
+ }
+
+ /* newer hardware supports per-core frequency, for e.g. ARM big.LITTLE */
+ for (unsigned int i = 0; i < cpus; i++) {
+ xSnprintf(name, sizeof(name), "machdep.cpufreq.cpu%u.current", i);
+ freqSize = sizeof(freq);
+ if (sysctlbyname(name, &freq, &freqSize, NULL, 0) != -1) {
+ this->cpuData[i + 1].frequency = freq; /* already in MHz */
+ match = true;
+ }
+ }
+
+ if (match) {
+ return;
+ }
+
+ /*
+ * Iterate through legacy sysctl nodes for single-core frequency until
+ * we find a match...
+ */
+ for (size_t i = 0; i < ARRAYSIZE(freqSysctls); i++) {
+ freqSize = sizeof(freq);
+ if (sysctlbyname(freqSysctls[i].name, &freq, &freqSize, NULL, 0) != -1) {
+ freq /= freqSysctls[i].scale; /* scale to MHz */
+ match = true;
+ break;
+ }
+ }
+
+ if (match) {
+ for (unsigned int i = 0; i < cpus; i++) {
+ this->cpuData[i + 1].frequency = freq;
+ }
+ }
+}
+
+void Machine_scan(Machine* super) {
+ NetBSDMachine* this = (NetBSDMachine*) super;
+
+ NetBSDProcessList_scanMemoryInfo(this);
+ NetBSDProcessList_scanCPUTime(this);
+
+ if (super->settings->showCPUFrequency) {
+ NetBSDProcessList_scanCPUFrequency(npl);
+ }
+}
+
+bool Machine_isCPUonline(const Machine* host, unsigned int id) {
+ assert(id < host->existingCPUs);
+
+ // TODO: Support detecting online / offline CPUs.
+ return true;
+}
diff --git a/netbsd/NetBSDMachine.h b/netbsd/NetBSDMachine.h
new file mode 100644
index 00000000..57070d67
--- /dev/null
+++ b/netbsd/NetBSDMachine.h
@@ -0,0 +1,54 @@
+#ifndef HEADER_NetBSDMachine
+#define HEADER_NetBSDMachine
+/*
+htop - NetBSDMachine.h
+(C) 2014 Hisham H. Muhammad
+(C) 2015 Michael McConville
+(C) 2021 Santhosh Raju
+(C) 2021 htop dev team
+Released under the GNU GPLv2+, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include <kvm.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+#include "Machine.h"
+#include "ProcessList.h"
+
+
+typedef struct CPUData_ {
+ unsigned long long int totalTime;
+ unsigned long long int userTime;
+ unsigned long long int niceTime;
+ unsigned long long int sysTime;
+ unsigned long long int sysAllTime;
+ unsigned long long int spinTime;
+ unsigned long long int intrTime;
+ unsigned long long int idleTime;
+
+ unsigned long long int totalPeriod;
+ unsigned long long int userPeriod;
+ unsigned long long int nicePeriod;
+ unsigned long long int sysPeriod;
+ unsigned long long int sysAllPeriod;
+ unsigned long long int spinPeriod;
+ unsigned long long int intrPeriod;
+ unsigned long long int idlePeriod;
+
+ double frequency;
+} CPUData;
+
+typedef struct NetBSDProcessList_ {
+ ProcessList super;
+ kvm_t* kd;
+
+ long fscale;
+ int pageSize;
+ int pageSizeKB;
+
+ CPUData* cpuData;
+} NetBSDProcessList;
+
+#endif
diff --git a/netbsd/NetBSDProcessList.c b/netbsd/NetBSDProcessList.c
index b7b6915a..9e5a9be4 100644
--- a/netbsd/NetBSDProcessList.c
+++ b/netbsd/NetBSDProcessList.c
@@ -20,7 +20,6 @@ in the source distribution for its full text.
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/sched.h>
-#include <sys/swap.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <uvm/uvm_extern.h>
@@ -32,137 +31,23 @@ in the source distribution for its full text.
#include "ProcessList.h"
#include "Settings.h"
#include "XUtils.h"
+#include "netbsd/NetBSDMachine.h"
#include "netbsd/NetBSDProcess.h"
-static long fscale;
-static int pageSize;
-static int pageSizeKB;
-
-static const struct {
- const char* name;
- long int scale;
-} freqSysctls[] = {
- { "machdep.est.frequency.current", 1 },
- { "machdep.powernow.frequency.current", 1 },
- { "machdep.intrepid.frequency.current", 1 },
- { "machdep.loongson.frequency.current", 1 },
- { "machdep.cpu.frequency.current", 1 },
- { "machdep.frequency.current", 1 },
- { "machdep.tsc_freq", 1000000 },
-};
-
-static void NetBSDProcessList_updateCPUcount(ProcessList* super) {
- NetBSDProcessList* opl = (NetBSDProcessList*) super;
- Machine* host = super->host;
-
- // Definitions for sysctl(3), cf. https://nxr.netbsd.org/xref/src/sys/sys/sysctl.h#813
- const int mib_ncpu_existing[] = { CTL_HW, HW_NCPU }; // Number of existing CPUs
- const int mib_ncpu_online[] = { CTL_HW, HW_NCPUONLINE }; // Number of online/active CPUs
-
- int r;
- unsigned int value;
- size_t size;
-
- bool change = false;
-
- // Query the number of active/online CPUs.
- size = sizeof(value);
- r = sysctl(mib_ncpu_online, 2, &value, &size, NULL, 0);
- if (r < 0 || value < 1) {
- value = 1;
- }
-
- if (value != host->activeCPUs) {
- host->activeCPUs = value;
- change = true;
- }
-
- // Query the total number of CPUs.
- size = sizeof(value);
- r = sysctl(mib_ncpu_existing, 2, &value, &size, NULL, 0);
- if (r < 0 || value < 1) {
- value = host->activeCPUs;
- }
-
- if (value != host->existingCPUs) {
- opl->cpuData = xReallocArray(opl->cpuData, value + 1, sizeof(CPUData));
- host->existingCPUs = value;
- change = true;
- }
-
- // Reset CPU stats when number of online/existing CPU cores changed
- if (change) {
- CPUData* dAvg = &opl->cpuData[0];
- memset(dAvg, '\0', sizeof(CPUData));
- dAvg->totalTime = 1;
- dAvg->totalPeriod = 1;
-
- for (unsigned int i = 0; i < host->existingCPUs; i++) {
- CPUData* d = &opl->cpuData[i + 1];
- memset(d, '\0', sizeof(CPUData));
- d->totalTime = 1;
- d->totalPeriod = 1;
- }
- }
-}
-
ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList) {
- const int fmib[] = { CTL_KERN, KERN_FSCALE };
- size_t size;
- char errbuf[_POSIX2_LINE_MAX];
-
- NetBSDProcessList* npl = xCalloc(1, sizeof(NetBSDProcessList));
- ProcessList* pl = (ProcessList*) npl;
- ProcessList_init(pl, Class(NetBSDProcess), host, pidMatchList);
+ NetBSDProcessList* this = xCalloc(1, sizeof(NetBSDProcessList));
+ ProcessList* super = (ProcessList*) this;
- NetBSDProcessList_updateCPUcount(pl);
-
- size = sizeof(fscale);
- if (sysctl(fmib, 2, &fscale, &size, NULL, 0) < 0) {
- CRT_fatalError("fscale sysctl call failed");
- }
+ ProcessList_init(super, Class(NetBSDProcess), host, pidMatchList);
- if ((pageSize = sysconf(_SC_PAGESIZE)) == -1)
- CRT_fatalError("pagesize sysconf call failed");
- pageSizeKB = pageSize / ONE_K;
-
- npl->kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
- if (npl->kd == NULL) {
- CRT_fatalError("kvm_openfiles() failed");
- }
-
- return pl;
+ return super;
}
void ProcessList_delete(ProcessList* this) {
NetBSDProcessList* npl = (NetBSDProcessList*) this;
-
- if (npl->kd) {
- kvm_close(npl->kd);
- }
-
- free(npl->cpuData);
-
ProcessList_done(this);
- free(this);
-}
-
-static void NetBSDProcessList_scanMemoryInfo(Machine* host) {
- static int uvmexp_mib[] = {CTL_VM, VM_UVMEXP2};
- struct uvmexp_sysctl uvmexp;
- size_t size_uvmexp = sizeof(uvmexp);
-
- if (sysctl(uvmexp_mib, 2, &uvmexp, &size_uvmexp, NULL, 0) < 0) {
- CRT_fatalError("uvmexp sysctl call failed");
- }
-
- host->totalMem = uvmexp.npages * pageSizeKB;
- host->buffersMem = 0;
- host->cachedMem = (uvmexp.filepages + uvmexp.execpages) * pageSizeKB;
- host->usedMem = (uvmexp.active + uvmexp.wired) * pageSizeKB;
- host->totalSwap = uvmexp.swpages * pageSizeKB;
- host->usedSwap = uvmexp.swpginuse * pageSizeKB;
+ free(npl);
}
static void NetBSDProcessList_updateExe(const struct kinfo_proc2* kproc, Process* proc) {
@@ -255,21 +140,22 @@ static void NetBSDProcessList_updateProcessName(kvm_t* kd, const struct kinfo_pr
/*
* Borrowed with modifications from NetBSD's top(1).
*/
-static double getpcpu(const struct kinfo_proc2* kp) {
- if (fscale == 0)
+static double getpcpu(const NetBSDMachine* nhost, const struct kinfo_proc2* kp) {
+ if (nhost->fscale == 0)
return 0.0;
- return 100.0 * (double)kp->p_pctcpu / fscale;
+ return 100.0 * (double)kp->p_pctcpu / nhost->fscale;
}
static void NetBSDProcessList_scanProcs(NetBSDProcessList* this) {
const Machine* host = this->super.host;
+ const NetBSDMachine* nhost = (const NetBSDMachine*) host;
const Settings* settings = host->settings;
bool hideKernelThreads = settings->hideKernelThreads;
bool hideUserlandThreads = settings->hideUserlandThreads;
int count = 0;
- const struct kinfo_proc2* kprocs = kvm_getproc2(this->kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2), &count);
+ const struct kinfo_proc2* kprocs = kvm_getproc2(nhost->kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2), &count);
for (int i = 0; i < count; i++) {
const struct kinfo_proc2* kproc = &kprocs[i];
@@ -302,10 +188,10 @@ static void NetBSDProcessList_scanProcs(NetBSDProcessList* this) {
}
NetBSDProcessList_updateExe(kproc, proc);
- NetBSDProcessList_updateProcessName(this->kd, kproc, proc);
+ NetBSDProcessList_updateProcessName(nhost->kd, kproc, proc);
} else {
if (settings->updateProcessNames) {
- NetBSDProcessList_updateProcessName(this->kd, kproc, proc);
+ NetBSDProcessList_updateProcessName(nhost->kd, kproc, proc);
}
}
@@ -321,8 +207,8 @@ static void NetBSDProcessList_scanProcs(NetBSDProcessList* this) {
proc->m_virt = kproc->p_vm_vsize;
proc->m_resident = kproc->p_vm_rssize;
- proc->percent_mem = (proc->m_resident * pageSizeKB) / (double)(host->totalMem) * 100.0;
- proc->percent_cpu = CLAMP(getpcpu(kproc), 0.0, host->activeCPUs * 100.0);
+ proc->percent_mem = (proc->m_resident * nhost->pageSizeKB) / (double)(host->totalMem) * 100.0;
+ proc->percent_cpu = CLAMP(getpcpu(nhost, kproc), 0.0, host->activeCPUs * 100.0);
Process_updateCPUFieldWidths(proc->percent_cpu);
proc->nlwp = kproc->p_nlwps;
@@ -334,7 +220,7 @@ static void NetBSDProcessList_scanProcs(NetBSDProcessList* this) {
proc->majflt = kproc->p_uru_majflt;
int nlwps = 0;
- const struct kinfo_lwp* klwps = kvm_getlwps(this->kd, kproc->p_pid, kproc->p_paddr, sizeof(struct kinfo_lwp), &nlwps);
+ const struct kinfo_lwp* klwps = kvm_getlwps(nhost->kd, kproc->p_pid, kproc->p_paddr, sizeof(struct kinfo_lwp), &nlwps);
/* TODO: According to the link below, SDYING should be a regarded state */
/* Taken from: https://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/sys/sys/proc.h */
@@ -379,140 +265,8 @@ static void NetBSDProcessList_scanProcs(NetBSDProcessList* this) {
}
}
-static void getKernelCPUTimes(int cpuId, u_int64_t* times) {
- const int mib[] = { CTL_KERN, KERN_CP_TIME, cpuId };
- size_t length = sizeof(*times) * CPUSTATES;
- if (sysctl(mib, 3, times, &length, NULL, 0) == -1 || length != sizeof(*times) * CPUSTATES) {
- CRT_fatalError("sysctl kern.cp_time2 failed");
- }
-}
-
-static void kernelCPUTimesToHtop(const u_int64_t* times, CPUData* cpu) {
- unsigned long long totalTime = 0;
- for (int i = 0; i < CPUSTATES; i++) {
- totalTime += times[i];
- }
-
- unsigned long long sysAllTime = times[CP_INTR] + times[CP_SYS];
-
- cpu->totalPeriod = saturatingSub(totalTime, cpu->totalTime);
- cpu->userPeriod = saturatingSub(times[CP_USER], cpu->userTime);
- cpu->nicePeriod = saturatingSub(times[CP_NICE], cpu->niceTime);
- cpu->sysPeriod = saturatingSub(times[CP_SYS], cpu->sysTime);
- cpu->sysAllPeriod = saturatingSub(sysAllTime, cpu->sysAllTime);
- cpu->intrPeriod = saturatingSub(times[CP_INTR], cpu->intrTime);
- cpu->idlePeriod = saturatingSub(times[CP_IDLE], cpu->idleTime);
-
- cpu->totalTime = totalTime;
- cpu->userTime = times[CP_USER];
- cpu->niceTime = times[CP_NICE];
- cpu->sysTime = times[CP_SYS];
- cpu->sysAllTime = sysAllTime;
- cpu->intrTime = times[CP_INTR];
- cpu->idleTime = times[CP_IDLE];
-}
-
-static void NetBSDProcessList_scanCPUTime(NetBSDProcessList* this) {
- const Machine* host = this->super.host;
- u_int64_t kernelTimes[CPUSTATES] = {0};
- u_int64_t avg[CPUSTATES] = {0};
-
- for (unsigned int i = 0; i < host->existingCPUs; i++) {
- getKernelCPUTimes(i, kernelTimes);
- CPUData* cpu = &this->cpuData[i + 1];
- kernelCPUTimesToHtop(kernelTimes, cpu);
-
- avg[CP_USER] += cpu->userTime;
- avg[CP_NICE] += cpu->niceTime;
- avg[CP_SYS] += cpu->sysTime;
- avg[CP_INTR] += cpu->intrTime;
- avg[CP_IDLE] += cpu->idleTime;
- }
-
- for (int i = 0; i < CPUSTATES; i++) {
- avg[i] /= host->activeCPUs;
- }
-
- kernelCPUTimesToHtop(avg, &this->cpuData[0]);
-}
-
-static void NetBSDProcessList_scanCPUFrequency(NetBSDProcessList* this) {
- const Machine* host = this->super.host;
- unsigned int cpus = host->existingCPUs;
- bool match = false;
- char name[64];
- long int freq = 0;
- size_t freqSize;
-
- for (unsigned int i = 0; i < cpus; i++) {
- this->cpuData[i + 1].frequency = NAN;
- }
-
- /* newer hardware supports per-core frequency, for e.g. ARM big.LITTLE */
- for (unsigned int i = 0; i < cpus; i++) {
- xSnprintf(name, sizeof(name), "machdep.cpufreq.cpu%u.current", i);
- freqSize = sizeof(freq);
- if (sysctlbyname(name, &freq, &freqSize, NULL, 0) != -1) {
- this->cpuData[i + 1].frequency = freq; /* already in MHz */
- match = true;
- }
- }
-
- if (match) {
- return;
- }
-
- /*
- * Iterate through legacy sysctl nodes for single-core frequency until
- * we find a match...
- */
- for (size_t i = 0; i < ARRAYSIZE(freqSysctls); i++) {
- freqSize = sizeof(freq);
- if (sysctlbyname(freqSysctls[i].name, &freq, &freqSize, NULL, 0) != -1) {
- freq /= freqSysctls[i].scale; /* scale to MHz */
- match = true;
- break;
- }
- }
-
- if (match) {
- for (unsigned int i = 0; i < cpus; i++) {
- this->cpuData[i + 1].frequency = freq;
- }
- }
-}
-
-void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
+void ProcessList_goThroughEntries(ProcessList* super) {
NetBSDProcessList* npl = (NetBSDProcessList*) super;
- NetBSDProcessList_scanMemoryInfo(super->host);
- NetBSDProcessList_scanCPUTime(npl);
-
- if (super->settings->showCPUFrequency) {
- NetBSDProcessList_scanCPUFrequency(npl);
- }
-
- // in pause mode only gather global data for meters (CPU/memory/...)
- if (pauseProcessUpdate) {
- return;
- }
-
NetBSDProcessList_scanProcs(npl);
}
-
-Machine* Machine_new(UsersTable* usersTable, uid_t userId) {
- Machine* this = xCalloc(1, sizeof(Machine));
- Machine_init(this, usersTable, userId);
- return this;
-}
-
-void Machine_delete(Machine* host) {
- free(host);
-}
-
-bool Machine_isCPUonline(const Machine* host, unsigned int id) {
- assert(id < host->existingCPUs);
-
- // TODO: Support detecting online / offline CPUs.
- return true;
-}
diff --git a/netbsd/NetBSDProcessList.h b/netbsd/NetBSDProcessList.h
index 0fe18b03..362d84fc 100644
--- a/netbsd/NetBSDProcessList.h
+++ b/netbsd/NetBSDProcessList.h
@@ -10,55 +10,15 @@ Released under the GNU GPLv2+, see the COPYING file
in the source distribution for its full text.
*/
-#include <kvm.h>
#include <stdbool.h>
#include <sys/types.h>
#include "Hashtable.h"
#include "ProcessList.h"
-#include "UsersTable.h"
-typedef struct CPUData_ {
- unsigned long long int totalTime;
- unsigned long long int userTime;
- unsigned long long int niceTime;
- unsigned long long int sysTime;
- unsigned long long int sysAllTime;
- unsigned long long int spinTime;
- unsigned long long int intrTime;
- unsigned long long int idleTime;
-
- unsigned long long int totalPeriod;
- unsigned long long int userPeriod;
- unsigned long long int nicePeriod;
- unsigned long long int sysPeriod;
- unsigned long long int sysAllPeriod;
- unsigned long long int spinPeriod;
- unsigned long long int intrPeriod;
- unsigned long long int idlePeriod;
-
- double frequency;
-} CPUData;
-
typedef struct NetBSDProcessList_ {
ProcessList super;
- kvm_t* kd;
-
- CPUData* cpuData;
} NetBSDProcessList;
-
-ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList);
-
-void ProcessList_delete(ProcessList* this);
-
-void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
-
-Machine* Machine_new(UsersTable* usersTable, uid_t userId);
-
-bool Machine_isCPUonline(const Machine* host, unsigned int id);
-
-void Machine_delete(Machine* host);
-
#endif
diff --git a/netbsd/Platform.c b/netbsd/Platform.c
index ea81a26a..1d6509ff 100644
--- a/netbsd/Platform.c
+++ b/netbsd/Platform.c
@@ -45,7 +45,6 @@ in the source distribution for its full text.
#include "MemoryMeter.h"
#include "MemorySwapMeter.h"
#include "Meter.h"
-#include "ProcessList.h"
#include "Settings.h"
#include "SignalsPanel.h"
#include "SwapMeter.h"
@@ -54,8 +53,8 @@ in the source distribution for its full text.
#include "UptimeMeter.h"
#include "XUtils.h"
#include "generic/fdstat_sysctl.h"
+#include "netbsd/NetBSDMachine.h"
#include "netbsd/NetBSDProcess.h"
-#include "netbsd/NetBSDProcessList.h"
/*
* The older proplib APIs will be deprecated in NetBSD 10, but we still
@@ -238,8 +237,8 @@ int Platform_getMaxPid(void) {
double Platform_setCPUValues(Meter* this, int cpu) {
const Machine* host = this->host;
- const NetBSDProcessList* npl = (const NetBSDProcessList*) host->pl;
- const CPUData* cpuData = &npl->cpuData[cpu];
+ const NetBSDMachine* nhost = (const NetBSDMachine*) host;
+ const CPUData* cpuData = &nhost->cpuData[cpu];
double total = cpuData->totalPeriod == 0 ? 1 : cpuData->totalPeriod;
double totalPercent;
double* v = this->values;
diff --git a/openbsd/OpenBSDMachine.c b/openbsd/OpenBSDMachine.c
new file mode 100644
index 00000000..e3e30990
--- /dev/null
+++ b/openbsd/OpenBSDMachine.c
@@ -0,0 +1,286 @@
+/*
+htop - OpenBSDMachine.c
+(C) 2014 Hisham H. Muhammad
+(C) 2015 Michael McConville
+Released under the GNU GPLv2+, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "openbsd/OpenBSDMachine.h"
+
+#include <kvm.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mount.h>
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/sched.h>
+#include <sys/swap.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <uvm/uvmexp.h>
+
+#include "CRT.h"
+#include "Macros.h"
+#include "Object.h"
+#include "Settings.h"
+#include "XUtils.h"
+
+
+static void OpenBSDMachine_updateCPUcount(OpenBSDMachine* this) {
+ Machine* super = &this->super;
+ const int nmib[] = { CTL_HW, HW_NCPU };
+ const int mib[] = { CTL_HW, HW_NCPUONLINE };
+ int r;
+ unsigned int value;
+ size_t size;
+ bool change = false;
+
+ size = sizeof(value);
+ r = sysctl(mib, 2, &value, &size, NULL, 0);
+ if (r < 0 || value < 1) {
+ value = 1;
+ }
+
+ if (value != super->activeCPUs) {
+ super->activeCPUs = value;
+ change = true;
+ }
+
+ size = sizeof(value);
+ r = sysctl(nmib, 2, &value, &size, NULL, 0);
+ if (r < 0 || value < 1) {
+ value = super->activeCPUs;
+ }
+
+ if (value != super->existingCPUs) {
+ this->cpuData = xReallocArray(this->cpuData, value + 1, sizeof(CPUData));
+ super->existingCPUs = value;
+ change = true;
+ }
+
+ if (change) {
+ CPUData* dAvg = &this->cpuData[0];
+ memset(dAvg, '\0', sizeof(CPUData));
+ dAvg->totalTime = 1;
+ dAvg->totalPeriod = 1;
+ dAvg->online = true;
+
+ for (unsigned int i = 0; i < super->existingCPUs; i++) {
+ CPUData* d = &this->cpuData[i + 1];
+ memset(d, '\0', sizeof(CPUData));
+ d->totalTime = 1;
+ d->totalPeriod = 1;
+
+ const int ncmib[] = { CTL_KERN, KERN_CPUSTATS, i };
+ struct cpustats cpu_stats;
+
+ size = sizeof(cpu_stats);
+ if (sysctl(ncmib, 3, &cpu_stats, &size, NULL, 0) < 0) {
+ CRT_fatalError("ncmib sysctl call failed");
+ }
+ d->online = (cpu_stats.cs_flags & CPUSTATS_ONLINE);
+ }
+ }
+}
+
+Machine* Machine_new(UsersTable* usersTable, uid_t userId) {
+ const int fmib[] = { CTL_KERN, KERN_FSCALE };
+ size_t size;
+ char errbuf[_POSIX2_LINE_MAX];
+
+ OpenBSDMachine* this = xCalloc(1, sizeof(OpenBSDMachine));
+ Machine* super = &this->super;
+
+ Machine_init(super, usersTable, userId);
+
+ OpenBSDProcessList_updateCPUcount(this);
+
+ size = sizeof(this->fscale);
+ if (sysctl(fmib, 2, &this->fscale, &size, NULL, 0) < 0) {
+ CRT_fatalError("fscale sysctl call failed");
+ }
+
+ if ((this->pageSize = sysconf(_SC_PAGESIZE)) == -1)
+ CRT_fatalError("pagesize sysconf call failed");
+ this->pageSizeKB = this->pageSize / ONE_K;
+
+ this->kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
+ if (this->kd == NULL) {
+ CRT_fatalError("kvm_openfiles() failed");
+ }
+
+ this->cpuSpeed = -1;
+
+ return this;
+}
+
+void Machine_delete(Machine* super) {
+ OpenBSDMachine* this = (OpenBSDMachine*) super;
+
+ if (this->kd) {
+ kvm_close(this->kd);
+ }
+ free(this->cpuData);
+ Machine_done(super);
+ free(this);
+}
+
+static void OpenBSDMachine_scanMemoryInfo(OpenBSDMachine* this) {
+ Machine* host = &this->super;
+ const int uvmexp_mib[] = { CTL_VM, VM_UVMEXP };
+ struct uvmexp uvmexp;
+ size_t size_uvmexp = sizeof(uvmexp);
+
+ if (sysctl(uvmexp_mib, 2, &uvmexp, &size_uvmexp, NULL, 0) < 0) {
+ CRT_fatalError("uvmexp sysctl call failed");
+ }
+
+ super->totalMem = uvmexp.npages * this->pageSizeKB;
+ super->usedMem = (uvmexp.npages - uvmexp.free - uvmexp.paging) * this->pageSizeKB;
+
+ // Taken from OpenBSD systat/iostat.c, top/machine.c and uvm_sysctl(9)
+ const int bcache_mib[] = { CTL_VFS, VFS_GENERIC, VFS_BCACHESTAT };
+ struct bcachestats bcstats;
+ size_t size_bcstats = sizeof(bcstats);
+
+ if (sysctl(bcache_mib, 3, &bcstats, &size_bcstats, NULL, 0) < 0) {
+ CRT_fatalError("cannot get vfs.bcachestat");
+ }
+
+ super->cachedMem = bcstats.numbufpages * this->pageSizeKB;
+
+ /*
+ * Copyright (c) 1994 Thorsten Lockert <tholo@sigmasoft.com>
+ * All rights reserved.
+ *
+ * Taken almost directly from OpenBSD's top(1)
+ *
+ * Originally released under a BSD-3 license
+ * Modified through htop developers applying GPL-2
+ */
+ int nswap = swapctl(SWAP_NSWAP, 0, 0);
+ if (nswap > 0) {
+ struct swapent swdev[nswap];
+ int rnswap = swapctl(SWAP_STATS, swdev, nswap);
+
+ /* Total things up */
+ unsigned long long int total = 0, used = 0;
+ for (int i = 0; i < rnswap; i++) {
+ if (swdev[i].se_flags & SWF_ENABLE) {
+ used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
+ total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
+ }
+ }
+
+ super->totalSwap = total;
+ super->usedSwap = used;
+ } else {
+ super->totalSwap = super->usedSwap = 0;
+ }
+}
+
+static void getKernelCPUTimes(unsigned int cpuId, u_int64_t* times) {
+ const int mib[] = { CTL_KERN, KERN_CPTIME2, cpuId };
+ size_t length = sizeof(*times) * CPUSTATES;
+ if (sysctl(mib, 3, times, &length, NULL, 0) == -1 || length != sizeof(*times) * CPUSTATES) {
+ CRT_fatalError("sysctl kern.cp_time2 failed");
+ }
+}
+
+static void kernelCPUTimesToHtop(const u_int64_t* times, CPUData* cpu) {
+ unsigned long long totalTime = 0;
+ for (int i = 0; i < CPUSTATES; i++) {
+ totalTime += times[i];
+ }
+
+ unsigned long long sysAllTime = times[CP_INTR] + times[CP_SYS];
+
+ // XXX Not sure if CP_SPIN should be added to sysAllTime.
+ // See https://github.com/openbsd/src/commit/531d8034253fb82282f0f353c086e9ad827e031c
+ #ifdef CP_SPIN
+ sysAllTime += times[CP_SPIN];
+ #endif
+
+ cpu->totalPeriod = saturatingSub(totalTime, cpu->totalTime);
+ cpu->userPeriod = saturatingSub(times[CP_USER], cpu->userTime);
+ cpu->nicePeriod = saturatingSub(times[CP_NICE], cpu->niceTime);
+ cpu->sysPeriod = saturatingSub(times[CP_SYS], cpu->sysTime);
+ cpu->sysAllPeriod = saturatingSub(sysAllTime, cpu->sysAllTime);
+ #ifdef CP_SPIN
+ cpu->spinPeriod = saturatingSub(times[CP_SPIN], cpu->spinTime);
+ #endif
+ cpu->intrPeriod = saturatingSub(times[CP_INTR], cpu->intrTime);
+ cpu->idlePeriod = saturatingSub(times[CP_IDLE], cpu->idleTime);
+
+ cpu->totalTime = totalTime;
+ cpu->userTime = times[CP_USER];
+ cpu->niceTime = times[CP_NICE];
+ cpu->sysTime = times[CP_SYS];
+ cpu->sysAllTime = sysAllTime;
+ #ifdef CP_SPIN
+ cpu->spinTime = times[CP_SPIN];
+ #endif
+ cpu->intrTime = times[CP_INTR];
+ cpu->idleTime = times[CP_IDLE];
+}
+
+static void OpenBSDMachine_scanCPUTime(OpenBSDMachine* this) {
+ Machine* host = &this->super;
+ u_int64_t kernelTimes[CPUSTATES] = {0};
+ u_int64_t avg[CPUSTATES] = {0};
+
+ for (unsigned int i = 0; i < super->existingCPUs; i++) {
+ CPUData* cpu = &this->cpuData[i + 1];
+
+ if (!cpu->online) {
+ continue;
+ }
+
+ getKernelCPUTimes(i, kernelTimes);
+ kernelCPUTimesToHtop(kernelTimes, cpu);
+
+ avg[CP_USER] += cpu->userTime;
+ avg[CP_NICE] += cpu->niceTime;
+ avg[CP_SYS] += cpu->sysTime;
+ #ifdef CP_SPIN
+ avg[CP_SPIN] += cpu->spinTime;
+ #endif
+ avg[CP_INTR] += cpu->intrTime;
+ avg[CP_IDLE] += cpu->idleTime;
+ }
+
+ for (int i = 0; i < CPUSTATES; i++) {
+ avg[i] /= super->activeCPUs;
+ }
+
+ kernelCPUTimesToHtop(avg, &this->cpuData[0]);
+
+ {
+ const int mib[] = { CTL_HW, HW_CPUSPEED };
+ int cpuSpeed;
+ size_t size = sizeof(cpuSpeed);
+ if (sysctl(mib, 2, &cpuSpeed, &size, NULL, 0) == -1) {
+ this->cpuSpeed = -1;
+ } else {
+ this->cpuSpeed = cpuSpeed;
+ }
+ }
+}
+
+void Machine_scan(Machine* super) {
+ OpenBSDMachine* this = (OpenBSDMachine*) super;
+
+ OpenBSDMachine_updateCPUcount(this);
+ OpenBSDMachine_scanMemoryInfo(this);
+ OpenBSDMachine_scanCPUTime(this);
+}
+
+bool Machine_isCPUonline(const Machine* super, unsigned int id) {
+ assert(id < super->existingCPUs);
+
+ const OpenBSDMachine* this = (const OpenBSDMachine*) super;
+ return this->cpuData[id + 1].online;
+}
diff --git a/openbsd/OpenBSDMachine.h b/openbsd/OpenBSDMachine.h
new file mode 100644
index 00000000..51d6a750
--- /dev/null
+++ b/openbsd/OpenBSDMachine.h
@@ -0,0 +1,53 @@
+#ifndef HEADER_OpenBSDMachine
+#define HEADER_OpenBSDMachine
+/*
+htop - OpenBSDMachine.h
+(C) 2014 Hisham H. Muhammad
+(C) 2015 Michael McConville
+Released under the GNU GPLv2+, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include <kvm.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+#include "Machine.h"
+
+
+typedef struct CPUData_ {
+ unsigned long long int totalTime;
+ unsigned long long int userTime;
+ unsigned long long int niceTime;
+ unsigned long long int sysTime;
+ unsigned long long int sysAllTime;
+ unsigned long long int spinTime;
+ unsigned long long int intrTime;
+ unsigned long long int idleTime;
+
+ unsigned long long int totalPeriod;
+ unsigned long long int userPeriod;
+ unsigned long long int nicePeriod;
+ unsigned long long int sysPeriod;
+ unsigned long long int sysAllPeriod;
+ unsigned long long int spinPeriod;
+ unsigned long long int intrPeriod;
+ unsigned long long int idlePeriod;
+
+ bool online;
+} CPUData;
+
+typedef struct OpenBSDMachine_ {
+ Machine super;
+ kvm_t* kd;
+
+ CPUData* cpuData;
+
+ long fscale;
+ int cpuSpeed;
+ int pageSize;
+ int pageSizeKB;
+
+} OpenBSDMachine;
+
+#endif
diff --git a/openbsd/OpenBSDProcessList.c b/openbsd/OpenBSDProcessList.c
index c83eb543..2d86a9d4 100644
--- a/openbsd/OpenBSDProcessList.c
+++ b/openbsd/OpenBSDProcessList.c
@@ -17,7 +17,6 @@ in the source distribution for its full text.
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/sched.h>
-#include <sys/swap.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <uvm/uvmexp.h>
@@ -29,169 +28,26 @@ in the source distribution for its full text.
#include "ProcessList.h"
#include "Settings.h"
#include "XUtils.h"
+#include "openbsd/OpenBSDMachine.h"
#include "openbsd/OpenBSDProcess.h"
-static long fscale;
-static int pageSize;
-static int pageSizeKB;
-
-static void OpenBSDProcessList_updateCPUcount(ProcessList* super) {
- OpenBSDProcessList* opl = (OpenBSDProcessList*) super;
- Machine* host = super->host;
- const int nmib[] = { CTL_HW, HW_NCPU };
- const int mib[] = { CTL_HW, HW_NCPUONLINE };
- int r;
- unsigned int value;
- size_t size;
- bool change = false;
-
- size = sizeof(value);
- r = sysctl(mib, 2, &value, &size, NULL, 0);
- if (r < 0 || value < 1) {
- value = 1;
- }
-
- if (value != host->activeCPUs) {
- host->activeCPUs = value;
- change = true;
- }
-
- size = sizeof(value);
- r = sysctl(nmib, 2, &value, &size, NULL, 0);
- if (r < 0 || value < 1) {
- value = host->activeCPUs;
- }
-
- if (value != host->existingCPUs) {
- opl->cpuData = xReallocArray(opl->cpuData, value + 1, sizeof(CPUData));
- host->existingCPUs = value;
- change = true;
- }
-
- if (change) {
- CPUData* dAvg = &opl->cpuData[0];
- memset(dAvg, '\0', sizeof(CPUData));
- dAvg->totalTime = 1;
- dAvg->totalPeriod = 1;
- dAvg->online = true;
-
- for (unsigned int i = 0; i < host->existingCPUs; i++) {
- CPUData* d = &opl->cpuData[i + 1];
- memset(d, '\0', sizeof(CPUData));
- d->totalTime = 1;
- d->totalPeriod = 1;
-
- const int ncmib[] = { CTL_KERN, KERN_CPUSTATS, i };
- struct cpustats cpu_stats;
-
- size = sizeof(cpu_stats);
- if (sysctl(ncmib, 3, &cpu_stats, &size, NULL, 0) < 0) {
- CRT_fatalError("ncmib sysctl call failed");
- }
- d->online = (cpu_stats.cs_flags & CPUSTATS_ONLINE);
- }
- }
-}
-
-
ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList) {
- const int fmib[] = { CTL_KERN, KERN_FSCALE };
- size_t size;
- char errbuf[_POSIX2_LINE_MAX];
-
- OpenBSDProcessList* opl = xCalloc(1, sizeof(OpenBSDProcessList));
- ProcessList* pl = (ProcessList*) opl;
- ProcessList_init(pl, Class(OpenBSDProcess), host, pidMatchList);
-
- OpenBSDProcessList_updateCPUcount(pl);
-
- size = sizeof(fscale);
- if (sysctl(fmib, 2, &fscale, &size, NULL, 0) < 0) {
- CRT_fatalError("fscale sysctl call failed");
- }
-
- if ((pageSize = sysconf(_SC_PAGESIZE)) == -1)
- CRT_fatalError("pagesize sysconf call failed");
- pageSizeKB = pageSize / ONE_K;
+ OpenBSDProcessList* this = xCalloc(1, sizeof(OpenBSDProcessList));
+ ProcessList* super = (ProcessList*) this;
- opl->kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
- if (opl->kd == NULL) {
- CRT_fatalError("kvm_openfiles() failed");
- }
-
- opl->cpuSpeed = -1;
+ ProcessList_init(super, Class(OpenBSDProcess), host, pidMatchList);
- return pl;
+ return this;
}
-void ProcessList_delete(ProcessList* this) {
- OpenBSDProcessList* opl = (OpenBSDProcessList*) this;
-
- if (opl->kd) {
- kvm_close(opl->kd);
- }
-
- free(opl->cpuData);
+void ProcessList_delete(ProcessList* super) {
+ OpenBSDProcessList* this = (OpenBSDProcessList*) super;
- ProcessList_done(this);
+ ProcessList_done(super);
free(this);
}
-static void OpenBSDProcessList_scanMemoryInfo(ProcessList* pl) {
- Machine* host = pl->host;
- const int uvmexp_mib[] = { CTL_VM, VM_UVMEXP };
- struct uvmexp uvmexp;
- size_t size_uvmexp = sizeof(uvmexp);
-
- if (sysctl(uvmexp_mib, 2, &uvmexp, &size_uvmexp, NULL, 0) < 0) {
- CRT_fatalError("uvmexp sysctl call failed");
- }
-
- host->totalMem = uvmexp.npages * pageSizeKB;
- host->usedMem = (uvmexp.npages - uvmexp.free - uvmexp.paging) * pageSizeKB;
-
- // Taken from OpenBSD systat/iostat.c, top/machine.c and uvm_sysctl(9)
- const int bcache_mib[] = { CTL_VFS, VFS_GENERIC, VFS_BCACHESTAT };
- struct bcachestats bcstats;
- size_t size_bcstats = sizeof(bcstats);
-
- if (sysctl(bcache_mib, 3, &bcstats, &size_bcstats, NULL, 0) < 0) {
- CRT_fatalError("cannot get vfs.bcachestat");
- }
-
- host->cachedMem = bcstats.numbufpages * pageSizeKB;
-
- /*
- * Copyright (c) 1994 Thorsten Lockert <tholo@sigmasoft.com>
- * All rights reserved.
- *
- * Taken almost directly from OpenBSD's top(1)
- *
- * Originally released under a BSD-3 license
- * Modified through htop developers applying GPL-2
- */
- int nswap = swapctl(SWAP_NSWAP, 0, 0);
- if (nswap > 0) {
- struct swapent swdev[nswap];
- int rnswap = swapctl(SWAP_STATS, swdev, nswap);
-
- /* Total things up */
- unsigned long long int total = 0, used = 0;
- for (int i = 0; i < rnswap; i++) {
- if (swdev[i].se_flags & SWF_ENABLE) {
- used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
- total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
- }
- }
-
- host->totalSwap = total;
- host->usedSwap = used;
- } else {
- host->totalSwap = host->usedSwap = 0;
- }
-}
-
static void OpenBSDProcessList_updateCwd(const struct kinfo_proc* kproc, Process* proc) {
const int mib[] = { CTL_KERN, KERN_PROC_CWD, kproc->p_pid };
char buffer[2048];
@@ -264,21 +120,22 @@ static void OpenBSDProcessList_updateProcessName(kvm_t* kd, const struct kinfo_p
/*
* Taken from OpenBSD's ps(1).
*/
-static double getpcpu(const struct kinfo_proc* kp) {
- if (fscale == 0)
+static double getpcpu(const OpenBSDMachine* ohost, const struct kinfo_proc* kp) {
+ if (ohost->fscale == 0)
return 0.0;
- return 100.0 * (double)kp->p_pctcpu / fscale;
+ return 100.0 * (double)kp->p_pctcpu / ohost->fscale;
}
static void OpenBSDProcessList_scanProcs(OpenBSDProcessList* this) {
Machine* host = this->super.host;
+ OpenBSDMachine* ohost = (OpenBSDMachine*) host;
const Settings* settings = host->settings;
const bool hideKernelThreads = settings->hideKernelThreads;
const bool hideUserlandThreads = settings->hideUserlandThreads;
int count = 0;
- const struct kinfo_proc* kprocs = kvm_getprocs(this->kd, KERN_PROC_KTHREAD | KERN_PROC_SHOW_THREADS, 0, sizeof(struct kinfo_proc), &count);
+ const struct kinfo_proc* kprocs = kvm_getprocs(ohost->kd, KERN_PROC_KTHREAD | KERN_PROC_SHOW_THREADS, 0, sizeof(struct kinfo_proc), &count);
for (int i = 0; i < count; i++) {
const struct kinfo_proc* kproc = &kprocs[i];
@@ -310,7 +167,7 @@ static void OpenBSDProcessList_scanProcs(OpenBSDProcessList* this) {
Process_fillStarttimeBuffer(proc);
ProcessList_add(&this->super, proc);
- OpenBSDProcessList_updateProcessName(this->kd, kproc, proc);
+ OpenBSDProcessList_updateProcessName(ohost->kd, kproc, proc);
if (settings->ss->flags & PROCESS_FLAG_CWD) {
OpenBSDProcessList_updateCwd(kproc, proc);
@@ -326,16 +183,16 @@ static void OpenBSDProcessList_scanProcs(OpenBSDProcessList* this) {
}
} else {
if (settings->updateProcessNames) {
- OpenBSDProcessList_updateProcessName(this->kd, kproc, proc);
+ OpenBSDProcessList_updateProcessName(ohost->kd, kproc, proc);
}
}
fp->addr = kproc->p_addr;
- proc->m_virt = kproc->p_vm_dsize * pageSizeKB;
- proc->m_resident = kproc->p_vm_rssize * pageSizeKB;
+ proc->m_virt = kproc->p_vm_dsize * ohost->pageSizeKB;
+ proc->m_resident = kproc->p_vm_rssize * ohost->pageSizeKB;
proc->percent_mem = proc->m_resident / (float)host->totalMem * 100.0F;
- proc->percent_cpu = CLAMP(getpcpu(kproc), 0.0F, host->activeCPUs * 100.0F);
+ proc->percent_cpu = CLAMP(getpcpu(ohost, kproc), 0.0F, host->activeCPUs * 100.0F);
Process_updateCPUFieldWidths(proc->percent_cpu);
proc->nice = kproc->p_nice - 20;
@@ -379,122 +236,8 @@ static void OpenBSDProcessList_scanProcs(OpenBSDProcessList* this) {
}
}
-static void getKernelCPUTimes(unsigned int cpuId, u_int64_t* times) {
- const int mib[] = { CTL_KERN, KERN_CPTIME2, cpuId };
- size_t length = sizeof(*times) * CPUSTATES;
- if (sysctl(mib, 3, times, &length, NULL, 0) == -1 || length != sizeof(*times) * CPUSTATES) {
- CRT_fatalError("sysctl kern.cp_time2 failed");
- }
-}
-
-static void kernelCPUTimesToHtop(const u_int64_t* times, CPUData* cpu) {
- unsigned long long totalTime = 0;
- for (int i = 0; i < CPUSTATES; i++) {
- totalTime += times[i];
- }
-
- unsigned long long sysAllTime = times[CP_INTR] + times[CP_SYS];
-
- // XXX Not sure if CP_SPIN should be added to sysAllTime.
- // See https://github.com/openbsd/src/commit/531d8034253fb82282f0f353c086e9ad827e031c
- #ifdef CP_SPIN
- sysAllTime += times[CP_SPIN];
- #endif
-
- cpu->totalPeriod = saturatingSub(totalTime, cpu->totalTime);
- cpu->userPeriod = saturatingSub(times[CP_USER], cpu->userTime);
- cpu->nicePeriod = saturatingSub(times[CP_NICE], cpu->niceTime);
- cpu->sysPeriod = saturatingSub(times[CP_SYS], cpu->sysTime);
- cpu->sysAllPeriod = saturatingSub(sysAllTime, cpu->sysAllTime);
- #ifdef CP_SPIN
- cpu->spinPeriod = saturatingSub(times[CP_SPIN], cpu->spinTime);
- #endif
- cpu->intrPeriod = saturatingSub(times[CP_INTR], cpu->intrTime);
- cpu->idlePeriod = saturatingSub(times[CP_IDLE], cpu->idleTime);
-
- cpu->totalTime = totalTime;
- cpu->userTime = times[CP_USER];
- cpu->niceTime = times[CP_NICE];
- cpu->sysTime = times[CP_SYS];
- cpu->sysAllTime = sysAllTime;
- #ifdef CP_SPIN
- cpu->spinTime = times[CP_SPIN];
- #endif
- cpu->intrTime = times[CP_INTR];
- cpu->idleTime = times[CP_IDLE];
-}
-
-static void OpenBSDProcessList_scanCPUTime(OpenBSDProcessList* this) {
- Machine* host = this->super.host;
- u_int64_t kernelTimes[CPUSTATES] = {0};
- u_int64_t avg[CPUSTATES] = {0};
-
- for (unsigned int i = 0; i < host->existingCPUs; i++) {
- CPUData* cpu = &this->cpuData[i + 1];
-
- if (!cpu->online) {
- continue;
- }
-
- getKernelCPUTimes(i, kernelTimes);
- kernelCPUTimesToHtop(kernelTimes, cpu);
-
- avg[CP_USER] += cpu->userTime;
- avg[CP_NICE] += cpu->niceTime;
- avg[CP_SYS] += cpu->sysTime;
- #ifdef CP_SPIN
- avg[CP_SPIN] += cpu->spinTime;
- #endif
- avg[CP_INTR] += cpu->intrTime;
- avg[CP_IDLE] += cpu->idleTime;
- }
-
- for (int i = 0; i < CPUSTATES; i++) {
- avg[i] /= host->activeCPUs;
- }
-
- kernelCPUTimesToHtop(avg, &this->cpuData[0]);
-
- {
- const int mib[] = { CTL_HW, HW_CPUSPEED };
- int cpuSpeed;
- size_t size = sizeof(cpuSpeed);
- if (sysctl(mib, 2, &cpuSpeed, &size, NULL, 0) == -1) {
- this->cpuSpeed = -1;
- } else {
- this->cpuSpeed = cpuSpeed;
- }
- }
-}
-
-void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
- OpenBSDProcessList* opl = (OpenBSDProcessList*) super;
-
- OpenBSDProcessList_updateCPUcount(super);
- OpenBSDProcessList_scanMemoryInfo(super);
- OpenBSDProcessList_scanCPUTime(opl);
-
- // in pause mode only gather global data for meters (CPU/memory/...)
- if (pauseProcessUpdate) {
- return;
- }
-
- OpenBSDProcessList_scanProcs(opl);
-}
-
-Machine* Machine_new(UsersTable* usersTable, uid_t userId) {
- Machine* this = xCalloc(1, sizeof(Machine));
- Machine_init(this, usersTable, userId);
- return this;
-}
-
-void Machine_delete(Machine* host) {
- free(host);
-}
-
-bool Machine_isCPUonline(const Machine* host, unsigned int id) {
- assert(id < host->existingCPUs);
+void ProcessList_goThroughEntries(ProcessList* super) {
+ OpenBSDProcessList* this = (OpenBSDProcessList*) super;
- const OpenBSDProcessList* opl = (const OpenBSDProcessList*) host->pl;
- return opl->cpuData[id + 1].online;
+ OpenBSDProcessList_scanProcs(this);
}
diff --git a/openbsd/OpenBSDProcessList.h b/openbsd/OpenBSDProcessList.h
index 6ca2ba2c..8a03fecb 100644
--- a/openbsd/OpenBSDProcessList.h
+++ b/openbsd/OpenBSDProcessList.h
@@ -8,57 +8,14 @@ Released under the GNU GPLv2+, see the COPYING file
in the source distribution for its full text.
*/
-#include <kvm.h>
#include <stdbool.h>
#include <sys/types.h>
-#include "Hashtable.h"
#include "ProcessList.h"
-#include "UsersTable.h"
-typedef struct CPUData_ {
- unsigned long long int totalTime;
- unsigned long long int userTime;
- unsigned long long int niceTime;
- unsigned long long int sysTime;
- unsigned long long int sysAllTime;
- unsigned long long int spinTime;
- unsigned long long int intrTime;
- unsigned long long int idleTime;
-
- unsigned long long int totalPeriod;
- unsigned long long int userPeriod;
- unsigned long long int nicePeriod;
- unsigned long long int sysPeriod;
- unsigned long long int sysAllPeriod;
- unsigned long long int spinPeriod;
- unsigned long long int intrPeriod;
- unsigned long long int idlePeriod;
-
- bool online;
-} CPUData;
-
typedef struct OpenBSDProcessList_ {
ProcessList super;
- kvm_t* kd;
-
- CPUData* cpuData;
- int cpuSpeed;
-
} OpenBSDProcessList;
-
-ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList);
-
-void ProcessList_delete(ProcessList* this);
-
-void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
-
-Machine* Machine_new(UsersTable* usersTable, uid_t userId);
-
-bool Machine_isCPUonline(const Machine* host, unsigned int id);
-
-void Machine_delete(Machine* host);
-
#endif
diff --git a/openbsd/Platform.c b/openbsd/Platform.c
index 03c36856..94e71928 100644
--- a/openbsd/Platform.c
+++ b/openbsd/Platform.c
@@ -35,7 +35,6 @@ in the source distribution for its full text.
#include "MemoryMeter.h"
#include "MemorySwapMeter.h"
#include "Meter.h"
-#include "ProcessList.h"
#include "Settings.h"
#include "SignalsPanel.h"
#include "SwapMeter.h"
@@ -43,8 +42,8 @@ in the source distribution for its full text.
#include "TasksMeter.h"
#include "UptimeMeter.h"
#include "XUtils.h"
+#include "openbsd/OpenBSDMachine.h"
#include "openbsd/OpenBSDProcess.h"
-#include "openbsd/OpenBSDProcessList.h"
const ScreenDefaults Platform_defaultScreens[] = {
@@ -182,8 +181,8 @@ int Platform_getMaxPid(void) {
double Platform_setCPUValues(Meter* this, unsigned int cpu) {
const Machine* host = this->host;
- const OpenBSDProcessList* pl = (const OpenBSDProcessList*) host->pl;
- const CPUData* cpuData = &(pl->cpuData[cpu]);
+ const OpenBSDMachine* ohost = (const OpenBSDMachine*) host;
+ const CPUData* cpuData = &(ohost->cpuData[cpu]);
double total;
double totalPercent;
double* v = this->values;
@@ -217,7 +216,7 @@ double Platform_setCPUValues(Meter* this, unsigned int cpu) {
v[CPU_METER_TEMPERATURE] = NAN;
- v[CPU_METER_FREQUENCY] = (pl->cpuSpeed != -1) ? pl->cpuSpeed : NAN;
+ v[CPU_METER_FREQUENCY] = (ohost->cpuSpeed != -1) ? ohost->cpuSpeed : NAN;
return totalPercent;
}
diff --git a/pcp/PCPMachine.c b/pcp/PCPMachine.c
new file mode 100644
index 00000000..59e05624
--- /dev/null
+++ b/pcp/PCPMachine.c
@@ -0,0 +1,332 @@
+/*
+htop - PCPProcessList.c
+(C) 2014 Hisham H. Muhammad
+(C) 2020-2023 htop dev team
+(C) 2020-2023 Red Hat, Inc.
+Released under the GNU GPLv2+, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "config.h" // IWYU pragma: keep
+
+#include "pcp/PCPMachine.h"
+
+#include <assert.h>
+#include <limits.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include "Macros.h"
+#include "Machine.h"
+#include "Object.h"
+#include "Platform.h"
+#include "Settings.h"
+#include "XUtils.h"
+
+#include "pcp/PCPMetric.h"
+#include "pcp/PCPProcess.h"
+
+
+static void PCPMachine_updateCPUcount(PCPMachine* this) {
+ Machine* super = &this->super;
+ super->activeCPUs = PCPMetric_instanceCount(PCP_PERCPU_SYSTEM);
+ unsigned int cpus = Platform_getMaxCPU();
+ if (cpus == super->existingCPUs)
+ return;
+ if (cpus == 0)
+ cpus = super->activeCPUs;
+ if (cpus <= 1)
+ cpus = super->activeCPUs = 1;
+ super->existingCPUs = cpus;
+
+ free(this->percpu);
+ free(this->values);
+
+ this->percpu = xCalloc(cpus, sizeof(pmAtomValue*));
+ for (unsigned int i = 0; i < cpus; i++)
+ this->percpu[i] = xCalloc(CPU_METRIC_COUNT, sizeof(pmAtomValue));
+ this->values = xCalloc(cpus, sizeof(pmAtomValue));
+}
+
+static void PCPMachine_updateMemoryInfo(Machine* host) {
+ unsigned long long int freeMem = 0;
+ unsigned long long int swapFreeMem = 0;
+ unsigned long long int sreclaimableMem = 0;
+ host->totalMem = host->usedMem = host->cachedMem = 0;
+ host->usedSwap = host->totalSwap = host->sharedMem = 0;
+
+ pmAtomValue value;
+ if (PCPMetric_values(PCP_MEM_TOTAL, &value, 1, PM_TYPE_U64) != NULL)
+ host->totalMem = value.ull;
+ if (PCPMetric_values(PCP_MEM_FREE, &value, 1, PM_TYPE_U64) != NULL)
+ freeMem = value.ull;
+ if (PCPMetric_values(PCP_MEM_BUFFERS, &value, 1, PM_TYPE_U64) != NULL)
+ host->buffersMem = value.ull;
+ if (PCPMetric_values(PCP_MEM_SRECLAIM, &value, 1, PM_TYPE_U64) != NULL)
+ sreclaimableMem = value.ull;
+ if (PCPMetric_values(PCP_MEM_SHARED, &value, 1, PM_TYPE_U64) != NULL)
+ host->sharedMem = value.ull;
+ if (PCPMetric_values(PCP_MEM_CACHED, &value, 1, PM_TYPE_U64) != NULL)
+ host->cachedMem = value.ull + sreclaimableMem - host->sharedMem;
+ const memory_t usedDiff = freeMem + host->cachedMem + sreclaimableMem + host->buffersMem;
+ host->usedMem = (host->totalMem >= usedDiff) ?
+ host->totalMem - usedDiff : host->totalMem - freeMem;
+ if (PCPMetric_values(PCP_MEM_AVAILABLE, &value, 1, PM_TYPE_U64) != NULL)
+ host->availableMem = MINIMUM(value.ull, host->totalMem);
+ else
+ host->availableMem = freeMem;
+ if (PCPMetric_values(PCP_MEM_SWAPFREE, &value, 1, PM_TYPE_U64) != NULL)
+ swapFreeMem = value.ull;
+ if (PCPMetric_values(PCP_MEM_SWAPTOTAL, &value, 1, PM_TYPE_U64) != NULL)
+ host->totalSwap = value.ull;
+ if (PCPMetric_values(PCP_MEM_SWAPCACHED, &value, 1, PM_TYPE_U64) != NULL)
+ host->cachedSwap = value.ull;
+ host->usedSwap = host->totalSwap - swapFreeMem - host->cachedSwap;
+}
+
+/* make copies of previously sampled values to avoid overwrite */
+static inline void PCPMachine_backupCPUTime(pmAtomValue* values) {
+ /* the PERIOD fields (must) mirror the TIME fields */
+ for (int metric = CPU_TOTAL_TIME; metric < CPU_TOTAL_PERIOD; metric++) {
+ values[metric + CPU_TOTAL_PERIOD] = values[metric];
+ }
+}
+
+static inline void PCPMachine_saveCPUTimePeriod(pmAtomValue* values, CPUMetric previous, pmAtomValue* latest) {
+ pmAtomValue* value;
+
+ /* new value for period */
+ value = &values[previous];
+ if (latest->ull > value->ull)
+ value->ull = latest->ull - value->ull;
+ else
+ value->ull = 0;
+
+ /* new value for time */
+ value = &values[previous - CPU_TOTAL_PERIOD];
+ value->ull = latest->ull;
+}
+
+/* using copied sampled values and new values, calculate derivations */
+static void PCPMachine_deriveCPUTime(pmAtomValue* values) {
+
+ pmAtomValue* usertime = &values[CPU_USER_TIME];
+ pmAtomValue* guesttime = &values[CPU_GUEST_TIME];
+ usertime->ull -= guesttime->ull;
+
+ pmAtomValue* nicetime = &values[CPU_NICE_TIME];
+ pmAtomValue* guestnicetime = &values[CPU_GUESTNICE_TIME];
+ nicetime->ull -= guestnicetime->ull;
+
+ pmAtomValue* idletime = &values[CPU_IDLE_TIME];
+ pmAtomValue* iowaittime = &values[CPU_IOWAIT_TIME];
+ pmAtomValue* idlealltime = &values[CPU_IDLE_ALL_TIME];
+ idlealltime->ull = idletime->ull + iowaittime->ull;
+
+ pmAtomValue* systemtime = &values[CPU_SYSTEM_TIME];
+ pmAtomValue* irqtime = &values[CPU_IRQ_TIME];
+ pmAtomValue* softirqtime = &values[CPU_SOFTIRQ_TIME];
+ pmAtomValue* systalltime = &values[CPU_SYSTEM_ALL_TIME];
+ systalltime->ull = systemtime->ull + irqtime->ull + softirqtime->ull;
+
+ pmAtomValue* virtalltime = &values[CPU_GUEST_TIME];
+ virtalltime->ull = guesttime->ull + guestnicetime->ull;
+
+ pmAtomValue* stealtime = &values[CPU_STEAL_TIME];
+ pmAtomValue* totaltime = &values[CPU_TOTAL_TIME];
+ totaltime->ull = usertime->ull + nicetime->ull + systalltime->ull +
+ idlealltime->ull + stealtime->ull + virtalltime->ull;
+
+ PCPMachine_saveCPUTimePeriod(values, CPU_USER_PERIOD, usertime);
+ PCPMachine_saveCPUTimePeriod(values, CPU_NICE_PERIOD, nicetime);
+ PCPMachine_saveCPUTimePeriod(values, CPU_SYSTEM_PERIOD, systemtime);
+ PCPMachine_saveCPUTimePeriod(values, CPU_SYSTEM_ALL_PERIOD, systalltime);
+ PCPMachine_saveCPUTimePeriod(values, CPU_IDLE_ALL_PERIOD, idlealltime);
+ PCPMachine_saveCPUTimePeriod(values, CPU_IDLE_PERIOD, idletime);
+ PCPMachine_saveCPUTimePeriod(values, CPU_IOWAIT_PERIOD, iowaittime);
+ PCPMachine_saveCPUTimePeriod(values, CPU_IRQ_PERIOD, irqtime);
+ PCPMachine_saveCPUTimePeriod(values, CPU_SOFTIRQ_PERIOD, softirqtime);
+ PCPMachine_saveCPUTimePeriod(values, CPU_STEAL_PERIOD, stealtime);
+ PCPMachine_saveCPUTimePeriod(values, CPU_GUEST_PERIOD, virtalltime);
+ PCPMachine_saveCPUTimePeriod(values, CPU_TOTAL_PERIOD, totaltime);
+}
+
+static void PCPMachine_updateAllCPUTime(PCPMachine* this, PCPMetric metric, CPUMetric cpumetric)
+{
+ pmAtomValue* value = &this->cpu[cpumetric];
+ if (PCPMetric_values(metric, value, 1, PM_TYPE_U64) == NULL)
+ memset(value, 0, sizeof(pmAtomValue));
+}
+
+static void PCPMachine_updatePerCPUTime(PCPMachine* this, PCPMetric metric, CPUMetric cpumetric)
+{
+ int cpus = this->super.existingCPUs;
+ if (PCPMetric_values(metric, this->values, cpus, PM_TYPE_U64) == NULL)
+ memset(this->values, 0, cpus * sizeof(pmAtomValue));
+ for (int i = 0; i < cpus; i++)
+ this->percpu[i][cpumetric].ull = this->values[i].ull;
+}
+
+static void PCPMachine_updatePerCPUReal(PCPMachine* this, PCPMetric metric, CPUMetric cpumetric)
+{
+ int cpus = this->super.existingCPUs;
+ if (PCPMetric_values(metric, this->values, cpus, PM_TYPE_DOUBLE) == NULL)
+ memset(this->values, 0, cpus * sizeof(pmAtomValue));
+ for (int i = 0; i < cpus; i++)
+ this->percpu[i][cpumetric].d = this->values[i].d;
+}
+
+static inline void PCPMachine_scanZfsArcstats(PCPMachine* this) {
+ unsigned long long int dbufSize = 0;
+ unsigned long long int dnodeSize = 0;
+ unsigned long long int bonusSize = 0;
+ pmAtomValue value;
+
+ memset(&this->zfs, 0, sizeof(ZfsArcStats));
+ if (PCPMetric_values(PCP_ZFS_ARC_ANON_SIZE, &value, 1, PM_TYPE_U64))
+ this->zfs.anon = value.ull / ONE_K;
+ if (PCPMetric_values(PCP_ZFS_ARC_C_MIN, &value, 1, PM_TYPE_U64))
+ this->zfs.min = value.ull / ONE_K;
+ if (PCPMetric_values(PCP_ZFS_ARC_C_MAX, &value, 1, PM_TYPE_U64))
+ this->zfs.max = value.ull / ONE_K;
+ if (PCPMetric_values(PCP_ZFS_ARC_BONUS_SIZE, &value, 1, PM_TYPE_U64))
+ bonusSize = value.ull / ONE_K;
+ if (PCPMetric_values(PCP_ZFS_ARC_DBUF_SIZE, &value, 1, PM_TYPE_U64))
+ dbufSize = value.ull / ONE_K;
+ if (PCPMetric_values(PCP_ZFS_ARC_DNODE_SIZE, &value, 1, PM_TYPE_U64))
+ dnodeSize = value.ull / ONE_K;
+ if (PCPMetric_values(PCP_ZFS_ARC_COMPRESSED_SIZE, &value, 1, PM_TYPE_U64))
+ this->zfs.compressed = value.ull / ONE_K;
+ if (PCPMetric_values(PCP_ZFS_ARC_UNCOMPRESSED_SIZE, &value, 1, PM_TYPE_U64))
+ this->zfs.uncompressed = value.ull / ONE_K;
+ if (PCPMetric_values(PCP_ZFS_ARC_HDR_SIZE, &value, 1, PM_TYPE_U64))
+ this->zfs.header = value.ull / ONE_K;
+ if (PCPMetric_values(PCP_ZFS_ARC_MFU_SIZE, &value, 1, PM_TYPE_U64))
+ this->zfs.MFU = value.ull / ONE_K;
+ if (PCPMetric_values(PCP_ZFS_ARC_MRU_SIZE, &value, 1, PM_TYPE_U64))
+ this->zfs.MRU = value.ull / ONE_K;
+ if (PCPMetric_values(PCP_ZFS_ARC_SIZE, &value, 1, PM_TYPE_U64))
+ this->zfs.size = value.ull / ONE_K;
+
+ this->zfs.other = (dbufSize + dnodeSize + bonusSize) / ONE_K;
+ this->zfs.enabled = (this->zfs.size > 0);
+ this->zfs.isCompressed = (this->zfs.compressed > 0);
+}
+
+static void PCPMachine_scan(PCPMachine* this) {
+ Machine* super = &this->super;
+
+ PCPMachine_updateMemoryInfo(super);
+ PCPMachine_updateCPUcount(this);
+
+ PCPMachine_backupCPUTime(this->cpu);
+ PCPMachine_updateAllCPUTime(this, PCP_CPU_USER, CPU_USER_TIME);
+ PCPMachine_updateAllCPUTime(this, PCP_CPU_NICE, CPU_NICE_TIME);
+ PCPMachine_updateAllCPUTime(this, PCP_CPU_SYSTEM, CPU_SYSTEM_TIME);
+ PCPMachine_updateAllCPUTime(this, PCP_CPU_IDLE, CPU_IDLE_TIME);
+ PCPMachine_updateAllCPUTime(this, PCP_CPU_IOWAIT, CPU_IOWAIT_TIME);
+ PCPMachine_updateAllCPUTime(this, PCP_CPU_IRQ, CPU_IRQ_TIME);
+ PCPMachine_updateAllCPUTime(this, PCP_CPU_SOFTIRQ, CPU_SOFTIRQ_TIME);
+ PCPMachine_updateAllCPUTime(this, PCP_CPU_STEAL, CPU_STEAL_TIME);
+ PCPMachine_updateAllCPUTime(this, PCP_CPU_GUEST, CPU_GUEST_TIME);
+ PCPMachine_deriveCPUTime(this->cpu);
+
+ for (unsigned int i = 0; i < super->existingCPUs; i++)
+ PCPMachine_backupCPUTime(this->percpu[i]);
+ PCPMachine_updatePerCPUTime(this, PCP_PERCPU_USER, CPU_USER_TIME);
+ PCPMachine_updatePerCPUTime(this, PCP_PERCPU_NICE, CPU_NICE_TIME);
+ PCPMachine_updatePerCPUTime(this, PCP_PERCPU_SYSTEM, CPU_SYSTEM_TIME);
+ PCPMachine_updatePerCPUTime(this, PCP_PERCPU_IDLE, CPU_IDLE_TIME);
+ PCPMachine_updatePerCPUTime(this, PCP_PERCPU_IOWAIT, CPU_IOWAIT_TIME);
+ PCPMachine_updatePerCPUTime(this, PCP_PERCPU_IRQ, CPU_IRQ_TIME);
+ PCPMachine_updatePerCPUTime(this, PCP_PERCPU_SOFTIRQ, CPU_SOFTIRQ_TIME);
+ PCPMachine_updatePerCPUTime(this, PCP_PERCPU_STEAL, CPU_STEAL_TIME);
+ PCPMachine_updatePerCPUTime(this, PCP_PERCPU_GUEST, CPU_GUEST_TIME);
+ for (unsigned int i = 0; i < super->existingCPUs; i++)
+ PCPMachine_deriveCPUTime(this->percpu[i]);
+
+ if (super->settings->showCPUFrequency)
+ PCPMachine_updatePerCPUReal(this, PCP_HINV_CPUCLOCK, CPU_FREQUENCY);
+
+ PCPMachine_scanZfsArcstats(this);
+}
+
+void Machine_scan(Machine* super) {
+ PCPMachine* host = (PCPMachine*) super;
+ const Settings* settings = super->settings;
+ uint32_t flags = settings->ss->flags;
+ bool flagged;
+
+ for (int metric = PCP_PROC_PID; metric < PCP_METRIC_COUNT; metric++)
+ PCPMetric_enable(metric, true);
+
+ flagged = settings->showCPUFrequency;
+ PCPMetric_enable(PCP_HINV_CPUCLOCK, flagged);
+ flagged = flags & PROCESS_FLAG_LINUX_CGROUP;
+ PCPMetric_enable(PCP_PROC_CGROUPS, flagged);
+ flagged = flags & PROCESS_FLAG_LINUX_OOM;
+ PCPMetric_enable(PCP_PROC_OOMSCORE, flagged);
+ flagged = flags & PROCESS_FLAG_LINUX_CTXT;
+ PCPMetric_enable(PCP_PROC_VCTXSW, flagged);
+ PCPMetric_enable(PCP_PROC_NVCTXSW, flagged);
+ flagged = flags & PROCESS_FLAG_LINUX_SECATTR;
+ PCPMetric_enable(PCP_PROC_LABELS, flagged);
+ flagged = flags & PROCESS_FLAG_LINUX_AUTOGROUP;
+ PCPMetric_enable(PCP_PROC_AUTOGROUP_ID, flagged);
+ PCPMetric_enable(PCP_PROC_AUTOGROUP_NICE, flagged);
+
+ /* Sample smaps metrics on every second pass to improve performance */
+ host->smaps_flag = !!host->smaps_flag;
+ PCPMetric_enable(PCP_PROC_SMAPS_PSS, host->smaps_flag);
+ PCPMetric_enable(PCP_PROC_SMAPS_SWAP, host->smaps_flag);
+ PCPMetric_enable(PCP_PROC_SMAPS_SWAPPSS, host->smaps_flag);
+
+ struct timeval timestamp;
+ if (PCPMetric_fetch(&timestamp) != true)
+ return;
+
+ double sample = host->timestamp;
+ host->timestamp = pmtimevalToReal(&timestamp);
+ host->period = (host->timestamp - sample) * 100;
+
+ PCPMachine_scan(host);
+}
+
+Machine* Machine_new(UsersTable* usersTable, uid_t userId) {
+ PCPMachine* this = xCalloc(1, sizeof(PCPMachine));
+ Machine* super = &this->super;
+
+ Machine_init(super, usersTable, userId);
+
+ struct timeval timestamp;
+ gettimeofday(&timestamp, NULL);
+ this->timestamp = pmtimevalToReal(&timestamp);
+
+ this->cpu = xCalloc(CPU_METRIC_COUNT, sizeof(pmAtomValue));
+ PCPMachine_updateCPUcount(this);
+
+ return super;
+}
+
+void Machine_delete(Machine* super) {
+ PCPMachine* this = (PCPMachine*) super;
+ Machine_done(super);
+ free(this->values);
+ for (unsigned int i = 0; i < super->existingCPUs; i++)
+ free(this->percpu[i]);
+ free(this->percpu);
+ free(this->cpu);
+ free(this);
+}
+
+bool Machine_isCPUonline(const Machine* host, unsigned int id) {
+ assert(id < host->existingCPUs);
+ (void) host;
+
+ pmAtomValue value;
+ if (PCPMetric_instance(PCP_PERCPU_SYSTEM, id, id, &value, PM_TYPE_U32))
+ return true;
+ return false;
+}
diff --git a/pcp/PCPMachine.h b/pcp/PCPMachine.h
new file mode 100644
index 00000000..faca8efc
--- /dev/null
+++ b/pcp/PCPMachine.h
@@ -0,0 +1,68 @@
+#ifndef HEADER_PCPMachine
+#define HEADER_PCPMachine
+/*
+htop - PCPMachine.h
+(C) 2014 Hisham H. Muhammad
+Released under the GNU GPLv2+, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "config.h" // IWYU pragma: keep
+
+#include <stdbool.h>
+#include <sys/types.h>
+
+#include "Hashtable.h"
+#include "Machine.h"
+#include "UsersTable.h"
+
+#include "pcp/Platform.h"
+#include "zfs/ZfsArcStats.h"
+
+
+typedef enum CPUMetric_ {
+ CPU_TOTAL_TIME,
+ CPU_USER_TIME,
+ CPU_SYSTEM_TIME,
+ CPU_SYSTEM_ALL_TIME,
+ CPU_IDLE_ALL_TIME,
+ CPU_IDLE_TIME,
+ CPU_NICE_TIME,
+ CPU_IOWAIT_TIME,
+ CPU_IRQ_TIME,
+ CPU_SOFTIRQ_TIME,
+ CPU_STEAL_TIME,
+ CPU_GUEST_TIME,
+ CPU_GUESTNICE_TIME,
+
+ CPU_TOTAL_PERIOD,
+ CPU_USER_PERIOD,
+ CPU_SYSTEM_PERIOD,
+ CPU_SYSTEM_ALL_PERIOD,
+ CPU_IDLE_ALL_PERIOD,
+ CPU_IDLE_PERIOD,
+ CPU_NICE_PERIOD,
+ CPU_IOWAIT_PERIOD,
+ CPU_IRQ_PERIOD,
+ CPU_SOFTIRQ_PERIOD,
+ CPU_STEAL_PERIOD,
+ CPU_GUEST_PERIOD,
+ CPU_GUESTNICE_PERIOD,
+
+ CPU_FREQUENCY,
+
+ CPU_METRIC_COUNT
+} CPUMetric;
+
+typedef struct PCPMachine_ {
+ Machine super;
+ int smaps_flag;
+ double period;
+ double timestamp; /* previous sample timestamp */
+ pmAtomValue* cpu; /* aggregate values for each metric */
+ pmAtomValue** percpu; /* per-processor values for each metric */
+ pmAtomValue* values; /* per-processor buffer for just one metric */
+ ZfsArcStats zfs;
+} PCPMachine;
+
+#endif
diff --git a/pcp/PCPProcessList.c b/pcp/PCPProcessList.c
index 0e345fc0..c18d74be 100644
--- a/pcp/PCPProcessList.c
+++ b/pcp/PCPProcessList.c
@@ -26,68 +26,23 @@ in the source distribution for its full text.
#include "Settings.h"
#include "XUtils.h"
+#include "pcp/PCPMachine.h"
#include "pcp/PCPMetric.h"
#include "pcp/PCPProcess.h"
-static void PCPProcessList_updateCPUcount(PCPProcessList* this) {
- Machine* host = this->super.host;
- host->activeCPUs = PCPMetric_instanceCount(PCP_PERCPU_SYSTEM);
- unsigned int cpus = Platform_getMaxCPU();
- if (cpus == host->existingCPUs)
- return;
- if (cpus == 0)
- cpus = host->activeCPUs;
- if (cpus <= 1)
- cpus = host->activeCPUs = 1;
- host->existingCPUs = cpus;
-
- free(this->percpu);
- free(this->values);
-
- this->percpu = xCalloc(cpus, sizeof(pmAtomValue*));
- for (unsigned int i = 0; i < cpus; i++)
- this->percpu[i] = xCalloc(CPU_METRIC_COUNT, sizeof(pmAtomValue));
- this->values = xCalloc(cpus, sizeof(pmAtomValue));
-}
-
-static char* setUser(UsersTable* this, unsigned int uid, int pid, int offset) {
- char* name = Hashtable_get(this->users, uid);
- if (name)
- return name;
-
- pmAtomValue value;
- if (PCPMetric_instance(PCP_PROC_ID_USER, pid, offset, &value, PM_TYPE_STRING)) {
- Hashtable_put(this->users, uid, value.cp);
- name = value.cp;
- }
- return name;
-}
-
ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList) {
PCPProcessList* this = xCalloc(1, sizeof(PCPProcessList));
ProcessList* super = &(this->super);
ProcessList_init(super, Class(PCPProcess), host, pidMatchList);
- struct timeval timestamp;
- gettimeofday(&timestamp, NULL);
- this->timestamp = pmtimevalToReal(&timestamp);
-
- this->cpu = xCalloc(CPU_METRIC_COUNT, sizeof(pmAtomValue));
- PCPProcessList_updateCPUcount(this);
-
return super;
}
-void ProcessList_delete(ProcessList* pl) {
- PCPProcessList* this = (PCPProcessList*) pl;
- ProcessList_done(pl);
- free(this->values);
- for (unsigned int i = 0; i < pl->host->existingCPUs; i++)
- free(this->percpu[i]);
- free(this->percpu);
- free(this->cpu);
+void ProcessList_delete(ProcessList* super) {
+ PCPProcessList* this = (PCPProcessList*) super;
+ ProcessList_done(super);
free(this);
}
@@ -143,6 +98,19 @@ static inline char Metric_instance_char(int metric, int pid, int offset, char fa
return fallback;
}
+static char* setUser(UsersTable* this, unsigned int uid, int pid, int offset) {
+ char* name = Hashtable_get(this->users, uid);
+ if (name)
+ return name;
+
+ pmAtomValue value;
+ if (PCPMetric_instance(PCP_PROC_ID_USER, pid, offset, &value, PM_TYPE_STRING)) {
+ Hashtable_put(this->users, uid, value.cp);
+ name = value.cp;
+ }
+ return name;
+}
+
static inline ProcessState PCPProcessList_getProcessState(char state) {
switch (state) {
case '?': return UNKNOWN;
@@ -340,16 +308,17 @@ static void PCPProcessList_updateCmdline(Process* process, int pid, int offset,
}
}
-static bool PCPProcessList_updateProcesses(PCPProcessList* this, double period, struct timeval* tv) {
+static bool PCPProcessList_updateProcesses(PCPProcessList* this) {
ProcessList* pl = (ProcessList*) this;
-
Machine* host = pl->host;
- const Settings* settings = host->settings;
+ PCPMachine* phost = (PCPMachine*) host;
+ const Settings* settings = host->settings;
bool hideKernelThreads = settings->hideKernelThreads;
bool hideUserlandThreads = settings->hideUserlandThreads;
+ uint32_t flags = settings->ss->flags;
- unsigned long long now = tv->tv_sec * 1000LL + tv->tv_usec / 1000LL;
+ unsigned long long now = (unsigned long long)(phost->timestamp * 1000);
int pid = -1, offset = -1;
/* for every process ... */
@@ -387,12 +356,12 @@ static bool PCPProcessList_updateProcesses(PCPProcessList* this, double period,
continue;
}
- if (settings->ss->flags & PROCESS_FLAG_IO)
+ if (flags & PROCESS_FLAG_IO)
PCPProcessList_updateIO(pp, pid, offset, now);
PCPProcessList_updateMemory(pp, pid, offset);
- if ((settings->ss->flags & PROCESS_FLAG_LINUX_SMAPS) &&
+ if ((flags & PROCESS_FLAG_LINUX_SMAPS) &&
(Process_isKernelThread(proc) == false)) {
if (PCPMetric_enabled(PCP_PROC_SMAPS_PSS))
PCPProcessList_updateSmaps(pp, pid, offset);
@@ -407,10 +376,10 @@ static bool PCPProcessList_updateProcesses(PCPProcessList* this, double period,
if (tty_nr != proc->tty_nr)
PCPProcessList_updateTTY(proc, pid, offset);
- float percent_cpu = (pp->utime + pp->stime - lasttimes) / period * 100.0;
+ float percent_cpu = (pp->utime + pp->stime - lasttimes) / phost->period * 100.0;
proc->percent_cpu = isnan(percent_cpu) ?
0.0 : CLAMP(percent_cpu, 0.0, host->activeCPUs * 100.0);
- proc->percent_mem = proc->m_resident / (double)host->totalMem * 100.0;
+ proc->percent_mem = proc->m_resident / (double) host->totalMem * 100.0;
Process_updateCPUFieldWidths(proc->percent_cpu);
PCPProcessList_updateUsername(proc, pid, offset, host->usersTable);
@@ -423,22 +392,22 @@ static bool PCPProcessList_updateProcesses(PCPProcessList* this, double period,
PCPProcessList_updateCmdline(proc, pid, offset, command);
}
- if (settings->ss->flags & PROCESS_FLAG_LINUX_CGROUP)
+ if (flags & PROCESS_FLAG_LINUX_CGROUP)
PCPProcessList_readCGroups(pp, pid, offset);
- if (settings->ss->flags & PROCESS_FLAG_LINUX_OOM)
+ if (flags & PROCESS_FLAG_LINUX_OOM)
PCPProcessList_readOomData(pp, pid, offset);
- if (settings->ss->flags & PROCESS_FLAG_LINUX_CTXT)
+ if (flags & PROCESS_FLAG_LINUX_CTXT)
PCPProcessList_readCtxtData(pp, pid, offset);
- if (settings->ss->flags & PROCESS_FLAG_LINUX_SECATTR)
+ if (flags & PROCESS_FLAG_LINUX_SECATTR)
PCPProcessList_readSecattrData(pp, pid, offset);
- if (settings->ss->flags & PROCESS_FLAG_CWD)
+ if (flags & PROCESS_FLAG_CWD)
PCPProcessList_readCwd(pp, pid, offset);
- if (settings->ss->flags & PROCESS_FLAG_LINUX_AUTOGROUP)
+ if (flags & PROCESS_FLAG_LINUX_AUTOGROUP)
PCPProcessList_readAutogroup(pp, pid, offset);
if (proc->state == ZOMBIE && !proc->cmdline && command[0]) {
@@ -467,277 +436,7 @@ static bool PCPProcessList_updateProcesses(PCPProcessList* this, double period,
return true;
}
-static void PCPProcessList_updateMemoryInfo(ProcessList* super) {
- Machine* host = super->host;
- unsigned long long int freeMem = 0;
- unsigned long long int swapFreeMem = 0;
- unsigned long long int sreclaimableMem = 0;
- host->totalMem = host->usedMem = host->cachedMem = 0;
- host->usedSwap = host->totalSwap = host->sharedMem = 0;
-
- pmAtomValue value;
- if (PCPMetric_values(PCP_MEM_TOTAL, &value, 1, PM_TYPE_U64) != NULL)
- host->totalMem = value.ull;
- if (PCPMetric_values(PCP_MEM_FREE, &value, 1, PM_TYPE_U64) != NULL)
- freeMem = value.ull;
- if (PCPMetric_values(PCP_MEM_BUFFERS, &value, 1, PM_TYPE_U64) != NULL)
- host->buffersMem = value.ull;
- if (PCPMetric_values(PCP_MEM_SRECLAIM, &value, 1, PM_TYPE_U64) != NULL)
- sreclaimableMem = value.ull;
- if (PCPMetric_values(PCP_MEM_SHARED, &value, 1, PM_TYPE_U64) != NULL)
- host->sharedMem = value.ull;
- if (PCPMetric_values(PCP_MEM_CACHED, &value, 1, PM_TYPE_U64) != NULL)
- host->cachedMem = value.ull + sreclaimableMem - host->sharedMem;
- const memory_t usedDiff = freeMem + host->cachedMem + sreclaimableMem + host->buffersMem;
- host->usedMem = (host->totalMem >= usedDiff) ?
- host->totalMem - usedDiff : host->totalMem - freeMem;
- if (PCPMetric_values(PCP_MEM_AVAILABLE, &value, 1, PM_TYPE_U64) != NULL)
- host->availableMem = MINIMUM(value.ull, host->totalMem);
- else
- host->availableMem = freeMem;
- if (PCPMetric_values(PCP_MEM_SWAPFREE, &value, 1, PM_TYPE_U64) != NULL)
- swapFreeMem = value.ull;
- if (PCPMetric_values(PCP_MEM_SWAPTOTAL, &value, 1, PM_TYPE_U64) != NULL)
- host->totalSwap = value.ull;
- if (PCPMetric_values(PCP_MEM_SWAPCACHED, &value, 1, PM_TYPE_U64) != NULL)
- host->cachedSwap = value.ull;
- host->usedSwap = host->totalSwap - swapFreeMem - host->cachedSwap;
-}
-
-/* make copies of previously sampled values to avoid overwrite */
-static inline void PCPProcessList_backupCPUTime(pmAtomValue* values) {
- /* the PERIOD fields (must) mirror the TIME fields */
- for (int metric = CPU_TOTAL_TIME; metric < CPU_TOTAL_PERIOD; metric++) {
- values[metric + CPU_TOTAL_PERIOD] = values[metric];
- }
-}
-
-static inline void PCPProcessList_saveCPUTimePeriod(pmAtomValue* values, CPUMetric previous, pmAtomValue* latest) {
- pmAtomValue* value;
-
- /* new value for period */
- value = &values[previous];
- if (latest->ull > value->ull)
- value->ull = latest->ull - value->ull;
- else
- value->ull = 0;
-
- /* new value for time */
- value = &values[previous - CPU_TOTAL_PERIOD];
- value->ull = latest->ull;
-}
-
-/* using copied sampled values and new values, calculate derivations */
-static void PCPProcessList_deriveCPUTime(pmAtomValue* values) {
-
- pmAtomValue* usertime = &values[CPU_USER_TIME];
- pmAtomValue* guesttime = &values[CPU_GUEST_TIME];
- usertime->ull -= guesttime->ull;
-
- pmAtomValue* nicetime = &values[CPU_NICE_TIME];
- pmAtomValue* guestnicetime = &values[CPU_GUESTNICE_TIME];
- nicetime->ull -= guestnicetime->ull;
-
- pmAtomValue* idletime = &values[CPU_IDLE_TIME];
- pmAtomValue* iowaittime = &values[CPU_IOWAIT_TIME];
- pmAtomValue* idlealltime = &values[CPU_IDLE_ALL_TIME];
- idlealltime->ull = idletime->ull + iowaittime->ull;
-
- pmAtomValue* systemtime = &values[CPU_SYSTEM_TIME];
- pmAtomValue* irqtime = &values[CPU_IRQ_TIME];
- pmAtomValue* softirqtime = &values[CPU_SOFTIRQ_TIME];
- pmAtomValue* systalltime = &values[CPU_SYSTEM_ALL_TIME];
- systalltime->ull = systemtime->ull + irqtime->ull + softirqtime->ull;
-
- pmAtomValue* virtalltime = &values[CPU_GUEST_TIME];
- virtalltime->ull = guesttime->ull + guestnicetime->ull;
-
- pmAtomValue* stealtime = &values[CPU_STEAL_TIME];
- pmAtomValue* totaltime = &values[CPU_TOTAL_TIME];
- totaltime->ull = usertime->ull + nicetime->ull + systalltime->ull +
- idlealltime->ull + stealtime->ull + virtalltime->ull;
-
- PCPProcessList_saveCPUTimePeriod(values, CPU_USER_PERIOD, usertime);
- PCPProcessList_saveCPUTimePeriod(values, CPU_NICE_PERIOD, nicetime);
- PCPProcessList_saveCPUTimePeriod(values, CPU_SYSTEM_PERIOD, systemtime);
- PCPProcessList_saveCPUTimePeriod(values, CPU_SYSTEM_ALL_PERIOD, systalltime);
- PCPProcessList_saveCPUTimePeriod(values, CPU_IDLE_ALL_PERIOD, idlealltime);
- PCPProcessList_saveCPUTimePeriod(values, CPU_IDLE_PERIOD, idletime);
- PCPProcessList_saveCPUTimePeriod(values, CPU_IOWAIT_PERIOD, iowaittime);
- PCPProcessList_saveCPUTimePeriod(values, CPU_IRQ_PERIOD, irqtime);
- PCPProcessList_saveCPUTimePeriod(values, CPU_SOFTIRQ_PERIOD, softirqtime);
- PCPProcessList_saveCPUTimePeriod(values, CPU_STEAL_PERIOD, stealtime);
- PCPProcessList_saveCPUTimePeriod(values, CPU_GUEST_PERIOD, virtalltime);
- PCPProcessList_saveCPUTimePeriod(values, CPU_TOTAL_PERIOD, totaltime);
-}
-
-static void PCPProcessList_updateAllCPUTime(PCPProcessList* this, PCPMetric metric, CPUMetric cpumetric)
-{
- pmAtomValue* value = &this->cpu[cpumetric];
- if (PCPMetric_values(metric, value, 1, PM_TYPE_U64) == NULL)
- memset(value, 0, sizeof(pmAtomValue));
-}
-
-static void PCPProcessList_updatePerCPUTime(PCPProcessList* this, PCPMetric metric, CPUMetric cpumetric)
-{
- int cpus = this->super.host->existingCPUs;
- if (PCPMetric_values(metric, this->values, cpus, PM_TYPE_U64) == NULL)
- memset(this->values, 0, cpus * sizeof(pmAtomValue));
- for (int i = 0; i < cpus; i++)
- this->percpu[i][cpumetric].ull = this->values[i].ull;
-}
-
-static void PCPProcessList_updatePerCPUReal(PCPProcessList* this, PCPMetric metric, CPUMetric cpumetric)
-{
- int cpus = this->super.host->existingCPUs;
- if (PCPMetric_values(metric, this->values, cpus, PM_TYPE_DOUBLE) == NULL)
- memset(this->values, 0, cpus * sizeof(pmAtomValue));
- for (int i = 0; i < cpus; i++)
- this->percpu[i][cpumetric].d = this->values[i].d;
-}
-
-static inline void PCPProcessList_scanZfsArcstats(PCPProcessList* this) {
- unsigned long long int dbufSize = 0;
- unsigned long long int dnodeSize = 0;
- unsigned long long int bonusSize = 0;
- pmAtomValue value;
-
- memset(&this->zfs, 0, sizeof(ZfsArcStats));
- if (PCPMetric_values(PCP_ZFS_ARC_ANON_SIZE, &value, 1, PM_TYPE_U64))
- this->zfs.anon = value.ull / ONE_K;
- if (PCPMetric_values(PCP_ZFS_ARC_C_MIN, &value, 1, PM_TYPE_U64))
- this->zfs.min = value.ull / ONE_K;
- if (PCPMetric_values(PCP_ZFS_ARC_C_MAX, &value, 1, PM_TYPE_U64))
- this->zfs.max = value.ull / ONE_K;
- if (PCPMetric_values(PCP_ZFS_ARC_BONUS_SIZE, &value, 1, PM_TYPE_U64))
- bonusSize = value.ull / ONE_K;
- if (PCPMetric_values(PCP_ZFS_ARC_DBUF_SIZE, &value, 1, PM_TYPE_U64))
- dbufSize = value.ull / ONE_K;
- if (PCPMetric_values(PCP_ZFS_ARC_DNODE_SIZE, &value, 1, PM_TYPE_U64))
- dnodeSize = value.ull / ONE_K;
- if (PCPMetric_values(PCP_ZFS_ARC_COMPRESSED_SIZE, &value, 1, PM_TYPE_U64))
- this->zfs.compressed = value.ull / ONE_K;
- if (PCPMetric_values(PCP_ZFS_ARC_UNCOMPRESSED_SIZE, &value, 1, PM_TYPE_U64))
- this->zfs.uncompressed = value.ull / ONE_K;
- if (PCPMetric_values(PCP_ZFS_ARC_HDR_SIZE, &value, 1, PM_TYPE_U64))
- this->zfs.header = value.ull / ONE_K;
- if (PCPMetric_values(PCP_ZFS_ARC_MFU_SIZE, &value, 1, PM_TYPE_U64))
- this->zfs.MFU = value.ull / ONE_K;
- if (PCPMetric_values(PCP_ZFS_ARC_MRU_SIZE, &value, 1, PM_TYPE_U64))
- this->zfs.MRU = value.ull / ONE_K;
- if (PCPMetric_values(PCP_ZFS_ARC_SIZE, &value, 1, PM_TYPE_U64))
- this->zfs.size = value.ull / ONE_K;
-
- this->zfs.other = (dbufSize + dnodeSize + bonusSize) / ONE_K;
- this->zfs.enabled = (this->zfs.size > 0);
- this->zfs.isCompressed = (this->zfs.compressed > 0);
-}
-
-static void PCPProcessList_updateHeader(ProcessList* super, const Settings* settings) {
- Machine* host = super->host;
- PCPProcessList_updateMemoryInfo(super);
-
+void ProcessList_goThroughEntries(ProcessList* super) {
PCPProcessList* this = (PCPProcessList*) super;
- PCPProcessList_updateCPUcount(this);
-
- PCPProcessList_backupCPUTime(this->cpu);
- PCPProcessList_updateAllCPUTime(this, PCP_CPU_USER, CPU_USER_TIME);
- PCPProcessList_updateAllCPUTime(this, PCP_CPU_NICE, CPU_NICE_TIME);
- PCPProcessList_updateAllCPUTime(this, PCP_CPU_SYSTEM, CPU_SYSTEM_TIME);
- PCPProcessList_updateAllCPUTime(this, PCP_CPU_IDLE, CPU_IDLE_TIME);
- PCPProcessList_updateAllCPUTime(this, PCP_CPU_IOWAIT, CPU_IOWAIT_TIME);
- PCPProcessList_updateAllCPUTime(this, PCP_CPU_IRQ, CPU_IRQ_TIME);
- PCPProcessList_updateAllCPUTime(this, PCP_CPU_SOFTIRQ, CPU_SOFTIRQ_TIME);
- PCPProcessList_updateAllCPUTime(this, PCP_CPU_STEAL, CPU_STEAL_TIME);
- PCPProcessList_updateAllCPUTime(this, PCP_CPU_GUEST, CPU_GUEST_TIME);
- PCPProcessList_deriveCPUTime(this->cpu);
-
- for (unsigned int i = 0; i < host->existingCPUs; i++)
- PCPProcessList_backupCPUTime(this->percpu[i]);
- PCPProcessList_updatePerCPUTime(this, PCP_PERCPU_USER, CPU_USER_TIME);
- PCPProcessList_updatePerCPUTime(this, PCP_PERCPU_NICE, CPU_NICE_TIME);
- PCPProcessList_updatePerCPUTime(this, PCP_PERCPU_SYSTEM, CPU_SYSTEM_TIME);
- PCPProcessList_updatePerCPUTime(this, PCP_PERCPU_IDLE, CPU_IDLE_TIME);
- PCPProcessList_updatePerCPUTime(this, PCP_PERCPU_IOWAIT, CPU_IOWAIT_TIME);
- PCPProcessList_updatePerCPUTime(this, PCP_PERCPU_IRQ, CPU_IRQ_TIME);
- PCPProcessList_updatePerCPUTime(this, PCP_PERCPU_SOFTIRQ, CPU_SOFTIRQ_TIME);
- PCPProcessList_updatePerCPUTime(this, PCP_PERCPU_STEAL, CPU_STEAL_TIME);
- PCPProcessList_updatePerCPUTime(this, PCP_PERCPU_GUEST, CPU_GUEST_TIME);
- for (unsigned int i = 0; i < host->existingCPUs; i++)
- PCPProcessList_deriveCPUTime(this->percpu[i]);
-
- if (settings->showCPUFrequency)
- PCPProcessList_updatePerCPUReal(this, PCP_HINV_CPUCLOCK, CPU_FREQUENCY);
-
- PCPProcessList_scanZfsArcstats(this);
-}
-
-void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
- PCPProcessList* this = (PCPProcessList*) super;
- Machine* host = super->host;
- const Settings* settings = host->settings;
- bool enabled = !pauseProcessUpdate;
-
- bool flagged = settings->showCPUFrequency;
- PCPMetric_enable(PCP_HINV_CPUCLOCK, flagged);
-
- /* In pause mode do not sample per-process metric values at all */
- for (int metric = PCP_PROC_PID; metric < PCP_METRIC_COUNT; metric++)
- PCPMetric_enable(metric, enabled);
-
- flagged = settings->ss->flags & PROCESS_FLAG_LINUX_CGROUP;
- PCPMetric_enable(PCP_PROC_CGROUPS, flagged && enabled);
- flagged = settings->ss->flags & PROCESS_FLAG_LINUX_OOM;
- PCPMetric_enable(PCP_PROC_OOMSCORE, flagged && enabled);
- flagged = settings->ss->flags & PROCESS_FLAG_LINUX_CTXT;
- PCPMetric_enable(PCP_PROC_VCTXSW, flagged && enabled);
- PCPMetric_enable(PCP_PROC_NVCTXSW, flagged && enabled);
- flagged = settings->ss->flags & PROCESS_FLAG_LINUX_SECATTR;
- PCPMetric_enable(PCP_PROC_LABELS, flagged && enabled);
- flagged = settings->ss->flags & PROCESS_FLAG_LINUX_AUTOGROUP;
- PCPMetric_enable(PCP_PROC_AUTOGROUP_ID, flagged && enabled);
- PCPMetric_enable(PCP_PROC_AUTOGROUP_NICE, flagged && enabled);
-
- /* Sample smaps metrics on every second pass to improve performance */
- static int smaps_flag;
- smaps_flag = !!smaps_flag;
- PCPMetric_enable(PCP_PROC_SMAPS_PSS, smaps_flag && enabled);
- PCPMetric_enable(PCP_PROC_SMAPS_SWAP, smaps_flag && enabled);
- PCPMetric_enable(PCP_PROC_SMAPS_SWAPPSS, smaps_flag && enabled);
-
- struct timeval timestamp;
- if (PCPMetric_fetch(&timestamp) != true)
- return;
-
- double sample = this->timestamp;
- this->timestamp = pmtimevalToReal(&timestamp);
-
- PCPProcessList_updateHeader(super, settings);
-
- /* In pause mode only update global data for meters (CPU, memory, etc) */
- if (pauseProcessUpdate)
- return;
-
- double period = (this->timestamp - sample) * 100;
- PCPProcessList_updateProcesses(this, period, &timestamp);
-}
-
-Machine* Machine_new(UsersTable* usersTable, uid_t userId) {
- Machine* this = xCalloc(1, sizeof(Machine));
- Machine_init(this, usersTable, userId);
- return this;
-}
-
-void Machine_delete(Machine* host) {
- free(host);
-}
-
-bool Machine_isCPUonline(const Machine* host, unsigned int id) {
- assert(id < host->existingCPUs);
- (void) host;
-
- pmAtomValue value;
- if (PCPMetric_instance(PCP_PERCPU_SYSTEM, id, id, &value, PM_TYPE_U32))
- return true;
- return false;
+ PCPProcessList_updateProcesses(this);
}
diff --git a/pcp/PCPProcessList.h b/pcp/PCPProcessList.h
index 9bce9cd7..47a36026 100644
--- a/pcp/PCPProcessList.h
+++ b/pcp/PCPProcessList.h
@@ -17,62 +17,10 @@ in the source distribution for its full text.
#include "UsersTable.h"
#include "pcp/Platform.h"
-#include "zfs/ZfsArcStats.h"
-typedef enum CPUMetric_ {
- CPU_TOTAL_TIME,
- CPU_USER_TIME,
- CPU_SYSTEM_TIME,
- CPU_SYSTEM_ALL_TIME,
- CPU_IDLE_ALL_TIME,
- CPU_IDLE_TIME,
- CPU_NICE_TIME,
- CPU_IOWAIT_TIME,
- CPU_IRQ_TIME,
- CPU_SOFTIRQ_TIME,
- CPU_STEAL_TIME,
- CPU_GUEST_TIME,
- CPU_GUESTNICE_TIME,
-
- CPU_TOTAL_PERIOD,
- CPU_USER_PERIOD,
- CPU_SYSTEM_PERIOD,
- CPU_SYSTEM_ALL_PERIOD,
- CPU_IDLE_ALL_PERIOD,
- CPU_IDLE_PERIOD,
- CPU_NICE_PERIOD,
- CPU_IOWAIT_PERIOD,
- CPU_IRQ_PERIOD,
- CPU_SOFTIRQ_PERIOD,
- CPU_STEAL_PERIOD,
- CPU_GUEST_PERIOD,
- CPU_GUESTNICE_PERIOD,
-
- CPU_FREQUENCY,
-
- CPU_METRIC_COUNT
-} CPUMetric;
-
typedef struct PCPProcessList_ {
ProcessList super;
- double timestamp; /* previous sample timestamp */
- pmAtomValue* cpu; /* aggregate values for each metric */
- pmAtomValue** percpu; /* per-processor values for each metric */
- pmAtomValue* values; /* per-processor buffer for just one metric */
- ZfsArcStats zfs;
} PCPProcessList;
-ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList);
-
-void ProcessList_delete(ProcessList* pl);
-
-void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
-
-Machine* Machine_new(UsersTable* usersTable, uid_t userId);
-
-bool Machine_isCPUonline(const Machine* host, unsigned int id);
-
-void Machine_delete(Machine* host);
-
#endif
diff --git a/pcp/Platform.c b/pcp/Platform.c
index 181898aa..12e0f4d7 100644
--- a/pcp/Platform.c
+++ b/pcp/Platform.c
@@ -46,6 +46,7 @@ in the source distribution for its full text.
#include "linux/ZramStats.h"
#include "pcp/PCPDynamicColumn.h"
#include "pcp/PCPDynamicMeter.h"
+#include "pcp/PCPMachine.h"
#include "pcp/PCPMetric.h"
#include "pcp/PCPProcessList.h"
#include "zfs/ZfsArcMeter.h"
@@ -484,9 +485,7 @@ long long Platform_getBootTime(void) {
return pcp->btime;
}
-static double Platform_setOneCPUValues(Meter* this, pmAtomValue* values) {
- Settings* settings = this->host->settings;
-
+static double Platform_setOneCPUValues(Meter* this, const Settings* settings, pmAtomValue* values) {
unsigned long long value = values[CPU_TOTAL_PERIOD].ull;
double total = (double) (value == 0 ? 1 : value);
double percent;
@@ -524,18 +523,19 @@ static double Platform_setOneCPUValues(Meter* this, pmAtomValue* values) {
}
double Platform_setCPUValues(Meter* this, int cpu) {
- const PCPProcessList* pl = (const PCPProcessList*) this->host->pl;
+ const PCPMachine* phost = (const PCPMachine*) this->host;
+ const Settings* settings = this->host->settings;
+
if (cpu <= 0) /* use aggregate values */
- return Platform_setOneCPUValues(this, pl->cpu);
- return Platform_setOneCPUValues(this, pl->percpu[cpu - 1]);
+ return Platform_setOneCPUValues(this, settings, phost->cpu);
+ return Platform_setOneCPUValues(this, settings, phost->percpu[cpu - 1]);
}
void Platform_setMemoryValues(Meter* this) {
const Machine* host = this->host;
- const ProcessList* pl = host->pl;
- const PCPProcessList* ppl = (const PCPProcessList*) pl;
+ const PCPMachine* phost = (const PCPMachine*) host;
- this->total = host->totalMem;
+ this->total = host->totalMem;
this->values[MEMORY_METER_USED] = host->usedMem;
this->values[MEMORY_METER_BUFFERS] = host->buffersMem;
this->values[MEMORY_METER_SHARED] = host->sharedMem;
@@ -543,11 +543,11 @@ void Platform_setMemoryValues(Meter* this) {
this->values[MEMORY_METER_CACHE] = host->cachedMem;
this->values[MEMORY_METER_AVAILABLE] = host->availableMem;
- if (ppl->zfs.enabled != 0) {
+ if (phost->zfs.enabled != 0) {
// ZFS does not shrink below the value of zfs_arc_min.
unsigned long long int shrinkableSize = 0;
- if (ppl->zfs.size > ppl->zfs.min)
- shrinkableSize = ppl->zfs.size - ppl->zfs.min;
+ if (phost->zfs.size > phost->zfs.min)
+ shrinkableSize = phost->zfs.size - phost->zfs.min;
this->values[MEMORY_METER_USED] -= shrinkableSize;
this->values[MEMORY_METER_CACHE] += shrinkableSize;
this->values[MEMORY_METER_AVAILABLE] += shrinkableSize;
@@ -595,15 +595,15 @@ void Platform_setZramValues(Meter* this) {
}
void Platform_setZfsArcValues(Meter* this) {
- const PCPProcessList* ppl = (const PCPProcessList*) this->host->pl;
+ const PCPMachine* phost = (const PCPMachine*) this->host;
- ZfsArcMeter_readStats(this, &(ppl->zfs));
+ ZfsArcMeter_readStats(this, &phost->zfs);
}
void Platform_setZfsCompressedArcValues(Meter* this) {
- const PCPProcessList* ppl = (const PCPProcessList*) this->host->pl;
+ const PCPMachine* phost = (const PCPMachine*) this->host;
- ZfsCompressedArcMeter_readStats(this, &(ppl->zfs));
+ ZfsCompressedArcMeter_readStats(this, &phost->zfs);
}
void Platform_getHostname(char* buffer, size_t size) {
diff --git a/solaris/Platform.c b/solaris/Platform.c
index 8c88fc85..ad899492 100644
--- a/solaris/Platform.c
+++ b/solaris/Platform.c
@@ -34,10 +34,11 @@ in the source distribution for its full text.
#include "HostnameMeter.h"
#include "SysArchMeter.h"
#include "UptimeMeter.h"
+
+#include "solaris/SolarisMachine.h"
+
#include "zfs/ZfsArcMeter.h"
#include "zfs/ZfsCompressedArcMeter.h"
-#include "SolarisProcess.h"
-#include "SolarisProcessList.h"
const ScreenDefaults Platform_defaultScreens[] = {
@@ -195,15 +196,15 @@ int Platform_getMaxPid(void) {
double Platform_setCPUValues(Meter* this, unsigned int cpu) {
const Machine* host = this->host;
- const SolarisProcessList* spl = (const SolarisProcessList*) host->pl;
+ const SolarisMachine* shost = (const SolarisMachine*) host;
unsigned int cpus = host->existingCPUs;
const CPUData* cpuData = NULL;
if (cpus == 1) {
// single CPU box has everything in spl->cpus[0]
- cpuData = &(spl->cpus[0]);
+ cpuData = &(shost->cpus[0]);
} else {
- cpuData = &(spl->cpus[cpu]);
+ cpuData = &(shost->cpus[cpu]);
}
if (!cpuData->online) {
@@ -216,7 +217,7 @@ double Platform_setCPUValues(Meter* this, unsigned int cpu) {
v[CPU_METER_NICE] = cpuData->nicePercent;
v[CPU_METER_NORMAL] = cpuData->userPercent;
- if (host->settings->detailedCPUTime) {
+ if (super->settings->detailedCPUTime) {
v[CPU_METER_KERNEL] = cpuData->systemPercent;
v[CPU_METER_IRQ] = cpuData->irqPercent;
this->curItems = 4;
@@ -255,15 +256,15 @@ void Platform_setSwapValues(Meter* this) {
}
void Platform_setZfsArcValues(Meter* this) {
- const SolarisProcessList* spl = (const SolarisProcessList*) this->host->pl;
+ const SolarisMachine* shost = (SolarisMachine*) this->host;
- ZfsArcMeter_readStats(this, &(spl->zfs));
+ ZfsArcMeter_readStats(this, &(shost->zfs));
}
void Platform_setZfsCompressedArcValues(Meter* this) {
- const SolarisProcessList* spl = (const SolarisProcessList*) this->host->pl;
+ const SolarisMachine* shost = (SolarisMachine*) this->host;
- ZfsCompressedArcMeter_readStats(this, &(spl->zfs));
+ ZfsCompressedArcMeter_readStats(this, &(shost->zfs));
}
static int Platform_buildenv(void* accum, struct ps_prochandle* Phandle, uintptr_t addr, const char* str) {
diff --git a/solaris/SolarisMachine.c b/solaris/SolarisMachine.c
new file mode 100644
index 00000000..9ce4ced2
--- /dev/null
+++ b/solaris/SolarisMachine.c
@@ -0,0 +1,332 @@
+/*
+htop - SolarisMachine.c
+(C) 2014 Hisham H. Muhammad
+(C) 2017,2018 Guy M. Broome
+Released under the GNU GPLv2+, see the COPYING file
+in the source distribution for its full text.
+*/
+
+
+#include "solaris/SolarisMachine.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <limits.h>
+#include <string.h>
+#include <procfs.h>
+#include <errno.h>
+#include <pwd.h>
+#include <math.h>
+#include <time.h>
+
+#include "CRT.h"
+#include "solaris/Platform.h"
+
+
+static void SolarisMachine_updateCPUcount(SolarisMachine* this) {
+ Machine* super = &this->super;
+ long int s;
+ bool change = false;
+
+ s = sysconf(_SC_NPROCESSORS_CONF);
+ if (s < 1)
+ CRT_fatalError("Cannot get existing CPU count by sysconf(_SC_NPROCESSORS_CONF)");
+
+ if (s != super->existingCPUs) {
+ if (s == 1) {
+ this->cpus = xRealloc(this->cpus, sizeof(CPUData));
+ this->cpus[0].online = true;
+ } else {
+ this->cpus = xReallocArray(this->cpus, s + 1, sizeof(CPUData));
+ this->cpus[0].online = true; /* average is always "online" */
+ for (int i = 1; i < s + 1; i++) {
+ this->cpus[i].online = false;
+ }
+ }
+
+ change = true;
+ super->existingCPUs = s;
+ }
+
+ s = sysconf(_SC_NPROCESSORS_ONLN);
+ if (s < 1)
+ CRT_fatalError("Cannot get active CPU count by sysconf(_SC_NPROCESSORS_ONLN)");
+
+ if (s != super->activeCPUs) {
+ change = true;
+ hsuper->activeCPUs = s;
+ }
+
+ if (change) {
+ kstat_close(this->kd);
+ this->kd = kstat_open();
+ if (!this->kd)
+ CRT_fatalError("Cannot open kstat handle");
+ }
+}
+
+
+static void SolarisMachine_scanCPUTime(SolarisMachine* this) {
+ Machine* super = &this->super;
+ unsigned int activeCPUs = super->activeCPUs;
+ unsigned int existingCPUs = super->existingCPUs;
+ kstat_t* cpuinfo = NULL;
+ kstat_named_t* idletime = NULL;
+ kstat_named_t* intrtime = NULL;
+ kstat_named_t* krnltime = NULL;
+ kstat_named_t* usertime = NULL;
+ kstat_named_t* cpu_freq = NULL;
+ double idlebuf = 0;
+ double intrbuf = 0;
+ double krnlbuf = 0;
+ double userbuf = 0;
+ int arrskip = 0;
+
+ assert(existingCPUs > 0);
+ assert(this->kd);
+
+ if (existingCPUs > 1) {
+ // Store values for the stats loop one extra element up in the array
+ // to leave room for the average to be calculated afterwards
+ arrskip++;
+ }
+
+ // Calculate per-CPU statistics first
+ for (unsigned int i = 0; i < existingCPUs; i++) {
+ CPUData* cpuData = &(this->cpus[i + arrskip]);
+
+ if ((cpuinfo = kstat_lookup_wrapper(this->kd, "cpu", i, "sys")) != NULL) {
+ cpuData->online = true;
+ if (kstat_read(this->kd, cpuinfo, NULL) != -1) {
+ idletime = kstat_data_lookup_wrapper(cpuinfo, "cpu_nsec_idle");
+ intrtime = kstat_data_lookup_wrapper(cpuinfo, "cpu_nsec_intr");
+ krnltime = kstat_data_lookup_wrapper(cpuinfo, "cpu_nsec_kernel");
+ usertime = kstat_data_lookup_wrapper(cpuinfo, "cpu_nsec_user");
+ }
+ } else {
+ cpuData->online = false;
+ continue;
+ }
+
+ assert( (idletime != NULL) && (intrtime != NULL)
+ && (krnltime != NULL) && (usertime != NULL) );
+
+ if (super->settings->showCPUFrequency) {
+ if ((cpuinfo = kstat_lookup_wrapper(this->kd, "cpu_info", i, NULL)) != NULL) {
+ if (kstat_read(this->kd, cpuinfo, NULL) != -1) {
+ cpu_freq = kstat_data_lookup_wrapper(cpuinfo, "current_clock_Hz");
+ }
+ }
+
+ assert( cpu_freq != NULL );
+ }
+
+ uint64_t totaltime = (idletime->value.ui64 - cpuData->lidle)
+ + (intrtime->value.ui64 - cpuData->lintr)
+ + (krnltime->value.ui64 - cpuData->lkrnl)
+ + (usertime->value.ui64 - cpuData->luser);
+
+ // Calculate percentages of deltas since last reading
+ cpuData->userPercent = ((usertime->value.ui64 - cpuData->luser) / (double)totaltime) * 100.0;
+ cpuData->nicePercent = (double)0.0; // Not implemented on Solaris
+ cpuData->systemPercent = ((krnltime->value.ui64 - cpuData->lkrnl) / (double)totaltime) * 100.0;
+ cpuData->irqPercent = ((intrtime->value.ui64 - cpuData->lintr) / (double)totaltime) * 100.0;
+ cpuData->systemAllPercent = cpuData->systemPercent + cpuData->irqPercent;
+ cpuData->idlePercent = ((idletime->value.ui64 - cpuData->lidle) / (double)totaltime) * 100.0;
+ // Store current values to use for the next round of deltas
+ cpuData->luser = usertime->value.ui64;
+ cpuData->lkrnl = krnltime->value.ui64;
+ cpuData->lintr = intrtime->value.ui64;
+ cpuData->lidle = idletime->value.ui64;
+ // Add frequency in MHz
+ cpuData->frequency = super->settings->showCPUFrequency ? (double)cpu_freq->value.ui64 / 1E6 : NAN;
+ // Accumulate the current percentages into buffers for later average calculation
+ if (existingCPUs > 1) {
+ userbuf += cpuData->userPercent;
+ krnlbuf += cpuData->systemPercent;
+ intrbuf += cpuData->irqPercent;
+ idlebuf += cpuData->idlePercent;
+ }
+ }
+
+ if (existingCPUs > 1) {
+ CPUData* cpuData = &(this->cpus[0]);
+ cpuData->userPercent = userbuf / activeCPUs;
+ cpuData->nicePercent = (double)0.0; // Not implemented on Solaris
+ cpuData->systemPercent = krnlbuf / activeCPUs;
+ cpuData->irqPercent = intrbuf / activeCPUs;
+ cpuData->systemAllPercent = cpuData->systemPercent + cpuData->irqPercent;
+ cpuData->idlePercent = idlebuf / activeCPUs;
+ }
+}
+
+static void SolarisMachine_scanMemoryInfo(SolarisMachine* this) {
+ Machine* super = &this->super;
+ static kstat_t *meminfo = NULL;
+ int ksrphyserr = -1;
+ kstat_named_t *totalmem_pgs = NULL;
+ kstat_named_t *freemem_pgs = NULL;
+ kstat_named_t *pages = NULL;
+ struct swaptable *sl = NULL;
+ struct swapent *swapdev = NULL;
+ uint64_t totalswap = 0;
+ uint64_t totalfree = 0;
+ int nswap = 0;
+ char *spath = NULL;
+ char *spathbase = NULL;
+
+ // Part 1 - physical memory
+ if (this->kd != NULL && meminfo == NULL) {
+ // Look up the kstat chain just once, it never changes
+ meminfo = kstat_lookup_wrapper(this->kd, "unix", 0, "system_pages");
+ }
+ if (meminfo != NULL) {
+ ksrphyserr = kstat_read(this->kd, meminfo, NULL);
+ }
+ if (ksrphyserr != -1) {
+ totalmem_pgs = kstat_data_lookup_wrapper(meminfo, "physmem");
+ freemem_pgs = kstat_data_lookup_wrapper(meminfo, "freemem");
+ pages = kstat_data_lookup_wrapper(meminfo, "pagestotal");
+
+ super->totalMem = totalmem_pgs->value.ui64 * this->pageSizeKB;
+ if (super->totalMem > freemem_pgs->value.ui64 * this->pageSizeKB) {
+ super->usedMem = super->totalMem - freemem_pgs->value.ui64 * this->pageSizeKB;
+ } else {
+ super->usedMem = 0; // This can happen in non-global zone (in theory)
+ }
+ // Not sure how to implement this on Solaris - suggestions welcome!
+ super->cachedMem = 0;
+ // Not really "buffers" but the best Solaris analogue that I can find to
+ // "memory in use but not by programs or the kernel itself"
+ super->buffersMem = (totalmem_pgs->value.ui64 - pages->value.ui64) * this->pageSizeKB;
+ } else {
+ // Fall back to basic sysconf if kstat isn't working
+ super->totalMem = sysconf(_SC_PHYS_PAGES) * this->pageSize;
+ super->buffersMem = 0;
+ super->cachedMem = 0;
+ super->usedMem = super->totalMem - (sysconf(_SC_AVPHYS_PAGES) * this->pageSize);
+ }
+
+ // Part 2 - swap
+ nswap = swapctl(SC_GETNSWP, NULL);
+ if (nswap > 0) {
+ sl = xMalloc((nswap * sizeof(swapent_t)) + sizeof(int));
+ }
+ if (sl != NULL) {
+ spathbase = xMalloc( nswap * MAXPATHLEN );
+ }
+ if (spathbase != NULL) {
+ spath = spathbase;
+ swapdev = sl->swt_ent;
+ for (int i = 0; i < nswap; i++, swapdev++) {
+ swapdev->ste_path = spath;
+ spath += MAXPATHLEN;
+ }
+ sl->swt_n = nswap;
+ }
+ nswap = swapctl(SC_LIST, sl);
+ if (nswap > 0) {
+ swapdev = sl->swt_ent;
+ for (int i = 0; i < nswap; i++, swapdev++) {
+ totalswap += swapdev->ste_pages;
+ totalfree += swapdev->ste_free;
+ }
+ }
+ free(spathbase);
+ free(sl);
+ super->totalSwap = totalswap * this->pageSizeKB;
+ super->usedSwap = super->totalSwap - (totalfree * this->pageSizeKB);
+}
+
+static void SolarisMachine_scanZfsArcstats(SolarisMachine* this) {
+ kstat_named_t *cur_kstat = NULL;
+ kstat_t *arcstats = NULL;
+ int ksrphyserr = -1;
+
+ if (this->kd != NULL) {
+ arcstats = kstat_lookup_wrapper(this->kd, "zfs", 0, "arcstats");
+ }
+ if (arcstats != NULL) {
+ ksrphyserr = kstat_read(this->kd, arcstats, NULL);
+ }
+ if (ksrphyserr != -1) {
+ cur_kstat = kstat_data_lookup_wrapper( arcstats, "size" );
+ this->zfs.size = cur_kstat->value.ui64 / 1024;
+ this->zfs.enabled = this->zfs.size > 0 ? 1 : 0;
+
+ cur_kstat = kstat_data_lookup_wrapper( arcstats, "c_max" );
+ this->zfs.max = cur_kstat->value.ui64 / 1024;
+
+ cur_kstat = kstat_data_lookup_wrapper( arcstats, "mfu_size" );
+ this->zfs.MFU = cur_kstat != NULL ? cur_kstat->value.ui64 / 1024 : 0;
+
+ cur_kstat = kstat_data_lookup_wrapper( arcstats, "mru_size" );
+ this->zfs.MRU = cur_kstat != NULL ? cur_kstat->value.ui64 / 1024 : 0;
+
+ cur_kstat = kstat_data_lookup_wrapper( arcstats, "anon_size" );
+ this->zfs.anon = cur_kstat != NULL ? cur_kstat->value.ui64 / 1024 : 0;
+
+ cur_kstat = kstat_data_lookup_wrapper( arcstats, "hdr_size" );
+ this->zfs.header = cur_kstat != NULL ? cur_kstat->value.ui64 / 1024 : 0;
+
+ cur_kstat = kstat_data_lookup_wrapper( arcstats, "other_size" );
+ this->zfs.other = cur_kstat != NULL ? cur_kstat->value.ui64 / 1024 : 0;
+
+ if ((cur_kstat = kstat_data_lookup_wrapper( arcstats, "compressed_size" )) != NULL) {
+ this->zfs.compressed = cur_kstat->value.ui64 / 1024;
+ this->zfs.isCompressed = 1;
+
+ cur_kstat = kstat_data_lookup_wrapper( arcstats, "uncompressed_size" );
+ this->zfs.uncompressed = cur_kstat->value.ui64 / 1024;
+ } else {
+ this->zfs.isCompressed = 0;
+ }
+ }
+}
+
+void Machine_scan(Machine* super) {
+ SolarisMachine* this = (SolarisMachine*) super;
+
+ SolarisMachine_updateCPUcount(this);
+ SolarisMachine_scanCPUTime(this);
+ SolarisMachine_scanMemoryInfo(this);
+ SolarisMachine_scanZfsArcstats(this);
+}
+
+Machine* Machine_new(UsersTable* usersTable, uid_t userId) {
+ SolarisMachine* this = xCalloc(1, sizeof(SolarisMachine));
+ Machine *super = &this->super;
+
+ Machine_init(super, usersTable, userId);
+
+ this->pageSize = sysconf(_SC_PAGESIZE);
+ if (this->pageSize == -1)
+ CRT_fatalError("Cannot get pagesize by sysconf(_SC_PAGESIZE)");
+ this->pageSizeKB = this->pageSize / 1024;
+
+ SolarisMachine_updateCPUcount(this);
+
+ return super;
+}
+
+void Machine_delete(Machine* super) {
+ SolarisMachine* this = (SolarisMachine*) super;
+
+ Machine_done(super);
+
+ free(this->cpus);
+ if (this->kd) {
+ kstat_close(this->kd);
+ }
+ free(this);
+}
+
+bool Machine_isCPUonline(const Machine* super, unsigned int id) {
+ assert(id < super->existingCPUs);
+
+ const SolarisMachine* this = (const SolarisMachine*) super;
+
+ return (super->existingCPUs == 1) ? true : this->cpus[id + 1].online;
+}
diff --git a/solaris/SolarisMachine.h b/solaris/SolarisMachine.h
new file mode 100644
index 00000000..da091c6e
--- /dev/null
+++ b/solaris/SolarisMachine.h
@@ -0,0 +1,59 @@
+#ifndef HEADER_SolarisMachine
+#define HEADER_SolarisMachine
+/*
+htop - SolarisMachine.h
+(C) 2014 Hisham H. Muhammad
+(C) 2017,2018 Guy M. Broome
+Released under the GNU GPLv2+, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "config.h" // IWYU pragma: keep
+
+#include <kstat.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/param.h>
+#include <sys/uio.h>
+#include <sys/resource.h>
+#include <sys/sysconf.h>
+#include <sys/sysinfo.h>
+#include <sys/swap.h>
+
+#include "Hashtable.h"
+#include "UsersTable.h"
+
+#include "zfs/ZfsArcStats.h"
+
+
+#define ZONE_ERRMSGLEN 1024
+extern char zone_errmsg[ZONE_ERRMSGLEN];
+
+typedef struct CPUData_ {
+ double userPercent;
+ double nicePercent;
+ double systemPercent;
+ double irqPercent;
+ double idlePercent;
+ double systemAllPercent;
+ double frequency;
+ uint64_t luser;
+ uint64_t lkrnl;
+ uint64_t lintr;
+ uint64_t lidle;
+ bool online;
+} CPUData;
+
+typedef struct SolarisMachine_ {
+ Machine super;
+
+ kstat_ctl_t* kd;
+ CPUData* cpus;
+
+ int pageSize;
+ int pageSizeKB;
+
+ ZfsArcStats zfs;
+} SolarisMachine;
+
+#endif
diff --git a/solaris/SolarisProcessList.c b/solaris/SolarisProcessList.c
index 84991d6e..e759b187 100644
--- a/solaris/SolarisProcessList.c
+++ b/solaris/SolarisProcessList.c
@@ -29,9 +29,6 @@ in the source distribution for its full text.
#define GZONE "global "
#define UZONE "unknown "
-static int pageSize;
-static int pageSizeKB;
-
static char* SolarisProcessList_readZoneName(kstat_ctl_t* kd, SolarisProcess* sproc) {
char* zname;
@@ -47,296 +44,18 @@ static char* SolarisProcessList_readZoneName(kstat_ctl_t* kd, SolarisProcess* sp
return zname;
}
-static void SolarisProcessList_updateCPUcount(ProcessList* super) {
- Machine* host = super->host;
- SolarisProcessList* spl = (SolarisProcessList*) super;
- long int s;
- bool change = false;
-
- s = sysconf(_SC_NPROCESSORS_CONF);
- if (s < 1)
- CRT_fatalError("Cannot get existing CPU count by sysconf(_SC_NPROCESSORS_CONF)");
-
- if (s != host->existingCPUs) {
- if (s == 1) {
- spl->cpus = xRealloc(spl->cpus, sizeof(CPUData));
- spl->cpus[0].online = true;
- } else {
- spl->cpus = xReallocArray(spl->cpus, s + 1, sizeof(CPUData));
- spl->cpus[0].online = true; /* average is always "online" */
- for (int i = 1; i < s + 1; i++) {
- spl->cpus[i].online = false;
- }
- }
-
- change = true;
- host->existingCPUs = s;
- }
-
- s = sysconf(_SC_NPROCESSORS_ONLN);
- if (s < 1)
- CRT_fatalError("Cannot get active CPU count by sysconf(_SC_NPROCESSORS_ONLN)");
-
- if (s != host->activeCPUs) {
- change = true;
- host->activeCPUs = s;
- }
-
- if (change) {
- kstat_close(spl->kd);
- spl->kd = kstat_open();
- if (!spl->kd)
- CRT_fatalError("Cannot open kstat handle");
- }
-}
-
ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList) {
SolarisProcessList* spl = xCalloc(1, sizeof(SolarisProcessList));
ProcessList* pl = (ProcessList*) spl;
- ProcessList_init(pl, Class(SolarisProcess), host, pidMatchList);
-
- spl->kd = kstat_open();
- if (!spl->kd)
- CRT_fatalError("Cannot open kstat handle");
- pageSize = sysconf(_SC_PAGESIZE);
- if (pageSize == -1)
- CRT_fatalError("Cannot get pagesize by sysconf(_SC_PAGESIZE)");
- pageSizeKB = pageSize / 1024;
-
- SolarisProcessList_updateCPUcount(pl);
+ ProcessList_init(pl, Class(SolarisProcess), host, pidMatchList);
return pl;
}
-static inline void SolarisProcessList_scanCPUTime(ProcessList* pl) {
- const SolarisProcessList* spl = (SolarisProcessList*) pl;
- unsigned int activeCPUs = pl->host->activeCPUs;
- unsigned int existingCPUs = pl->host->existingCPUs;
- kstat_t* cpuinfo = NULL;
- kstat_named_t* idletime = NULL;
- kstat_named_t* intrtime = NULL;
- kstat_named_t* krnltime = NULL;
- kstat_named_t* usertime = NULL;
- kstat_named_t* cpu_freq = NULL;
- double idlebuf = 0;
- double intrbuf = 0;
- double krnlbuf = 0;
- double userbuf = 0;
- int arrskip = 0;
-
- assert(existingCPUs > 0);
- assert(spl->kd);
-
- if (existingCPUs > 1) {
- // Store values for the stats loop one extra element up in the array
- // to leave room for the average to be calculated afterwards
- arrskip++;
- }
-
- // Calculate per-CPU statistics first
- for (unsigned int i = 0; i < existingCPUs; i++) {
- CPUData* cpuData = &(spl->cpus[i + arrskip]);
-
- if ((cpuinfo = kstat_lookup_wrapper(spl->kd, "cpu", i, "sys")) != NULL) {
- cpuData->online = true;
- if (kstat_read(spl->kd, cpuinfo, NULL) != -1) {
- idletime = kstat_data_lookup_wrapper(cpuinfo, "cpu_nsec_idle");
- intrtime = kstat_data_lookup_wrapper(cpuinfo, "cpu_nsec_intr");
- krnltime = kstat_data_lookup_wrapper(cpuinfo, "cpu_nsec_kernel");
- usertime = kstat_data_lookup_wrapper(cpuinfo, "cpu_nsec_user");
- }
- } else {
- cpuData->online = false;
- continue;
- }
-
- assert( (idletime != NULL) && (intrtime != NULL)
- && (krnltime != NULL) && (usertime != NULL) );
-
- if (pl->settings->showCPUFrequency) {
- if ((cpuinfo = kstat_lookup_wrapper(spl->kd, "cpu_info", i, NULL)) != NULL) {
- if (kstat_read(spl->kd, cpuinfo, NULL) != -1) {
- cpu_freq = kstat_data_lookup_wrapper(cpuinfo, "current_clock_Hz");
- }
- }
-
- assert( cpu_freq != NULL );
- }
-
- uint64_t totaltime = (idletime->value.ui64 - cpuData->lidle)
- + (intrtime->value.ui64 - cpuData->lintr)
- + (krnltime->value.ui64 - cpuData->lkrnl)
- + (usertime->value.ui64 - cpuData->luser);
-
- // Calculate percentages of deltas since last reading
- cpuData->userPercent = ((usertime->value.ui64 - cpuData->luser) / (double)totaltime) * 100.0;
- cpuData->nicePercent = (double)0.0; // Not implemented on Solaris
- cpuData->systemPercent = ((krnltime->value.ui64 - cpuData->lkrnl) / (double)totaltime) * 100.0;
- cpuData->irqPercent = ((intrtime->value.ui64 - cpuData->lintr) / (double)totaltime) * 100.0;
- cpuData->systemAllPercent = cpuData->systemPercent + cpuData->irqPercent;
- cpuData->idlePercent = ((idletime->value.ui64 - cpuData->lidle) / (double)totaltime) * 100.0;
- // Store current values to use for the next round of deltas
- cpuData->luser = usertime->value.ui64;
- cpuData->lkrnl = krnltime->value.ui64;
- cpuData->lintr = intrtime->value.ui64;
- cpuData->lidle = idletime->value.ui64;
- // Add frequency in MHz
- cpuData->frequency = pl->settings->showCPUFrequency ? (double)cpu_freq->value.ui64 / 1E6 : NAN;
- // Accumulate the current percentages into buffers for later average calculation
- if (existingCPUs > 1) {
- userbuf += cpuData->userPercent;
- krnlbuf += cpuData->systemPercent;
- intrbuf += cpuData->irqPercent;
- idlebuf += cpuData->idlePercent;
- }
- }
-
- if (existingCPUs > 1) {
- CPUData* cpuData = &(spl->cpus[0]);
- cpuData->userPercent = userbuf / activeCPUs;
- cpuData->nicePercent = (double)0.0; // Not implemented on Solaris
- cpuData->systemPercent = krnlbuf / activeCPUs;
- cpuData->irqPercent = intrbuf / activeCPUs;
- cpuData->systemAllPercent = cpuData->systemPercent + cpuData->irqPercent;
- cpuData->idlePercent = idlebuf / activeCPUs;
- }
-}
-
-static inline void SolarisProcessList_scanMemoryInfo(ProcessList* pl) {
- Machine* host = pl->host;
- SolarisProcessList* spl = (SolarisProcessList*) pl;
-
- static kstat_t *meminfo = NULL;
- int ksrphyserr = -1;
- kstat_named_t *totalmem_pgs = NULL;
- kstat_named_t *freemem_pgs = NULL;
- kstat_named_t *pages = NULL;
- struct swaptable *sl = NULL;
- struct swapent *swapdev = NULL;
- uint64_t totalswap = 0;
- uint64_t totalfree = 0;
- int nswap = 0;
- char *spath = NULL;
- char *spathbase = NULL;
-
- // Part 1 - physical memory
- if (spl->kd != NULL && meminfo == NULL) {
- // Look up the kstat chain just once, it never changes
- meminfo = kstat_lookup_wrapper(spl->kd, "unix", 0, "system_pages");
- }
- if (meminfo != NULL) {
- ksrphyserr = kstat_read(spl->kd, meminfo, NULL);
- }
- if (ksrphyserr != -1) {
- totalmem_pgs = kstat_data_lookup_wrapper(meminfo, "physmem");
- freemem_pgs = kstat_data_lookup_wrapper(meminfo, "freemem");
- pages = kstat_data_lookup_wrapper(meminfo, "pagestotal");
-
- host->totalMem = totalmem_pgs->value.ui64 * pageSizeKB;
- if (host->totalMem > freemem_pgs->value.ui64 * pageSizeKB) {
- host->usedMem = host->totalMem - freemem_pgs->value.ui64 * pageSizeKB;
- } else {
- host->usedMem = 0; // This can happen in non-global zone (in theory)
- }
- // Not sure how to implement this on Solaris - suggestions welcome!
- host->cachedMem = 0;
- // Not really "buffers" but the best Solaris analogue that I can find to
- // "memory in use but not by programs or the kernel itself"
- host->buffersMem = (totalmem_pgs->value.ui64 - pages->value.ui64) * pageSizeKB;
- } else {
- // Fall back to basic sysconf if kstat isn't working
- host->totalMem = sysconf(_SC_PHYS_PAGES) * pageSize;
- host->buffersMem = 0;
- host->cachedMem = 0;
- host->usedMem = host->totalMem - (sysconf(_SC_AVPHYS_PAGES) * pageSize);
- }
-
- // Part 2 - swap
- nswap = swapctl(SC_GETNSWP, NULL);
- if (nswap > 0) {
- sl = xMalloc((nswap * sizeof(swapent_t)) + sizeof(int));
- }
- if (sl != NULL) {
- spathbase = xMalloc( nswap * MAXPATHLEN );
- }
- if (spathbase != NULL) {
- spath = spathbase;
- swapdev = sl->swt_ent;
- for (int i = 0; i < nswap; i++, swapdev++) {
- swapdev->ste_path = spath;
- spath += MAXPATHLEN;
- }
- sl->swt_n = nswap;
- }
- nswap = swapctl(SC_LIST, sl);
- if (nswap > 0) {
- swapdev = sl->swt_ent;
- for (int i = 0; i < nswap; i++, swapdev++) {
- totalswap += swapdev->ste_pages;
- totalfree += swapdev->ste_free;
- }
- }
- free(spathbase);
- free(sl);
- host->totalSwap = totalswap * pageSizeKB;
- host->usedSwap = host->totalSwap - (totalfree * pageSizeKB);
-}
-
-static inline void SolarisProcessList_scanZfsArcstats(ProcessList* pl) {
- SolarisProcessList* spl = (SolarisProcessList*) pl;
- kstat_t *arcstats = NULL;
- int ksrphyserr = -1;
- kstat_named_t *cur_kstat = NULL;
-
- if (spl->kd != NULL) {
- arcstats = kstat_lookup_wrapper(spl->kd, "zfs", 0, "arcstats");
- }
- if (arcstats != NULL) {
- ksrphyserr = kstat_read(spl->kd, arcstats, NULL);
- }
- if (ksrphyserr != -1) {
- cur_kstat = kstat_data_lookup_wrapper( arcstats, "size" );
- spl->zfs.size = cur_kstat->value.ui64 / 1024;
- spl->zfs.enabled = spl->zfs.size > 0 ? 1 : 0;
-
- cur_kstat = kstat_data_lookup_wrapper( arcstats, "c_max" );
- spl->zfs.max = cur_kstat->value.ui64 / 1024;
-
- cur_kstat = kstat_data_lookup_wrapper( arcstats, "mfu_size" );
- spl->zfs.MFU = cur_kstat != NULL ? cur_kstat->value.ui64 / 1024 : 0;
-
- cur_kstat = kstat_data_lookup_wrapper( arcstats, "mru_size" );
- spl->zfs.MRU = cur_kstat != NULL ? cur_kstat->value.ui64 / 1024 : 0;
-
- cur_kstat = kstat_data_lookup_wrapper( arcstats, "anon_size" );
- spl->zfs.anon = cur_kstat != NULL ? cur_kstat->value.ui64 / 1024 : 0;
-
- cur_kstat = kstat_data_lookup_wrapper( arcstats, "hdr_size" );
- spl->zfs.header = cur_kstat != NULL ? cur_kstat->value.ui64 / 1024 : 0;
-
- cur_kstat = kstat_data_lookup_wrapper( arcstats, "other_size" );
- spl->zfs.other = cur_kstat != NULL ? cur_kstat->value.ui64 / 1024 : 0;
-
- if ((cur_kstat = kstat_data_lookup_wrapper( arcstats, "compressed_size" )) != NULL) {
- spl->zfs.compressed = cur_kstat->value.ui64 / 1024;
- spl->zfs.isCompressed = 1;
-
- cur_kstat = kstat_data_lookup_wrapper( arcstats, "uncompressed_size" );
- spl->zfs.uncompressed = cur_kstat->value.ui64 / 1024;
- } else {
- spl->zfs.isCompressed = 0;
- }
- }
-}
-
void ProcessList_delete(ProcessList* pl) {
SolarisProcessList* spl = (SolarisProcessList*) pl;
ProcessList_done(pl);
- free(spl->cpus);
- if (spl->kd) {
- kstat_close(spl->kd);
- }
free(spl);
}
@@ -392,7 +111,7 @@ static int SolarisProcessList_walkproc(psinfo_t* _psinfo, lwpsinfo_t* _lwpsinfo,
// Setup process list
ProcessList* pl = (ProcessList*) listptr;
SolarisProcessList* spl = (SolarisProcessList*) listptr;
- Machine* host = pl->super.host;
+ Machine* host = pl->host;
id_t lwpid_real = _lwpsinfo->pr_lwpid;
if (lwpid_real > 1023) {
@@ -407,8 +126,9 @@ static int SolarisProcessList_walkproc(psinfo_t* _psinfo, lwpsinfo_t* _lwpsinfo,
getpid = lwpid;
}
- Process* proc = ProcessList_getProcess(pl, getpid, &preExisting, SolarisProcess_new);
- SolarisProcess* sproc = (SolarisProcess*) proc;
+ Process* proc = ProcessList_getProcess(pl, getpid, &preExisting, SolarisProcess_new);
+ SolarisProcess* sproc = (SolarisProcess*) proc;
+ const Settings* settings = host->settings;
// Common code pass 1
proc->show = false;
@@ -455,7 +175,7 @@ static int SolarisProcessList_walkproc(psinfo_t* _psinfo, lwpsinfo_t* _lwpsinfo,
Process_updateComm(proc, _psinfo->pr_fname);
Process_updateCmdline(proc, _psinfo->pr_psargs, 0, 0);
- if (proc->settings->ss->flags & PROCESS_FLAG_CWD) {
+ if (settings->ss->flags & PROCESS_FLAG_CWD) {
SolarisProcessList_updateCwd(_psinfo->pr_pid, proc);
}
}
@@ -479,7 +199,7 @@ static int SolarisProcessList_walkproc(psinfo_t* _psinfo, lwpsinfo_t* _lwpsinfo,
}
// Update proc and thread counts based on settings
- if (proc->isKernelThread && !pl->settings->hideKernelThreads) {
+ if (proc->isKernelThread && !settings->hideKernelThreads) {
pl->kernelThreads += proc->nlwp;
pl->totalTasks += proc->nlwp + 1;
if (proc->state == RUNNING) {
@@ -489,14 +209,14 @@ static int SolarisProcessList_walkproc(psinfo_t* _psinfo, lwpsinfo_t* _lwpsinfo,
if (proc->state == RUNNING) {
pl->runningTasks++;
}
- if (pl->settings->hideUserlandThreads) {
+ if (settings->hideUserlandThreads) {
pl->totalTasks++;
} else {
pl->userlandThreads += proc->nlwp;
pl->totalTasks += proc->nlwp + 1;
}
}
- proc->show = !(pl->settings->hideKernelThreads && proc->isKernelThread);
+ proc->show = !(settings->hideKernelThreads && proc->isKernelThread);
} else { // We are not in the master LWP, so jump to the LWP handling code
proc->percent_cpu = ((uint16_t)_lwpsinfo->pr_pctcpu / (double)32768) * (double)100.0;
Process_updateCPUFieldWidths(proc->percent_cpu);
@@ -512,10 +232,10 @@ static int SolarisProcessList_walkproc(psinfo_t* _psinfo, lwpsinfo_t* _lwpsinfo,
}
// Top-level process only gets this for the representative LWP
- if (proc->isKernelThread && !pl->settings->hideKernelThreads) {
+ if (proc->isKernelThread && !settings->hideKernelThreads) {
proc->show = true;
}
- if (!proc->isKernelThread && !pl->settings->hideUserlandThreads) {
+ if (!proc->isKernelThread && !settings->hideUserlandThreads) {
proc->show = true;
}
} // Top-level LWP or subordinate LWP
@@ -540,35 +260,7 @@ static int SolarisProcessList_walkproc(psinfo_t* _psinfo, lwpsinfo_t* _lwpsinfo,
return 0;
}
-void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
- SolarisProcessList_updateCPUcount(super);
- SolarisProcessList_scanCPUTime(super);
- SolarisProcessList_scanMemoryInfo(super);
- SolarisProcessList_scanZfsArcstats(super);
-
- // in pause mode only gather global data for meters (CPU/memory/...)
- if (pauseProcessUpdate) {
- return;
- }
-
+void ProcessList_goThroughEntries(ProcessList* super) {
super->kernelThreads = 1;
proc_walk(&SolarisProcessList_walkproc, super, PR_WALK_LWP);
}
-
-Machine* Machine_new(UsersTable* usersTable, uid_t userId) {
- Machine* this = xCalloc(1, sizeof(Machine));
- Machine_init(this, usersTable, userId);
- return this;
-}
-
-void Machine_delete(Machine* host) {
- free(host);
-}
-
-bool Machine_isCPUonline(const Machine* host, unsigned int id) {
- assert(id < host->existingCPUs);
-
- const SolarisProcessList* spl = (const SolarisProcessList*) host->pl;
-
- return (super->host->existingCPUs == 1) ? true : spl->cpus[id + 1].online;
-}
diff --git a/solaris/SolarisProcessList.h b/solaris/SolarisProcessList.h
index 7cb64167..d8280117 100644
--- a/solaris/SolarisProcessList.h
+++ b/solaris/SolarisProcessList.h
@@ -18,7 +18,6 @@ in the source distribution for its full text.
#include <sys/resource.h>
#include <sys/sysconf.h>
#include <sys/sysinfo.h>
-#include <sys/swap.h>
#include "Hashtable.h"
#include "ProcessList.h"
@@ -26,44 +25,9 @@ in the source distribution for its full text.
#include "solaris/SolarisProcess.h"
-#include "zfs/ZfsArcStats.h"
-
-
-#define ZONE_ERRMSGLEN 1024
-extern char zone_errmsg[ZONE_ERRMSGLEN];
-
-typedef struct CPUData_ {
- double userPercent;
- double nicePercent;
- double systemPercent;
- double irqPercent;
- double idlePercent;
- double systemAllPercent;
- double frequency;
- uint64_t luser;
- uint64_t lkrnl;
- uint64_t lintr;
- uint64_t lidle;
- bool online;
-} CPUData;
typedef struct SolarisProcessList_ {
ProcessList super;
- kstat_ctl_t* kd;
- CPUData* cpus;
- ZfsArcStats zfs;
} SolarisProcessList;
-ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList);
-
-void ProcessList_delete(ProcessList* pl);
-
-void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
-
-Machine* Machine_new(UsersTable* usersTable, uid_t userId);
-
-bool Machine_isCPUonline(const Machine* host, unsigned int id);
-
-void Machine_delete(Machine* host);
-
#endif
diff --git a/unsupported/UnsupportedMachine.c b/unsupported/UnsupportedMachine.c
new file mode 100644
index 00000000..a6635acc
--- /dev/null
+++ b/unsupported/UnsupportedMachine.c
@@ -0,0 +1,56 @@
+/*
+htop - UnsupportedMachine.c
+(C) 2014 Hisham H. Muhammad
+Released under the GNU GPLv2+, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "UnsupportedMachine.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "Machine.h"
+
+
+Machine* Machine_new(UsersTable* usersTable, uid_t userId) {
+ UnsupportedMachine* this = xCalloc(1, sizeof(UnsupportedMachine));
+ Machine* super = &this->super;
+
+ Machine_init(super, usersTable, userId);
+
+ super->existingCPUs = 1;
+ super->activeCPUs = 1;
+
+ return super;
+}
+
+void Machine_delete(Machine* super) {
+ UnsupportedMachine* this = (UnsupportedMachine*) super;
+ Machine_done(super);
+ free(this);
+}
+
+bool Machine_isCPUonline(const Machine* host, unsigned int id) {
+ assert(id < host->existingCPUs);
+
+ (void) host; (void) id;
+
+ return true;
+}
+
+void Machine_scan(Machine* super) {
+ super->existingCPUs = 1;
+ super->activeCPUs = 1;
+
+ super->totalMem = 0;
+ super->usedMem = 0;
+ super->buffersMem = 0;
+ super->cachedMem = 0;
+ super->sharedMem = 0;
+ super->availableMem = 0;
+
+ super->totalSwap = 0;
+ super->usedSwap = 0;
+ super->cachedSwap = 0;
+}
diff --git a/unsupported/UnsupportedMachine.h b/unsupported/UnsupportedMachine.h
new file mode 100644
index 00000000..4ec760f1
--- /dev/null
+++ b/unsupported/UnsupportedMachine.h
@@ -0,0 +1,17 @@
+#ifndef HEADER_UnsupportedMachine
+#define HEADER_UnsupportedMachine
+/*
+htop - UnsupportedMachine.h
+(C) 2014 Hisham H. Muhammad
+Released under the GNU GPLv2+, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "Machine.h"
+
+
+typedef struct UnsupportedMachine_ {
+ Machine super;
+} UnsupportedMachine;
+
+#endif
diff --git a/unsupported/UnsupportedProcessList.c b/unsupported/UnsupportedProcessList.c
index e5b7af6d..e56f4978 100644
--- a/unsupported/UnsupportedProcessList.c
+++ b/unsupported/UnsupportedProcessList.c
@@ -16,10 +16,8 @@ in the source distribution for its full text.
ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList) {
ProcessList* this = xCalloc(1, sizeof(ProcessList));
- ProcessList_init(this, Class(Process), host, pidMatchList);
- host->existingCPUs = 1;
- host->activeCPUs = 1;
+ ProcessList_init(this, Class(Process), host, pidMatchList);
return this;
}
@@ -29,13 +27,7 @@ void ProcessList_delete(ProcessList* this) {
free(this);
}
-void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
-
- // in pause mode only gather global data for meters (CPU/memory/...)
- if (pauseProcessUpdate) {
- return;
- }
-
+void ProcessList_goThroughEntries(ProcessList* super) {
bool preExisting = true;
Process* proc;
@@ -51,7 +43,8 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
Process_updateCmdline(proc, "<unsupported architecture>", 0, 0);
Process_updateExe(proc, "/path/to/executable");
- if (proc->settings->ss->flags & PROCESS_FLAG_CWD) {
+ const Settings* settings = proc->host->settings;
+ if (settings->ss->flags & PROCESS_FLAG_CWD) {
free_and_xStrdup(&proc->procCwd, "/current/working/directory");
}
@@ -60,7 +53,7 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
proc->state = RUNNING;
proc->isKernelThread = false;
proc->isUserlandThread = false;
- proc->show = true; /* Reflected in proc->settings-> "hideXXX" really */
+ proc->show = true; /* Reflected in settings-> "hideXXX" really */
proc->pgrp = 0;
proc->session = 0;
proc->tty_nr = 0;
@@ -90,21 +83,3 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
if (!preExisting)
ProcessList_add(super, proc);
}
-
-Machine* Machine_new(UsersTable* usersTable, uid_t userId) {
- Machine* this = xCalloc(1, sizeof(Machine));
- Machine_init(this, usersTable, userId);
- return this;
-}
-
-void Machine_delete(Machine* host) {
- free(host);
-}
-
-bool Machine_isCPUonline(const Machine* host, unsigned int id) {
- assert(id < host->existingCPUs);
-
- (void) host; (void) id;
-
- return true;
-}
diff --git a/unsupported/UnsupportedProcessList.h b/unsupported/UnsupportedProcessList.h
index cdb0b601..96efdcd2 100644
--- a/unsupported/UnsupportedProcessList.h
+++ b/unsupported/UnsupportedProcessList.h
@@ -10,16 +10,8 @@ in the source distribution for its full text.
#include "ProcessList.h"
-ProcessList* ProcessList_new(Machine* host, Hashtable* pidMatchList);
-
-void ProcessList_delete(ProcessList* this);
-
-void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
-
-Machine* Machine_new(UsersTable* usersTable, uid_t userId);
-
-bool Machine_isCPUonline(const Machine* host, unsigned int id);
-
-void Machine_delete(Machine* host);
+typedef struct UnsupportedProcessList_ {
+ ProcessList super;
+} UnsupportedProcessList;
#endif

© 2014-2024 Faster IT GmbH | imprint | privacy policy