From 10eea2ab1bae2a8ec159d81c0446fd8061b33e2b Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 15 Apr 2024 21:58:07 +0200 Subject: Adding upstream version 3.3.0. Signed-off-by: Daniel Baumann --- solaris/SolarisMachine.c | 336 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 336 insertions(+) create mode 100644 solaris/SolarisMachine.c (limited to 'solaris/SolarisMachine.c') diff --git a/solaris/SolarisMachine.c b/solaris/SolarisMachine.c new file mode 100644 index 0000000..4f740d3 --- /dev/null +++ b/solaris/SolarisMachine.c @@ -0,0 +1,336 @@ +/* +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 "config.h" // IWYU pragma: keep + +#include "solaris/SolarisMachine.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; + kstat_t *arcstats; + int ksrphyserr; + + if (this->kd == NULL) + return; + + arcstats = kstat_lookup_wrapper(this->kd, "zfs", 0, "arcstats"); + if (arcstats == NULL) + return; + + ksrphyserr = kstat_read(this->kd, arcstats, NULL); + if (ksrphyserr == -1) + return; + + 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; +} -- cgit v1.2.3