2018-03-02 21:20:46 +00:00
|
|
|
/*
|
|
|
|
htop - SolarisProcessList.c
|
|
|
|
(C) 2014 Hisham H. Muhammad
|
2018-03-05 21:52:03 +00:00
|
|
|
(C) 2017,2018 Guy M. Broome
|
2021-09-22 09:33:00 +00:00
|
|
|
Released under the GNU GPLv2+, see the COPYING file
|
2018-03-02 21:20:46 +00:00
|
|
|
in the source distribution for its full text.
|
|
|
|
*/
|
|
|
|
|
2021-04-29 18:13:36 +00:00
|
|
|
|
|
|
|
#include "solaris/SolarisProcessList.h"
|
2018-03-02 21:20:46 +00:00
|
|
|
|
|
|
|
#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>
|
|
|
|
|
2020-10-15 20:37:02 +00:00
|
|
|
#include "CRT.h"
|
2021-05-19 17:01:30 +00:00
|
|
|
#include "solaris/Platform.h"
|
2021-04-29 18:13:36 +00:00
|
|
|
#include "solaris/SolarisProcess.h"
|
2020-10-15 20:37:02 +00:00
|
|
|
|
2021-04-29 15:12:43 +00:00
|
|
|
|
2021-07-04 17:34:03 +00:00
|
|
|
#define GZONE "global "
|
|
|
|
#define UZONE "unknown "
|
|
|
|
|
2020-12-10 00:57:48 +00:00
|
|
|
static int pageSize;
|
|
|
|
static int pageSizeKB;
|
|
|
|
|
2021-05-19 17:09:57 +00:00
|
|
|
static char* SolarisProcessList_readZoneName(kstat_ctl_t* kd, SolarisProcess* sproc) {
|
2020-10-31 21:14:27 +00:00
|
|
|
char* zname;
|
|
|
|
|
|
|
|
if ( sproc->zoneid == 0 ) {
|
|
|
|
zname = xStrdup(GZONE);
|
|
|
|
} else if ( kd == NULL ) {
|
|
|
|
zname = xStrdup(UZONE);
|
|
|
|
} else {
|
2021-05-19 17:00:44 +00:00
|
|
|
kstat_t* ks = kstat_lookup_wrapper( kd, "zones", sproc->zoneid, NULL );
|
2020-10-31 21:14:27 +00:00
|
|
|
zname = xStrdup(ks == NULL ? UZONE : ks->ks_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
return zname;
|
2018-03-02 21:20:46 +00:00
|
|
|
}
|
|
|
|
|
2021-06-13 10:22:00 +00:00
|
|
|
static void SolarisProcessList_updateCPUcount(ProcessList* super) {
|
|
|
|
SolarisProcessList* spl = (SolarisProcessList*) super;
|
|
|
|
long int s;
|
|
|
|
bool change = false;
|
|
|
|
|
|
|
|
s = sysconf(_SC_NPROCESSORS_CONF);
|
|
|
|
if (s < 1)
|
2021-08-08 13:10:34 +00:00
|
|
|
CRT_fatalError("Cannot get existing CPU count by sysconf(_SC_NPROCESSORS_CONF)");
|
2021-06-13 10:22:00 +00:00
|
|
|
|
|
|
|
if (s != super->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));
|
2021-08-10 14:58:35 +00:00
|
|
|
spl->cpus[0].online = true; /* average is always "online" */
|
|
|
|
for (int i = 1; i < s + 1; i++) {
|
2021-06-13 10:22:00 +00:00
|
|
|
spl->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;
|
|
|
|
super->activeCPUs = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (change) {
|
|
|
|
kstat_close(spl->kd);
|
|
|
|
spl->kd = kstat_open();
|
|
|
|
if (!spl->kd)
|
|
|
|
CRT_fatalError("Cannot open kstat handle");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
PCP: support for 'dynamic columns' added at runtime
Implements support for arbitrary Performance Co-Pilot
metrics with per-process instance domains to form new
htop columns. The column-to-metric mappings are setup
using configuration files which will be documented via
man pages as part of a follow-up commit.
We provide an initial set of column configurations so
as to provide new capabilities to pcp-htop: including
configs for containers, open fd counts, scheduler run
queue time, tcp/udp bytes/calls sent/recv, delay acct,
virtual machine guests, detailed virtual memory, swap.
Note there is a change to the configuration file path
resolution algorithm introduced for 'dynamic meters'.
First, look in any custom PCP_HTOP_DIR location. Then
iterate, in priority order, users home directory, then
local sysadmins files in /etc/pcp/htop, then readonly
configuration files below /usr/share/pcp/htop. This
final location becomes the preferred place for our own
shipped meter and column files.
The Settings file (htoprc) writing code is updated to
not using the numeric identifier for dynamic columns.
The same strategy used for dynamic meters is used here
where we write Dynamic(name) so the name can be setup
once more at start. Regular (static) columns writing
to htoprc - i.e. numerically indexed - is unchanged.
2021-07-11 01:11:29 +00:00
|
|
|
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* dynamicColumns, Hashtable* pidMatchList, uid_t userId) {
|
2018-03-02 21:20:46 +00:00
|
|
|
SolarisProcessList* spl = xCalloc(1, sizeof(SolarisProcessList));
|
|
|
|
ProcessList* pl = (ProcessList*) spl;
|
PCP: support for 'dynamic columns' added at runtime
Implements support for arbitrary Performance Co-Pilot
metrics with per-process instance domains to form new
htop columns. The column-to-metric mappings are setup
using configuration files which will be documented via
man pages as part of a follow-up commit.
We provide an initial set of column configurations so
as to provide new capabilities to pcp-htop: including
configs for containers, open fd counts, scheduler run
queue time, tcp/udp bytes/calls sent/recv, delay acct,
virtual machine guests, detailed virtual memory, swap.
Note there is a change to the configuration file path
resolution algorithm introduced for 'dynamic meters'.
First, look in any custom PCP_HTOP_DIR location. Then
iterate, in priority order, users home directory, then
local sysadmins files in /etc/pcp/htop, then readonly
configuration files below /usr/share/pcp/htop. This
final location becomes the preferred place for our own
shipped meter and column files.
The Settings file (htoprc) writing code is updated to
not using the numeric identifier for dynamic columns.
The same strategy used for dynamic meters is used here
where we write Dynamic(name) so the name can be setup
once more at start. Regular (static) columns writing
to htoprc - i.e. numerically indexed - is unchanged.
2021-07-11 01:11:29 +00:00
|
|
|
ProcessList_init(pl, Class(SolarisProcess), usersTable, dynamicMeters, dynamicColumns, pidMatchList, userId);
|
2018-03-02 21:20:46 +00:00
|
|
|
|
|
|
|
spl->kd = kstat_open();
|
2021-06-13 10:22:00 +00:00
|
|
|
if (!spl->kd)
|
|
|
|
CRT_fatalError("Cannot open kstat handle");
|
2018-03-02 21:20:46 +00:00
|
|
|
|
2020-12-10 00:57:48 +00:00
|
|
|
pageSize = sysconf(_SC_PAGESIZE);
|
|
|
|
if (pageSize == -1)
|
|
|
|
CRT_fatalError("Cannot get pagesize by sysconf(_SC_PAGESIZE)");
|
|
|
|
pageSizeKB = pageSize / 1024;
|
2018-03-02 21:20:46 +00:00
|
|
|
|
2021-06-13 10:22:00 +00:00
|
|
|
SolarisProcessList_updateCPUcount(pl);
|
2018-03-02 21:20:46 +00:00
|
|
|
|
|
|
|
return pl;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void SolarisProcessList_scanCPUTime(ProcessList* pl) {
|
|
|
|
const SolarisProcessList* spl = (SolarisProcessList*) pl;
|
2021-06-13 10:22:00 +00:00
|
|
|
unsigned int activeCPUs = pl->activeCPUs;
|
|
|
|
unsigned int existingCPUs = pl->existingCPUs;
|
2020-10-31 22:28:02 +00:00
|
|
|
kstat_t* cpuinfo = NULL;
|
|
|
|
kstat_named_t* idletime = NULL;
|
|
|
|
kstat_named_t* intrtime = NULL;
|
|
|
|
kstat_named_t* krnltime = NULL;
|
|
|
|
kstat_named_t* usertime = NULL;
|
2020-12-24 13:01:23 +00:00
|
|
|
kstat_named_t* cpu_freq = NULL;
|
2018-03-02 21:20:46 +00:00
|
|
|
double idlebuf = 0;
|
|
|
|
double intrbuf = 0;
|
|
|
|
double krnlbuf = 0;
|
|
|
|
double userbuf = 0;
|
|
|
|
int arrskip = 0;
|
|
|
|
|
2021-06-13 10:22:00 +00:00
|
|
|
assert(existingCPUs > 0);
|
|
|
|
assert(spl->kd);
|
2018-03-02 21:20:46 +00:00
|
|
|
|
2021-06-13 10:22:00 +00:00
|
|
|
if (existingCPUs > 1) {
|
2020-10-31 21:14:27 +00:00
|
|
|
// Store values for the stats loop one extra element up in the array
|
|
|
|
// to leave room for the average to be calculated afterwards
|
|
|
|
arrskip++;
|
2018-03-02 21:20:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Calculate per-CPU statistics first
|
2021-06-13 10:22:00 +00:00
|
|
|
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");
|
2020-12-24 13:01:23 +00:00
|
|
|
}
|
2021-06-13 10:22:00 +00:00
|
|
|
} else {
|
|
|
|
cpuData->online = false;
|
|
|
|
continue;
|
2018-03-02 21:20:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
assert( (idletime != NULL) && (intrtime != NULL)
|
|
|
|
&& (krnltime != NULL) && (usertime != NULL) );
|
|
|
|
|
2020-12-24 13:01:23 +00:00
|
|
|
if (pl->settings->showCPUFrequency) {
|
2021-06-13 10:22:00 +00:00
|
|
|
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");
|
2020-12-24 13:01:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert( cpu_freq != NULL );
|
|
|
|
}
|
|
|
|
|
2020-11-21 23:47:32 +00:00
|
|
|
uint64_t totaltime = (idletime->value.ui64 - cpuData->lidle)
|
|
|
|
+ (intrtime->value.ui64 - cpuData->lintr)
|
|
|
|
+ (krnltime->value.ui64 - cpuData->lkrnl)
|
|
|
|
+ (usertime->value.ui64 - cpuData->luser);
|
|
|
|
|
2018-03-02 21:20:46 +00:00
|
|
|
// 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;
|
2020-12-24 13:01:23 +00:00
|
|
|
// Add frequency in MHz
|
|
|
|
cpuData->frequency = pl->settings->showCPUFrequency ? (double)cpu_freq->value.ui64 / 1E6 : NAN;
|
2018-03-02 21:20:46 +00:00
|
|
|
// Accumulate the current percentages into buffers for later average calculation
|
2021-06-13 10:22:00 +00:00
|
|
|
if (existingCPUs > 1) {
|
2018-03-02 21:20:46 +00:00
|
|
|
userbuf += cpuData->userPercent;
|
|
|
|
krnlbuf += cpuData->systemPercent;
|
|
|
|
intrbuf += cpuData->irqPercent;
|
|
|
|
idlebuf += cpuData->idlePercent;
|
|
|
|
}
|
|
|
|
}
|
2019-10-31 16:39:12 +00:00
|
|
|
|
2021-06-13 10:22:00 +00:00
|
|
|
if (existingCPUs > 1) {
|
2018-03-02 21:20:46 +00:00
|
|
|
CPUData* cpuData = &(spl->cpus[0]);
|
2021-06-13 10:22:00 +00:00
|
|
|
cpuData->userPercent = userbuf / activeCPUs;
|
2018-03-02 21:20:46 +00:00
|
|
|
cpuData->nicePercent = (double)0.0; // Not implemented on Solaris
|
2021-06-13 10:22:00 +00:00
|
|
|
cpuData->systemPercent = krnlbuf / activeCPUs;
|
|
|
|
cpuData->irqPercent = intrbuf / activeCPUs;
|
2018-03-02 21:20:46 +00:00
|
|
|
cpuData->systemAllPercent = cpuData->systemPercent + cpuData->irqPercent;
|
2021-06-13 10:22:00 +00:00
|
|
|
cpuData->idlePercent = idlebuf / activeCPUs;
|
2018-03-02 21:20:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void SolarisProcessList_scanMemoryInfo(ProcessList* pl) {
|
|
|
|
SolarisProcessList* spl = (SolarisProcessList*) pl;
|
2020-09-18 19:37:00 +00:00
|
|
|
static kstat_t *meminfo = NULL;
|
2018-03-27 20:18:29 +00:00
|
|
|
int ksrphyserr = -1;
|
2018-03-02 21:20:46 +00:00
|
|
|
kstat_named_t *totalmem_pgs = NULL;
|
2020-09-18 19:37:00 +00:00
|
|
|
kstat_named_t *freemem_pgs = NULL;
|
2018-03-02 21:20:46 +00:00
|
|
|
kstat_named_t *pages = NULL;
|
|
|
|
struct swaptable *sl = NULL;
|
|
|
|
struct swapent *swapdev = NULL;
|
|
|
|
uint64_t totalswap = 0;
|
|
|
|
uint64_t totalfree = 0;
|
|
|
|
int nswap = 0;
|
2019-10-31 16:39:12 +00:00
|
|
|
char *spath = NULL;
|
2018-03-30 18:34:12 +00:00
|
|
|
char *spathbase = NULL;
|
2018-03-02 21:20:46 +00:00
|
|
|
|
|
|
|
// Part 1 - physical memory
|
2020-09-18 19:37:00 +00:00
|
|
|
if (spl->kd != NULL && meminfo == NULL) {
|
2020-12-24 13:01:23 +00:00
|
|
|
// Look up the kstat chain just once, it never changes
|
2021-05-19 17:00:44 +00:00
|
|
|
meminfo = kstat_lookup_wrapper(spl->kd, "unix", 0, "system_pages");
|
2020-10-31 22:28:02 +00:00
|
|
|
}
|
|
|
|
if (meminfo != NULL) {
|
|
|
|
ksrphyserr = kstat_read(spl->kd, meminfo, NULL);
|
2020-09-18 19:37:00 +00:00
|
|
|
}
|
2018-03-02 21:20:46 +00:00
|
|
|
if (ksrphyserr != -1) {
|
2021-05-19 17:00:44 +00:00
|
|
|
totalmem_pgs = kstat_data_lookup_wrapper(meminfo, "physmem");
|
|
|
|
freemem_pgs = kstat_data_lookup_wrapper(meminfo, "freemem");
|
|
|
|
pages = kstat_data_lookup_wrapper(meminfo, "pagestotal");
|
2018-03-02 21:20:46 +00:00
|
|
|
|
2020-12-10 00:57:48 +00:00
|
|
|
pl->totalMem = totalmem_pgs->value.ui64 * pageSizeKB;
|
|
|
|
if (pl->totalMem > freemem_pgs->value.ui64 * pageSizeKB) {
|
|
|
|
pl->usedMem = pl->totalMem - freemem_pgs->value.ui64 * pageSizeKB;
|
2020-11-01 00:09:51 +00:00
|
|
|
} else {
|
|
|
|
pl->usedMem = 0; // This can happen in non-global zone (in theory)
|
|
|
|
}
|
2018-03-02 21:20:46 +00:00
|
|
|
// Not sure how to implement this on Solaris - suggestions welcome!
|
2019-10-31 16:39:12 +00:00
|
|
|
pl->cachedMem = 0;
|
2018-03-02 21:20:46 +00:00
|
|
|
// Not really "buffers" but the best Solaris analogue that I can find to
|
|
|
|
// "memory in use but not by programs or the kernel itself"
|
2020-12-10 00:57:48 +00:00
|
|
|
pl->buffersMem = (totalmem_pgs->value.ui64 - pages->value.ui64) * pageSizeKB;
|
2020-10-31 21:14:27 +00:00
|
|
|
} else {
|
2018-03-02 21:20:46 +00:00
|
|
|
// Fall back to basic sysconf if kstat isn't working
|
2020-12-10 00:57:48 +00:00
|
|
|
pl->totalMem = sysconf(_SC_PHYS_PAGES) * pageSize;
|
2018-03-02 21:20:46 +00:00
|
|
|
pl->buffersMem = 0;
|
|
|
|
pl->cachedMem = 0;
|
2020-12-10 00:57:48 +00:00
|
|
|
pl->usedMem = pl->totalMem - (sysconf(_SC_AVPHYS_PAGES) * pageSize);
|
2018-03-02 21:20:46 +00:00
|
|
|
}
|
2019-10-31 16:39:12 +00:00
|
|
|
|
2018-03-02 21:20:46 +00:00
|
|
|
// Part 2 - swap
|
|
|
|
nswap = swapctl(SC_GETNSWP, NULL);
|
2020-10-31 21:14:27 +00:00
|
|
|
if (nswap > 0) {
|
|
|
|
sl = xMalloc((nswap * sizeof(swapent_t)) + sizeof(int));
|
|
|
|
}
|
|
|
|
if (sl != NULL) {
|
|
|
|
spathbase = xMalloc( nswap * MAXPATHLEN );
|
|
|
|
}
|
2019-10-31 16:39:12 +00:00
|
|
|
if (spathbase != NULL) {
|
2018-03-30 18:34:12 +00:00
|
|
|
spath = spathbase;
|
2018-03-02 21:20:46 +00:00
|
|
|
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);
|
2019-10-31 16:39:12 +00:00
|
|
|
if (nswap > 0) {
|
2018-03-02 21:20:46 +00:00
|
|
|
swapdev = sl->swt_ent;
|
|
|
|
for (int i = 0; i < nswap; i++, swapdev++) {
|
|
|
|
totalswap += swapdev->ste_pages;
|
|
|
|
totalfree += swapdev->ste_free;
|
|
|
|
}
|
|
|
|
}
|
2018-03-30 18:34:12 +00:00
|
|
|
free(spathbase);
|
|
|
|
free(sl);
|
2020-12-10 00:57:48 +00:00
|
|
|
pl->totalSwap = totalswap * pageSizeKB;
|
|
|
|
pl->usedSwap = pl->totalSwap - (totalfree * pageSizeKB);
|
2018-03-02 21:20:46 +00:00
|
|
|
}
|
|
|
|
|
2019-07-08 02:43:39 +00:00
|
|
|
static inline void SolarisProcessList_scanZfsArcstats(ProcessList* pl) {
|
|
|
|
SolarisProcessList* spl = (SolarisProcessList*) pl;
|
|
|
|
kstat_t *arcstats = NULL;
|
|
|
|
int ksrphyserr = -1;
|
|
|
|
kstat_named_t *cur_kstat = NULL;
|
|
|
|
|
2020-10-31 21:14:27 +00:00
|
|
|
if (spl->kd != NULL) {
|
2021-05-19 17:00:44 +00:00
|
|
|
arcstats = kstat_lookup_wrapper(spl->kd, "zfs", 0, "arcstats");
|
2020-10-31 21:14:27 +00:00
|
|
|
}
|
|
|
|
if (arcstats != NULL) {
|
|
|
|
ksrphyserr = kstat_read(spl->kd, arcstats, NULL);
|
|
|
|
}
|
2019-07-08 02:43:39 +00:00
|
|
|
if (ksrphyserr != -1) {
|
2021-05-19 17:00:44 +00:00
|
|
|
cur_kstat = kstat_data_lookup_wrapper( arcstats, "size" );
|
2019-07-08 02:43:39 +00:00
|
|
|
spl->zfs.size = cur_kstat->value.ui64 / 1024;
|
|
|
|
spl->zfs.enabled = spl->zfs.size > 0 ? 1 : 0;
|
|
|
|
|
2021-05-19 17:00:44 +00:00
|
|
|
cur_kstat = kstat_data_lookup_wrapper( arcstats, "c_max" );
|
2019-07-08 02:43:39 +00:00
|
|
|
spl->zfs.max = cur_kstat->value.ui64 / 1024;
|
|
|
|
|
2021-05-19 17:00:44 +00:00
|
|
|
cur_kstat = kstat_data_lookup_wrapper( arcstats, "mfu_size" );
|
2020-09-18 19:13:51 +00:00
|
|
|
spl->zfs.MFU = cur_kstat != NULL ? cur_kstat->value.ui64 / 1024 : 0;
|
2019-07-08 02:43:39 +00:00
|
|
|
|
2021-05-19 17:00:44 +00:00
|
|
|
cur_kstat = kstat_data_lookup_wrapper( arcstats, "mru_size" );
|
2020-09-18 19:13:51 +00:00
|
|
|
spl->zfs.MRU = cur_kstat != NULL ? cur_kstat->value.ui64 / 1024 : 0;
|
2019-07-08 02:43:39 +00:00
|
|
|
|
2021-05-19 17:00:44 +00:00
|
|
|
cur_kstat = kstat_data_lookup_wrapper( arcstats, "anon_size" );
|
2020-09-18 19:13:51 +00:00
|
|
|
spl->zfs.anon = cur_kstat != NULL ? cur_kstat->value.ui64 / 1024 : 0;
|
2019-07-08 02:43:39 +00:00
|
|
|
|
2021-05-19 17:00:44 +00:00
|
|
|
cur_kstat = kstat_data_lookup_wrapper( arcstats, "hdr_size" );
|
2020-09-18 19:13:51 +00:00
|
|
|
spl->zfs.header = cur_kstat != NULL ? cur_kstat->value.ui64 / 1024 : 0;
|
2019-07-08 02:43:39 +00:00
|
|
|
|
2021-05-19 17:00:44 +00:00
|
|
|
cur_kstat = kstat_data_lookup_wrapper( arcstats, "other_size" );
|
2020-09-18 19:13:51 +00:00
|
|
|
spl->zfs.other = cur_kstat != NULL ? cur_kstat->value.ui64 / 1024 : 0;
|
2019-09-03 18:26:02 +00:00
|
|
|
|
2021-05-19 17:00:44 +00:00
|
|
|
if ((cur_kstat = kstat_data_lookup_wrapper( arcstats, "compressed_size" )) != NULL) {
|
2019-09-03 18:26:02 +00:00
|
|
|
spl->zfs.compressed = cur_kstat->value.ui64 / 1024;
|
|
|
|
spl->zfs.isCompressed = 1;
|
|
|
|
|
2021-05-19 17:00:44 +00:00
|
|
|
cur_kstat = kstat_data_lookup_wrapper( arcstats, "uncompressed_size" );
|
2019-09-03 18:26:02 +00:00
|
|
|
spl->zfs.uncompressed = cur_kstat->value.ui64 / 1024;
|
|
|
|
} else {
|
|
|
|
spl->zfs.isCompressed = 0;
|
|
|
|
}
|
2019-07-08 02:43:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-30 18:34:12 +00:00
|
|
|
void ProcessList_delete(ProcessList* pl) {
|
|
|
|
SolarisProcessList* spl = (SolarisProcessList*) pl;
|
|
|
|
ProcessList_done(pl);
|
2018-03-02 21:20:46 +00:00
|
|
|
free(spl->cpus);
|
2020-11-01 00:09:51 +00:00
|
|
|
if (spl->kd) {
|
|
|
|
kstat_close(spl->kd);
|
|
|
|
}
|
2018-03-30 18:34:12 +00:00
|
|
|
free(spl);
|
2018-03-02 21:20:46 +00:00
|
|
|
}
|
|
|
|
|
2021-05-19 15:43:38 +00:00
|
|
|
static void SolarisProcessList_updateExe(pid_t pid, Process* proc) {
|
|
|
|
char path[32];
|
|
|
|
xSnprintf(path, sizeof(path), "/proc/%d/path/a.out", pid);
|
|
|
|
|
|
|
|
char target[PATH_MAX];
|
|
|
|
ssize_t ret = readlink(path, target, sizeof(target) - 1);
|
|
|
|
if (ret <= 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
target[ret] = '\0';
|
|
|
|
Process_updateExe(proc, target);
|
|
|
|
}
|
|
|
|
|
2021-05-25 17:11:56 +00:00
|
|
|
static void SolarisProcessList_updateCwd(pid_t pid, Process* proc) {
|
|
|
|
char path[32];
|
|
|
|
xSnprintf(path, sizeof(path), "/proc/%d/cwd", pid);
|
|
|
|
|
|
|
|
char target[PATH_MAX];
|
|
|
|
ssize_t ret = readlink(path, target, sizeof(target) - 1);
|
|
|
|
if (ret <= 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
target[ret] = '\0';
|
|
|
|
free_and_xStrdup(&proc->procCwd, target);
|
|
|
|
}
|
|
|
|
|
2021-10-11 22:45:09 +00:00
|
|
|
/* Taken from: https://docs.oracle.com/cd/E19253-01/817-6223/6mlkidlom/index.html#tbl-sched-state */
|
|
|
|
static inline ProcessState SolarisProcessList_getProcessState(char state) {
|
|
|
|
switch (state) {
|
|
|
|
case 'S': return SLEEPING;
|
|
|
|
case 'R': return RUNNABLE;
|
|
|
|
case 'O': return RUNNING;
|
|
|
|
case 'Z': return ZOMBIE;
|
|
|
|
case 'T': return STOPPED;
|
|
|
|
case 'I': return IDLE;
|
|
|
|
default: return UNKNOWN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-28 20:04:49 +00:00
|
|
|
/* NOTE: the following is a callback function of type proc_walk_f
|
|
|
|
* and MUST conform to the appropriate definition in order
|
|
|
|
* to work. See libproc(3LIB) on a Solaris or Illumos
|
|
|
|
* system for more info.
|
2019-10-31 16:39:12 +00:00
|
|
|
*/
|
2018-03-28 20:04:49 +00:00
|
|
|
|
2021-05-19 17:09:57 +00:00
|
|
|
static int SolarisProcessList_walkproc(psinfo_t* _psinfo, lwpsinfo_t* _lwpsinfo, void* listptr) {
|
2018-03-28 19:54:36 +00:00
|
|
|
bool preExisting;
|
2018-03-30 18:34:12 +00:00
|
|
|
pid_t getpid;
|
2018-03-27 21:22:07 +00:00
|
|
|
|
2018-03-28 19:54:36 +00:00
|
|
|
// Setup process list
|
2020-10-31 22:28:02 +00:00
|
|
|
ProcessList* pl = (ProcessList*) listptr;
|
|
|
|
SolarisProcessList* spl = (SolarisProcessList*) listptr;
|
2018-03-28 19:54:36 +00:00
|
|
|
|
|
|
|
id_t lwpid_real = _lwpsinfo->pr_lwpid;
|
2020-11-01 00:09:51 +00:00
|
|
|
if (lwpid_real > 1023) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-03-30 18:34:12 +00:00
|
|
|
pid_t lwpid = (_psinfo->pr_pid * 1024) + lwpid_real;
|
2018-03-28 19:54:36 +00:00
|
|
|
bool onMasterLWP = (_lwpsinfo->pr_lwpid == _psinfo->pr_lwp.pr_lwpid);
|
|
|
|
if (onMasterLWP) {
|
2018-03-30 18:34:12 +00:00
|
|
|
getpid = _psinfo->pr_pid * 1024;
|
2018-03-28 19:54:36 +00:00
|
|
|
} else {
|
2018-03-30 18:34:12 +00:00
|
|
|
getpid = lwpid;
|
2019-10-31 16:39:12 +00:00
|
|
|
}
|
2021-04-10 12:08:26 +00:00
|
|
|
|
2020-10-31 22:28:02 +00:00
|
|
|
Process* proc = ProcessList_getProcess(pl, getpid, &preExisting, SolarisProcess_new);
|
|
|
|
SolarisProcess* sproc = (SolarisProcess*) proc;
|
2018-03-27 21:22:07 +00:00
|
|
|
|
2018-03-28 19:54:36 +00:00
|
|
|
// Common code pass 1
|
2018-03-30 18:34:12 +00:00
|
|
|
proc->show = false;
|
|
|
|
sproc->taskid = _psinfo->pr_taskid;
|
|
|
|
sproc->projid = _psinfo->pr_projid;
|
|
|
|
sproc->poolid = _psinfo->pr_poolid;
|
|
|
|
sproc->contid = _psinfo->pr_contract;
|
|
|
|
proc->priority = _lwpsinfo->pr_pri;
|
2020-09-05 05:29:15 +00:00
|
|
|
proc->nice = _lwpsinfo->pr_nice - NZERO;
|
2018-03-30 18:34:12 +00:00
|
|
|
proc->processor = _lwpsinfo->pr_onpro;
|
2021-10-11 22:45:09 +00:00
|
|
|
proc->state = SolarisProcessList_getProcessState(_lwpsinfo->pr_sname);
|
2018-03-28 19:54:36 +00:00
|
|
|
// NOTE: This 'percentage' is a 16-bit BINARY FRACTIONS where 1.0 = 0x8000
|
|
|
|
// Source: https://docs.oracle.com/cd/E19253-01/816-5174/proc-4/index.html
|
|
|
|
// (accessed on 18 November 2017)
|
2020-10-31 22:28:02 +00:00
|
|
|
proc->percent_mem = ((uint16_t)_psinfo->pr_pctmem / (double)32768) * (double)100.0;
|
2018-03-30 18:34:12 +00:00
|
|
|
proc->pgrp = _psinfo->pr_pgid;
|
|
|
|
proc->nlwp = _psinfo->pr_nlwp;
|
2021-05-20 15:54:17 +00:00
|
|
|
proc->session = _psinfo->pr_sid;
|
|
|
|
|
2018-03-30 18:34:12 +00:00
|
|
|
proc->tty_nr = _psinfo->pr_ttydev;
|
2021-05-20 15:54:17 +00:00
|
|
|
const char* name = (_psinfo->pr_ttydev != PRNODEV) ? ttyname(_psinfo->pr_ttydev) : NULL;
|
|
|
|
if (!name) {
|
|
|
|
free(proc->tty_name);
|
|
|
|
proc->tty_name = NULL;
|
|
|
|
} else {
|
|
|
|
free_and_xStrdup(&proc->tty_name, name);
|
|
|
|
}
|
|
|
|
|
2021-07-14 17:25:04 +00:00
|
|
|
proc->m_resident = _psinfo->pr_rssize; // KB
|
|
|
|
proc->m_virt = _psinfo->pr_size; // KB
|
2018-03-27 21:22:07 +00:00
|
|
|
|
2021-06-18 18:43:16 +00:00
|
|
|
if (proc->st_uid != _psinfo->pr_euid) {
|
|
|
|
proc->st_uid = _psinfo->pr_euid;
|
|
|
|
proc->user = UsersTable_getRef(pl->usersTable, proc->st_uid);
|
|
|
|
}
|
|
|
|
|
2018-03-28 19:54:36 +00:00
|
|
|
if (!preExisting) {
|
2018-03-30 18:34:12 +00:00
|
|
|
sproc->realpid = _psinfo->pr_pid;
|
|
|
|
sproc->lwpid = lwpid_real;
|
|
|
|
sproc->zoneid = _psinfo->pr_zoneid;
|
2020-10-31 22:28:02 +00:00
|
|
|
sproc->zname = SolarisProcessList_readZoneName(spl->kd, sproc);
|
2021-05-19 15:43:38 +00:00
|
|
|
SolarisProcessList_updateExe(_psinfo->pr_pid, proc);
|
2021-05-25 17:11:56 +00:00
|
|
|
|
2021-05-19 15:43:38 +00:00
|
|
|
Process_updateComm(proc, _psinfo->pr_fname);
|
|
|
|
Process_updateCmdline(proc, _psinfo->pr_psargs, 0, 0);
|
2021-05-25 17:11:56 +00:00
|
|
|
|
|
|
|
if (proc->settings->flags & PROCESS_FLAG_CWD) {
|
|
|
|
SolarisProcessList_updateCwd(_psinfo->pr_pid, proc);
|
|
|
|
}
|
2018-03-28 19:54:36 +00:00
|
|
|
}
|
2018-03-27 16:27:12 +00:00
|
|
|
|
2018-03-28 19:54:36 +00:00
|
|
|
// End common code pass 1
|
2018-03-02 21:20:46 +00:00
|
|
|
|
2018-03-28 19:54:36 +00:00
|
|
|
if (onMasterLWP) { // Are we on the representative LWP?
|
2018-03-28 16:48:37 +00:00
|
|
|
proc->ppid = (_psinfo->pr_ppid * 1024);
|
|
|
|
proc->tgid = (_psinfo->pr_ppid * 1024);
|
|
|
|
sproc->realppid = _psinfo->pr_ppid;
|
2021-05-20 15:54:17 +00:00
|
|
|
sproc->realtgid = _psinfo->pr_ppid;
|
2018-03-28 19:54:36 +00:00
|
|
|
// See note above (in common section) about this BINARY FRACTION
|
2020-10-31 22:28:02 +00:00
|
|
|
proc->percent_cpu = ((uint16_t)_psinfo->pr_pctcpu / (double)32768) * (double)100.0;
|
2018-03-28 16:48:37 +00:00
|
|
|
proc->time = _psinfo->pr_time.tv_sec;
|
2020-10-31 19:52:20 +00:00
|
|
|
if (!preExisting) { // Tasks done only for NEW processes
|
2021-04-10 12:08:26 +00:00
|
|
|
proc->isUserlandThread = false;
|
2018-03-28 16:48:37 +00:00
|
|
|
proc->starttime_ctime = _psinfo->pr_start.tv_sec;
|
2018-03-27 16:27:12 +00:00
|
|
|
}
|
2018-03-27 20:18:29 +00:00
|
|
|
|
2018-03-28 19:54:36 +00:00
|
|
|
// Update proc and thread counts based on settings
|
2021-04-10 12:08:26 +00:00
|
|
|
if (proc->isKernelThread && !pl->settings->hideKernelThreads) {
|
2018-03-28 16:48:37 +00:00
|
|
|
pl->kernelThreads += proc->nlwp;
|
2020-10-31 22:28:02 +00:00
|
|
|
pl->totalTasks += proc->nlwp + 1;
|
2021-10-11 22:45:09 +00:00
|
|
|
if (proc->state == RUNNING) {
|
2020-11-01 00:09:51 +00:00
|
|
|
pl->runningTasks++;
|
|
|
|
}
|
2021-04-10 12:08:26 +00:00
|
|
|
} else if (!proc->isKernelThread) {
|
2021-10-11 22:45:09 +00:00
|
|
|
if (proc->state == RUNNING) {
|
2020-11-01 00:09:51 +00:00
|
|
|
pl->runningTasks++;
|
|
|
|
}
|
2018-03-28 16:48:37 +00:00
|
|
|
if (pl->settings->hideUserlandThreads) {
|
|
|
|
pl->totalTasks++;
|
2018-03-02 21:20:46 +00:00
|
|
|
} else {
|
2018-03-28 16:48:37 +00:00
|
|
|
pl->userlandThreads += proc->nlwp;
|
2020-10-31 22:28:02 +00:00
|
|
|
pl->totalTasks += proc->nlwp + 1;
|
2018-03-02 21:20:46 +00:00
|
|
|
}
|
|
|
|
}
|
2021-04-10 12:08:26 +00:00
|
|
|
proc->show = !(pl->settings->hideKernelThreads && proc->isKernelThread);
|
2018-03-28 19:54:36 +00:00
|
|
|
} else { // We are not in the master LWP, so jump to the LWP handling code
|
2020-10-31 22:28:02 +00:00
|
|
|
proc->percent_cpu = ((uint16_t)_lwpsinfo->pr_pctcpu / (double)32768) * (double)100.0;
|
2018-03-30 18:34:12 +00:00
|
|
|
proc->time = _lwpsinfo->pr_time.tv_sec;
|
|
|
|
if (!preExisting) { // Tasks done only for NEW LWPs
|
2021-04-10 12:08:26 +00:00
|
|
|
proc->isUserlandThread = true;
|
2018-03-30 18:34:12 +00:00
|
|
|
proc->ppid = _psinfo->pr_pid * 1024;
|
|
|
|
proc->tgid = _psinfo->pr_pid * 1024;
|
|
|
|
sproc->realppid = _psinfo->pr_pid;
|
2021-05-20 15:54:17 +00:00
|
|
|
sproc->realtgid = _psinfo->pr_pid;
|
2018-03-30 18:34:12 +00:00
|
|
|
proc->starttime_ctime = _lwpsinfo->pr_start.tv_sec;
|
2018-03-28 19:54:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Top-level process only gets this for the representative LWP
|
2021-04-10 12:08:26 +00:00
|
|
|
if (proc->isKernelThread && !pl->settings->hideKernelThreads) {
|
2020-10-31 22:28:02 +00:00
|
|
|
proc->show = true;
|
|
|
|
}
|
2021-04-10 12:08:26 +00:00
|
|
|
if (!proc->isKernelThread && !pl->settings->hideUserlandThreads) {
|
2020-10-31 22:28:02 +00:00
|
|
|
proc->show = true;
|
|
|
|
}
|
2018-03-28 19:54:36 +00:00
|
|
|
} // Top-level LWP or subordinate LWP
|
|
|
|
|
|
|
|
// Common code pass 2
|
|
|
|
|
|
|
|
if (!preExisting) {
|
|
|
|
if ((sproc->realppid <= 0) && !(sproc->realpid <= 1)) {
|
2021-04-10 12:08:26 +00:00
|
|
|
proc->isKernelThread = true;
|
2018-03-28 19:54:36 +00:00
|
|
|
} else {
|
2021-04-10 12:08:26 +00:00
|
|
|
proc->isKernelThread = false;
|
2018-03-28 19:54:36 +00:00
|
|
|
}
|
2021-04-10 12:08:26 +00:00
|
|
|
|
2020-10-13 12:26:40 +00:00
|
|
|
Process_fillStarttimeBuffer(proc);
|
2018-03-30 18:34:12 +00:00
|
|
|
ProcessList_add(pl, proc);
|
2018-03-28 16:48:37 +00:00
|
|
|
}
|
2021-04-18 16:10:04 +00:00
|
|
|
|
2018-03-30 18:34:12 +00:00
|
|
|
proc->updated = true;
|
2018-03-28 19:54:36 +00:00
|
|
|
|
|
|
|
// End common code pass 2
|
|
|
|
|
2018-03-28 16:48:37 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2018-03-27 20:48:58 +00:00
|
|
|
|
2020-10-27 20:26:28 +00:00
|
|
|
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
|
2021-06-13 10:22:00 +00:00
|
|
|
SolarisProcessList_updateCPUcount(super);
|
2020-10-27 20:26:28 +00:00
|
|
|
SolarisProcessList_scanCPUTime(super);
|
|
|
|
SolarisProcessList_scanMemoryInfo(super);
|
|
|
|
SolarisProcessList_scanZfsArcstats(super);
|
2020-10-13 14:03:37 +00:00
|
|
|
|
|
|
|
// in pause mode only gather global data for meters (CPU/memory/...)
|
2020-11-01 00:09:51 +00:00
|
|
|
if (pauseProcessUpdate) {
|
2020-10-13 14:03:37 +00:00
|
|
|
return;
|
2020-11-01 00:09:51 +00:00
|
|
|
}
|
2020-10-13 14:03:37 +00:00
|
|
|
|
2020-10-27 20:26:28 +00:00
|
|
|
super->kernelThreads = 1;
|
|
|
|
proc_walk(&SolarisProcessList_walkproc, super, PR_WALK_LWP);
|
2018-03-02 21:20:46 +00:00
|
|
|
}
|
2021-06-12 20:04:37 +00:00
|
|
|
|
|
|
|
bool ProcessList_isCPUonline(const ProcessList* super, unsigned int id) {
|
|
|
|
assert(id < super->existingCPUs);
|
|
|
|
|
2021-06-13 10:22:00 +00:00
|
|
|
const SolarisProcessList* spl = (const SolarisProcessList*) super;
|
2021-06-12 20:04:37 +00:00
|
|
|
|
2021-06-13 10:22:00 +00:00
|
|
|
return (super->existingCPUs == 1) ? true : spl->cpus[id + 1].online;
|
2021-06-12 20:04:37 +00:00
|
|
|
}
|