From bc84920b91f916532cdffd2fae5e31fdd37a017e Mon Sep 17 00:00:00 2001 From: "Martin \"eto\" Misuth" Date: Fri, 11 Dec 2015 11:01:24 +0100 Subject: [PATCH 1/6] added support for effective UID/username change detection --- freebsd/FreeBSDProcessList.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/freebsd/FreeBSDProcessList.c b/freebsd/FreeBSDProcessList.c index f1b7a191..ee84753c 100644 --- a/freebsd/FreeBSDProcessList.c +++ b/freebsd/FreeBSDProcessList.c @@ -224,6 +224,10 @@ void ProcessList_goThroughEntries(ProcessList* this) { free(fp->jname); fp->jname = FreeBSDProcessList_readJailName(kproc); } + if(proc->st_uid != kproc->ki_uid) { + proc->st_uid = kproc->ki_uid; + proc->user = UsersTable_getRef(this->usersTable, proc->st_uid); + } if (settings->updateProcessNames) { free(proc->comm); proc->comm = FreeBSDProcessList_readProcessName(fpl->kd, kproc, &proc->basenameOffset); From c2769985ccea4894a6fb9fbfa9588ef520e907db Mon Sep 17 00:00:00 2001 From: "Martin \"eto\" Misuth" Date: Sun, 13 Dec 2015 00:21:02 +0100 Subject: [PATCH 2/6] added cpu monitoring for both single core and smp systems, some notes in process monitor --- freebsd/FreeBSDProcessList.c | 173 +++++++++++++++++++++++++++++++---- freebsd/Platform.c | 36 +++++++- 2 files changed, 188 insertions(+), 21 deletions(-) diff --git a/freebsd/FreeBSDProcessList.c b/freebsd/FreeBSDProcessList.c index ee84753c..a8e1af09 100644 --- a/freebsd/FreeBSDProcessList.c +++ b/freebsd/FreeBSDProcessList.c @@ -23,13 +23,20 @@ in the source distribution for its full text. #include #include #include +#include #define JAIL_ERRMSGLEN 1024 char jail_errmsg[JAIL_ERRMSGLEN]; typedef struct CPUData_ { - unsigned long long int totalTime; - unsigned long long int totalPeriod; + + double userPercent; + double nicePercent; + double systemPercent; + double irqPercent; + double idlePercent; + double systemAllPercent; + } CPUData; typedef struct FreeBSDProcessList_ { @@ -38,6 +45,12 @@ typedef struct FreeBSDProcessList_ { CPUData* cpus; + unsigned long *cp_time_o; + unsigned long *cp_time_n; + + unsigned long *cp_times_o; + unsigned long *cp_times_n; + } FreeBSDProcessList; }*/ @@ -46,25 +59,17 @@ static int MIB_vm_stats_vm_v_wire_count[4]; static int MIB_vm_stats_vm_v_cache_count[4]; static int MIB_hw_physmem[2]; +static int MIB_kern_cp_time[2]; +static int MIB_kern_cp_times[2]; + static int pageSizeKb; + ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId) { FreeBSDProcessList* fpl = calloc(1, sizeof(FreeBSDProcessList)); ProcessList* pl = (ProcessList*) fpl; ProcessList_init(pl, Class(FreeBSDProcess), usersTable, pidWhiteList, userId); - int cpus = 1; - size_t sizeof_cpus = sizeof(cpus); - int err = sysctlbyname("hw.ncpu", &cpus, &sizeof_cpus, NULL, 0); - if (err) cpus = 1; - pl->cpuCount = MAX(cpus, 1); - fpl->cpus = realloc(fpl->cpus, cpus * sizeof(CPUData)); - - for (int i = 0; i < cpus; i++) { - fpl->cpus[i].totalTime = 1; - fpl->cpus[i].totalPeriod = 1; - } - size_t 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_cache_count", MIB_vm_stats_vm_v_cache_count, &len); @@ -74,6 +79,50 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui fpl->kd = kvm_open(NULL, "/dev/null", NULL, 0, NULL); assert(fpl->kd); + int smp = 0; + size_t sizeof_smp = sizeof(smp); + + if (sysctlbyname("kern.smp.active", &smp, &sizeof_smp, NULL, 0) != 0 || sizeof_smp != sizeof(smp)) { + smp = 0; + } + + int cpus = 1; + size_t sizeof_cpus = sizeof(cpus); + + if (smp) { + int err = sysctlbyname("kern.smp.cpus", &cpus, &sizeof_cpus, 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 = calloc(cpus, sizeof_cp_time_array); + fpl->cp_time_n = calloc(cpus, sizeof_cp_time_array); + len = sizeof_cp_time_array; + + // fetch intial 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 intial CPU's clicks + if (cpus > 1) { + len = 2; sysctlnametomib("kern.cp_times", MIB_kern_cp_times, &len); + fpl->cp_times_o = calloc(cpus, sizeof_cp_time_array); + fpl->cp_times_n = calloc(cpus, sizeof_cp_time_array); + len = cpus * sizeof_cp_time_array; + sysctl(MIB_kern_cp_times, 2, fpl->cp_times_o, &len, NULL, 0); + } + + pl->cpuCount = MAX(cpus, 1); + + if (cpus == 1 ) { + fpl->cpus = realloc(fpl->cpus, sizeof(CPUData)); + } else { + // on smp we need CPUs + 1 to store averages too (as kernel kindly provides that as well) + fpl->cpus = realloc(fpl->cpus, (pl->cpuCount + 1) * sizeof(CPUData)); + } + return pl; } @@ -81,10 +130,95 @@ void ProcessList_delete(ProcessList* this) { const FreeBSDProcessList* fpl = (FreeBSDProcessList*) this; if (fpl->kd) kvm_close(fpl->kd); + if (fpl->cp_time_o != NULL) free(fpl->cp_time_o); + if (fpl->cp_time_n != NULL) free(fpl->cp_time_n); + if (fpl->cp_times_o != NULL) free(fpl->cp_times_o); + if (fpl->cp_times_n != NULL) free(fpl->cp_times_n); + ProcessList_done(this); free(this); } +static inline void FreeBSDProcessList_scanCPUTime(ProcessList* pl) { + const FreeBSDProcessList* fpl = (FreeBSDProcessList*) pl; + + int cpus = pl->cpuCount; // actual CPU count + 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 long total_o = 0; + unsigned long long total_n = 0; + unsigned long long total_d = 0; + 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 (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 + 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, but we store it anyway + cpuData->idlePercent = cp_time_p[CP_IDLE]; + } +} + static inline void FreeBSDProcessList_scanMemoryInfo(ProcessList* pl) { const FreeBSDProcessList* fpl = (FreeBSDProcessList*) pl; @@ -186,6 +320,7 @@ void ProcessList_goThroughEntries(ProcessList* this) { bool hideUserlandThreads = settings->hideUserlandThreads; FreeBSDProcessList_scanMemoryInfo(this); + FreeBSDProcessList_scanCPUTime(this); int count = 0; struct kinfo_proc* kprocs = kvm_getprocs(fpl->kd, KERN_PROC_ALL, 0, &count); @@ -199,7 +334,6 @@ void ProcessList_goThroughEntries(ProcessList* this) { proc->show = ! ((hideKernelThreads && Process_isKernelThread(fp)) || (hideUserlandThreads && Process_isUserlandThread(proc))); - if (!preExisting) { fp->jid = kproc->ki_jid; proc->pid = kproc->ki_pid; @@ -220,11 +354,17 @@ void ProcessList_goThroughEntries(ProcessList* this) { fp->jname = FreeBSDProcessList_readJailName(kproc); } else { if(fp->jid != kproc->ki_jid) { + // proces can enter jail anytime fp->jid = kproc->ki_jid; free(fp->jname); fp->jname = FreeBSDProcessList_readJailName(kproc); } + if (proc->ppid != kproc->ki_ppid) { + // if there are reapers in the system, proces can get reparented anytime + proc->ppid = kproc->ki_ppid; + } if(proc->st_uid != kproc->ki_uid) { + // some proceses change users (eg. to lower privs) proc->st_uid = kproc->ki_uid; proc->user = UsersTable_getRef(this->usersTable, proc->st_uid); } @@ -234,8 +374,6 @@ void ProcessList_goThroughEntries(ProcessList* this) { } } - proc->ppid = kproc->ki_ppid; - proc->m_size = kproc->ki_size / pageSizeKb / 1000; proc->m_resident = kproc->ki_rssize; // * pageSizeKb; proc->nlwp = kproc->ki_numthreads; @@ -253,7 +391,6 @@ void ProcessList_goThroughEntries(ProcessList* this) { proc->nice = PRIO_MAX + 1 + kproc->ki_pri.pri_level - PRI_MIN_IDLE; } - switch (kproc->ki_stat) { case SIDL: proc->state = 'I'; break; case SRUN: proc->state = 'R'; break; diff --git a/freebsd/Platform.c b/freebsd/Platform.c index b1703291..60b7586c 100644 --- a/freebsd/Platform.c +++ b/freebsd/Platform.c @@ -16,6 +16,7 @@ in the source distribution for its full text. #include "ClockMeter.h" #include "HostnameMeter.h" #include "FreeBSDProcess.h" +#include "FreeBSDProcessList.h" #include #include @@ -105,7 +106,7 @@ int Platform_getUptime() { struct timeval bootTime, currTime; int mib[2] = { CTL_KERN, KERN_BOOTTIME }; size_t size = sizeof(bootTime); - + int err = sysctl(mib, 2, &bootTime, &size, NULL, 0); if (err) { return -1; @@ -119,7 +120,7 @@ void Platform_getLoadAverage(double* one, double* five, double* fifteen) { struct loadavg loadAverage; int mib[2] = { CTL_VM, VM_LOADAVG }; size_t size = sizeof(loadAverage); - + int err = sysctl(mib, 2, &loadAverage, &size, NULL, 0); if (err) { *one = 0; @@ -143,7 +144,36 @@ int Platform_getMaxPid() { } double Platform_setCPUValues(Meter* this, int cpu) { - // TODO + FreeBSDProcessList* fpl = (FreeBSDProcessList*) this->pl; + int cpus = this->pl->cpuCount; + CPUData* cpuData; + + if (cpus == 1) { + // single CPU box has everything in fpl->cpus[0] + cpuData = &(fpl->cpus[0]); + } else { + cpuData = &(fpl->cpus[cpu]); + } + + double percent; + double* v = this->values; + + v[CPU_METER_NICE] = cpuData->nicePercent; + v[CPU_METER_NORMAL] = cpuData->userPercent; + if (this->pl->settings->detailedCPUTime) { + v[CPU_METER_KERNEL] = cpuData->systemPercent; + v[CPU_METER_IRQ] = cpuData->irqPercent; + Meter_setItems(this, 4); + percent = v[0]+v[1]+v[2]+v[3]; + } else { + v[2] = cpuData->systemAllPercent; + Meter_setItems(this, 3); + percent = v[0]+v[1]+v[2]; + } + + percent = MIN(100.0, MAX(0.0, percent)); + if (isnan(percent)) percent = 0.0; + return percent; } void Platform_setMemoryValues(Meter* this) { From 80f594f3145eea6345657be1a86d208b9401341b Mon Sep 17 00:00:00 2001 From: "Martin \"eto\" Misuth" Date: Sun, 13 Dec 2015 01:39:54 +0100 Subject: [PATCH 3/6] added CPU% for processes in process list --- freebsd/FreeBSDProcessList.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/freebsd/FreeBSDProcessList.c b/freebsd/FreeBSDProcessList.c index a8e1af09..4531a7b1 100644 --- a/freebsd/FreeBSDProcessList.c +++ b/freebsd/FreeBSDProcessList.c @@ -63,7 +63,7 @@ static int MIB_kern_cp_time[2]; static int MIB_kern_cp_times[2]; static int pageSizeKb; - +static int kernelFScale; ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId) { FreeBSDProcessList* fpl = calloc(1, sizeof(FreeBSDProcessList)); @@ -79,6 +79,12 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui fpl->kd = kvm_open(NULL, "/dev/null", NULL, 0, NULL); assert(fpl->kd); + size_t sizeof_kernelFScale = sizeof(kernelFScale); + if (sysctlbyname("kern.fscale", &kernelFScale, &sizeof_kernelFScale, NULL, 0) == -1) { + //sane default on x86 machines, in case this sysctl call failed + kernelFScale = 2048; + } + int smp = 0; size_t sizeof_smp = sizeof(smp); @@ -322,6 +328,7 @@ void ProcessList_goThroughEntries(ProcessList* this) { FreeBSDProcessList_scanMemoryInfo(this); FreeBSDProcessList_scanCPUTime(this); + int cpus = this->cpuCount; int count = 0; struct kinfo_proc* kprocs = kvm_getprocs(fpl->kd, KERN_PROC_ALL, 0, &count); @@ -379,6 +386,15 @@ void ProcessList_goThroughEntries(ProcessList* this) { proc->nlwp = kproc->ki_numthreads; proc->time = (kproc->ki_runtime + 5000) / 10000; + proc->percent_cpu = 100.0 * ((double)kproc->ki_pctcpu / (double)kernelFScale); + if (cpus > 1 ) { + proc->percent_cpu = proc->percent_cpu / (double) cpus; + } + if (proc->percent_cpu >= 99.8) { + // don't break formatting + proc->percent_cpu = 99.8; + } + proc->priority = kproc->ki_pri.pri_level - PZERO; if (strcmp("intr", kproc->ki_comm) == 0 && kproc->ki_flag & P_SYSTEM) { From 9d55c56f268d8c08423ccdcb19c0fd9049eca3c0 Mon Sep 17 00:00:00 2001 From: "Martin \"eto\" Misuth" Date: Sun, 13 Dec 2015 04:11:35 +0100 Subject: [PATCH 4/6] added Support for memory meter, and slightly adjusted process monitor logic --- freebsd/FreeBSDProcessList.c | 162 ++++++++++++++++++++++++++++------- freebsd/Platform.c | 6 ++ 2 files changed, 137 insertions(+), 31 deletions(-) diff --git a/freebsd/FreeBSDProcessList.c b/freebsd/FreeBSDProcessList.c index 4531a7b1..9ace433a 100644 --- a/freebsd/FreeBSDProcessList.c +++ b/freebsd/FreeBSDProcessList.c @@ -43,6 +43,15 @@ typedef struct FreeBSDProcessList_ { ProcessList super; kvm_t* kd; + int zfsArcEnabled; + + unsigned long long int memWire; + unsigned long long int memActive; + unsigned long long int memInactive; + unsigned long long int memFree; + unsigned long long int memZfsArc; + + CPUData* cpus; unsigned long *cp_time_o; @@ -55,48 +64,81 @@ typedef struct FreeBSDProcessList_ { }*/ -static int MIB_vm_stats_vm_v_wire_count[4]; -static int MIB_vm_stats_vm_v_cache_count[4]; + 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_kstat_zfs_misc_arcstats_size[5]; static int MIB_kern_cp_time[2]; static int MIB_kern_cp_times[2]; - -static int pageSizeKb; static int kernelFScale; + ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId) { FreeBSDProcessList* fpl = calloc(1, sizeof(FreeBSDProcessList)); ProcessList* pl = (ProcessList*) fpl; ProcessList_init(pl, Class(FreeBSDProcess), usersTable, pidWhiteList, userId); size_t 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_cache_count", MIB_vm_stats_vm_v_cache_count, &len); - len = 2; sysctlnametomib("hw.physmem", MIB_hw_physmem, &len); - pageSizeKb = PAGE_SIZE_KB; - fpl->kd = kvm_open(NULL, "/dev/null", NULL, 0, NULL); - assert(fpl->kd); + // 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); - size_t sizeof_kernelFScale = sizeof(kernelFScale); - if (sysctlbyname("kern.fscale", &kernelFScale, &sizeof_kernelFScale, NULL, 0) == -1) { - //sane default on x86 machines, in case this sysctl call failed - kernelFScale = 2048; + len = sizeof(pageSize); + if (sysctlbyname("vm.stats.vm.v_page_size", &pageSize, &len, NULL, 0) == -1) { + pageSize = PAGE_SIZE; + pageSizeKb = PAGE_SIZE_KB; + } else { + pageSizeKb = pageSize / ONE_K; } - int smp = 0; - size_t sizeof_smp = sizeof(smp); + // 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); - if (sysctlbyname("kern.smp.active", &smp, &sizeof_smp, NULL, 0) != 0 || sizeof_smp != sizeof(smp)) { + 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); + + len = sizeof(fpl->memZfsArc); + if (sysctlbyname("kstat.zfs.misc.arcstats.size", &fpl->memZfsArc, &len, + NULL, 0) == 0 && fpl->memZfsArc != 0) { + sysctlnametomib("kstat.zfs.misc.arcstats.size", MIB_kstat_zfs_misc_arcstats_size, &len); + fpl->zfsArcEnabled = 1; + } else { + fpl->zfsArcEnabled = 0; + } + + + int smp = 0; + len = sizeof(smp); + + if (sysctlbyname("kern.smp.active", &smp, &len, NULL, 0) != 0 || len != sizeof(smp)) { smp = 0; } int cpus = 1; - size_t sizeof_cpus = sizeof(cpus); + len = sizeof(cpus); if (smp) { - int err = sysctlbyname("kern.smp.cpus", &cpus, &sizeof_cpus, NULL, 0); + int err = sysctlbyname("kern.smp.cpus", &cpus, &len, NULL, 0); if (err) cpus = 1; } else { cpus = 1; @@ -129,6 +171,16 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui fpl->cpus = realloc(fpl->cpus, (pl->cpuCount + 1) * sizeof(CPUData)); } + + len = sizeof(kernelFScale); + if (sysctlbyname("kern.fscale", &kernelFScale, &len, NULL, 0) == -1) { + //sane default for kernel provded CPU precentage scaling, at least on x86 machines, in case this sysctl call failed + kernelFScale = 2048; + } + + fpl->kd = kvm_open(NULL, "/dev/null", NULL, 0, NULL); + assert(fpl->kd); + return pl; } @@ -226,17 +278,59 @@ static inline void FreeBSDProcessList_scanCPUTime(ProcessList* pl) { } static inline void FreeBSDProcessList_scanMemoryInfo(ProcessList* pl) { - const FreeBSDProcessList* fpl = (FreeBSDProcessList*) pl; + FreeBSDProcessList* fpl = (FreeBSDProcessList*) 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 + // + // 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 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_wire_count, 4, &(pl->usedMem), &len, NULL, 0); - pl->usedMem *= pageSizeKb; - pl->freeMem = pl->totalMem - pl->usedMem; + + sysctl(MIB_vm_stats_vm_v_active_count, 4, &(fpl->memActive), &len, NULL, 0); + fpl->memActive *= pageSizeKb; + + sysctl(MIB_vm_stats_vm_v_wire_count, 4, &(fpl->memWire), &len, NULL, 0); + fpl->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; + if (fpl->zfsArcEnabled) { + len = sizeof(fpl->memZfsArc); + sysctl(MIB_kstat_zfs_misc_arcstats_size, 5, &(fpl->memZfsArc), &len , NULL, 0); + fpl->memZfsArc /= 1024; + fpl->memWire -= fpl->memZfsArc; + pl->cachedMem += fpl->memZfsArc; + // maybe when we learn how to make custom memory meter + // we could do custom arc breakdown? + } + + pl->usedMem = fpl->memActive + fpl->memWire; + + //currently unused, same as with arc, custom meter perhaps + //sysctl(MIB_vm_stats_vm_v_inactive_count, 4, &(fpl->memInactive), &len, NULL, 0); + //sysctl(MIB_vm_stats_vm_v_free_count, 4, &(fpl->memFree), &len, NULL, 0); + //pl->freeMem = fpl->memInactive + fpl->memFree; + //pl->freeMem *= pageSizeKb; + struct kvm_swap swap[16]; int nswap = kvm_getswapinfo(fpl->kd, swap, sizeof(swap)/sizeof(swap[0]), 0); pl->totalSwap = 0; @@ -249,7 +343,6 @@ static inline void FreeBSDProcessList_scanMemoryInfo(ProcessList* pl) { pl->usedSwap *= pageSizeKb; pl->sharedMem = 0; // currently unused - pl->buffersMem = 0; // not exposed to userspace } char* FreeBSDProcessList_readProcessName(kvm_t* kd, struct kinfo_proc* kproc, int* basenameEnd) { @@ -334,8 +427,8 @@ void ProcessList_goThroughEntries(ProcessList* this) { for (int i = 0; i < count; i++) { struct kinfo_proc* kproc = &kprocs[i]; - bool preExisting = false; + bool isIdleProcess = false; Process* proc = ProcessList_getProcess(this, kproc->ki_pid, &preExisting, (Process_New) FreeBSDProcess_new); FreeBSDProcess* fp = (FreeBSDProcess*) proc; @@ -381,16 +474,23 @@ void ProcessList_goThroughEntries(ProcessList* this) { } } - proc->m_size = kproc->ki_size / pageSizeKb / 1000; - proc->m_resident = kproc->ki_rssize; // * pageSizeKb; + // from FreeBSD source /src/usr.bin/top/machine.c + proc->m_size = kproc->ki_size / 1024; + proc->m_resident = kproc->ki_rssize * pageSizeKb; proc->nlwp = kproc->ki_numthreads; proc->time = (kproc->ki_runtime + 5000) / 10000; proc->percent_cpu = 100.0 * ((double)kproc->ki_pctcpu / (double)kernelFScale); - if (cpus > 1 ) { - proc->percent_cpu = proc->percent_cpu / (double) cpus; + if (proc->percent_cpu > 0.1) { + // system idle process should own all CPU time left regardless of CPU count + if ( strcmp("idle", kproc->ki_comm) == 0 ) { + isIdleProcess = true; + } else { + if (cpus > 1) + proc->percent_cpu = proc->percent_cpu / (double) cpus; + } } - if (proc->percent_cpu >= 99.8) { + if (isIdleProcess == false && proc->percent_cpu >= 99.8) { // don't break formatting proc->percent_cpu = 99.8; } @@ -398,7 +498,7 @@ void ProcessList_goThroughEntries(ProcessList* this) { proc->priority = kproc->ki_pri.pri_level - PZERO; if (strcmp("intr", kproc->ki_comm) == 0 && kproc->ki_flag & P_SYSTEM) { - proc->nice = 0; //@etosan: freebsd intr kernel process (not thread) has weird nice value + proc->nice = 0; //@etosan: intr kernel process (not thread) has weird nice value } else if (kproc->ki_pri.pri_class == PRI_TIMESHARE) { proc->nice = kproc->ki_nice - NZERO; } else if (PRI_IS_REALTIME(kproc->ki_pri.pri_class)) { diff --git a/freebsd/Platform.c b/freebsd/Platform.c index 60b7586c..2dd15766 100644 --- a/freebsd/Platform.c +++ b/freebsd/Platform.c @@ -178,6 +178,12 @@ double Platform_setCPUValues(Meter* this, int cpu) { void Platform_setMemoryValues(Meter* this) { // TODO + ProcessList* pl = (ProcessList*) this->pl; + + this->total = pl->totalMem; + this->values[0] = pl->usedMem; + this->values[1] = pl->buffersMem; + this->values[2] = pl->cachedMem; } void Platform_setSwapValues(Meter* this) { From e0b6e2eef2f9a401419d06273681e4486d1b4484 Mon Sep 17 00:00:00 2001 From: "Martin \"eto\" Misuth" Date: Sun, 13 Dec 2015 04:16:06 +0100 Subject: [PATCH 5/6] enabled swap meter --- freebsd/Platform.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/freebsd/Platform.c b/freebsd/Platform.c index 2dd15766..a51b12bb 100644 --- a/freebsd/Platform.c +++ b/freebsd/Platform.c @@ -187,7 +187,9 @@ void Platform_setMemoryValues(Meter* this) { } void Platform_setSwapValues(Meter* this) { - // TODO + ProcessList* pl = (ProcessList*) this->pl; + this->total = pl->totalSwap; + this->values[0] = pl->usedSwap; } void Platform_setTasksValues(Meter* this) { From c67e482c67b4e4a99adb95fe35945204037a0c77 Mon Sep 17 00:00:00 2001 From: "Martin \"eto\" Misuth" Date: Thu, 17 Dec 2015 08:48:53 +0100 Subject: [PATCH 6/6] fixed bug with PPID of parent not being set on first process list scan pass. this caused htop to show processes as if freebsd kernel was their parent. on next pass reparenting code took chance to run, and that caused process to jump around. this fixed behaviour should be the correct one --- freebsd/FreeBSDProcessList.c | 1 + 1 file changed, 1 insertion(+) diff --git a/freebsd/FreeBSDProcessList.c b/freebsd/FreeBSDProcessList.c index 9ace433a..e8d6f137 100644 --- a/freebsd/FreeBSDProcessList.c +++ b/freebsd/FreeBSDProcessList.c @@ -441,6 +441,7 @@ void ProcessList_goThroughEntries(ProcessList* this) { fp->kernel = 1; else fp->kernel = 0; + proc->ppid = kproc->ki_ppid; proc->tpgid = kproc->ki_tpgid; proc->tgid = kproc->ki_pid; proc->session = kproc->ki_sid;