mirror of https://github.com/xzeldon/htop.git
Linux: Add PSS (proportional set size), Swap and SwapPSS calculation
Original code was written by *Craig M. Brandenburg* for htop 1.0.2 Many performance improvements by GitHub user *linvinus*, ported to htop 2.0.2
This commit is contained in:
parent
402e46bb82
commit
fc0bf546c3
|
@ -24,6 +24,7 @@ in the source distribution for its full text.
|
||||||
#define PROCESS_FLAG_LINUX_VSERVER 0x0400
|
#define PROCESS_FLAG_LINUX_VSERVER 0x0400
|
||||||
#define PROCESS_FLAG_LINUX_CGROUP 0x0800
|
#define PROCESS_FLAG_LINUX_CGROUP 0x0800
|
||||||
#define PROCESS_FLAG_LINUX_OOM 0x1000
|
#define PROCESS_FLAG_LINUX_OOM 0x1000
|
||||||
|
#define PROCESS_FLAG_LINUX_SMAPS 0x2000
|
||||||
|
|
||||||
typedef enum UnsupportedProcessFields {
|
typedef enum UnsupportedProcessFields {
|
||||||
FLAGS = 9,
|
FLAGS = 9,
|
||||||
|
@ -87,7 +88,10 @@ typedef enum LinuxProcessFields {
|
||||||
PERCENT_IO_DELAY = 117,
|
PERCENT_IO_DELAY = 117,
|
||||||
PERCENT_SWAP_DELAY = 118,
|
PERCENT_SWAP_DELAY = 118,
|
||||||
#endif
|
#endif
|
||||||
LAST_PROCESSFIELD = 119,
|
M_PSS = 119,
|
||||||
|
M_SWAP = 120,
|
||||||
|
M_PSSWP = 121,
|
||||||
|
LAST_PROCESSFIELD = 122,
|
||||||
} LinuxProcessField;
|
} LinuxProcessField;
|
||||||
|
|
||||||
#include "IOPriority.h"
|
#include "IOPriority.h"
|
||||||
|
@ -103,6 +107,9 @@ typedef struct LinuxProcess_ {
|
||||||
unsigned long long int cutime;
|
unsigned long long int cutime;
|
||||||
unsigned long long int cstime;
|
unsigned long long int cstime;
|
||||||
long m_share;
|
long m_share;
|
||||||
|
long m_pss;
|
||||||
|
long m_swap;
|
||||||
|
long m_psswp;
|
||||||
long m_trs;
|
long m_trs;
|
||||||
long m_drs;
|
long m_drs;
|
||||||
long m_lrs;
|
long m_lrs;
|
||||||
|
@ -239,6 +246,9 @@ ProcessFieldData Process_fields[] = {
|
||||||
[PERCENT_IO_DELAY] = { .name = "PERCENT_IO_DELAY", .title = "IOD% ", .description = "Block I/O delay %", .flags = 0, },
|
[PERCENT_IO_DELAY] = { .name = "PERCENT_IO_DELAY", .title = "IOD% ", .description = "Block I/O delay %", .flags = 0, },
|
||||||
[PERCENT_SWAP_DELAY] = { .name = "PERCENT_SWAP_DELAY", .title = "SWAPD% ", .description = "Swapin delay %", .flags = 0, },
|
[PERCENT_SWAP_DELAY] = { .name = "PERCENT_SWAP_DELAY", .title = "SWAPD% ", .description = "Swapin delay %", .flags = 0, },
|
||||||
#endif
|
#endif
|
||||||
|
[M_PSS] = { .name = "M_PSS", .title = " PSS ", .description = "proportional set size, same as M_RESIDENT but each page is divided by the number of processes sharing it.", .flags = PROCESS_FLAG_LINUX_SMAPS, },
|
||||||
|
[M_SWAP] = { .name = "M_SWAP", .title = " SWAP ", .description = "Size of the process's swapped pages", .flags = PROCESS_FLAG_LINUX_SMAPS, },
|
||||||
|
[M_PSSWP] = { .name = "M_PSSWP", .title = " PSSWP ", .description = "shows proportional swap share of this mapping, Unlike \"Swap\", this does not take into account swapped out page of underlying shmem objects.", .flags = PROCESS_FLAG_LINUX_SMAPS, },
|
||||||
[LAST_PROCESSFIELD] = { .name = "*** report bug! ***", .title = NULL, .description = NULL, .flags = 0, },
|
[LAST_PROCESSFIELD] = { .name = "*** report bug! ***", .title = NULL, .description = NULL, .flags = 0, },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -344,6 +354,9 @@ void LinuxProcess_writeField(Process* this, RichString* str, ProcessField field)
|
||||||
case M_LRS: Process_humanNumber(str, lp->m_lrs * PAGE_SIZE_KB, coloring); return;
|
case M_LRS: Process_humanNumber(str, lp->m_lrs * PAGE_SIZE_KB, coloring); return;
|
||||||
case M_TRS: Process_humanNumber(str, lp->m_trs * PAGE_SIZE_KB, coloring); return;
|
case M_TRS: Process_humanNumber(str, lp->m_trs * PAGE_SIZE_KB, coloring); return;
|
||||||
case M_SHARE: Process_humanNumber(str, lp->m_share * PAGE_SIZE_KB, coloring); return;
|
case M_SHARE: Process_humanNumber(str, lp->m_share * PAGE_SIZE_KB, coloring); return;
|
||||||
|
case M_PSS: Process_humanNumber(str, lp->m_pss, coloring); return;
|
||||||
|
case M_SWAP: Process_humanNumber(str, lp->m_swap, coloring); return;
|
||||||
|
case M_PSSWP: Process_humanNumber(str, lp->m_psswp, coloring); return;
|
||||||
case UTIME: Process_printTime(str, lp->utime); return;
|
case UTIME: Process_printTime(str, lp->utime); return;
|
||||||
case STIME: Process_printTime(str, lp->stime); return;
|
case STIME: Process_printTime(str, lp->stime); return;
|
||||||
case CUTIME: Process_printTime(str, lp->cutime); return;
|
case CUTIME: Process_printTime(str, lp->cutime); return;
|
||||||
|
@ -435,6 +448,12 @@ long LinuxProcess_compare(const void* v1, const void* v2) {
|
||||||
return (p2->m_trs - p1->m_trs);
|
return (p2->m_trs - p1->m_trs);
|
||||||
case M_SHARE:
|
case M_SHARE:
|
||||||
return (p2->m_share - p1->m_share);
|
return (p2->m_share - p1->m_share);
|
||||||
|
case M_PSS:
|
||||||
|
return (p2->m_pss - p1->m_pss);
|
||||||
|
case M_SWAP:
|
||||||
|
return (p2->m_swap - p1->m_swap);
|
||||||
|
case M_PSSWP:
|
||||||
|
return (p2->m_psswp - p1->m_psswp);
|
||||||
case UTIME: diff = p2->utime - p1->utime; goto test_diff;
|
case UTIME: diff = p2->utime - p1->utime; goto test_diff;
|
||||||
case CUTIME: diff = p2->cutime - p1->cutime; goto test_diff;
|
case CUTIME: diff = p2->cutime - p1->cutime; goto test_diff;
|
||||||
case STIME: diff = p2->stime - p1->stime; goto test_diff;
|
case STIME: diff = p2->stime - p1->stime; goto test_diff;
|
||||||
|
|
|
@ -15,6 +15,7 @@ in the source distribution for its full text.
|
||||||
#define PROCESS_FLAG_LINUX_VSERVER 0x0400
|
#define PROCESS_FLAG_LINUX_VSERVER 0x0400
|
||||||
#define PROCESS_FLAG_LINUX_CGROUP 0x0800
|
#define PROCESS_FLAG_LINUX_CGROUP 0x0800
|
||||||
#define PROCESS_FLAG_LINUX_OOM 0x1000
|
#define PROCESS_FLAG_LINUX_OOM 0x1000
|
||||||
|
#define PROCESS_FLAG_LINUX_SMAPS 0x2000
|
||||||
|
|
||||||
typedef enum UnsupportedProcessFields {
|
typedef enum UnsupportedProcessFields {
|
||||||
FLAGS = 9,
|
FLAGS = 9,
|
||||||
|
@ -78,7 +79,10 @@ typedef enum LinuxProcessFields {
|
||||||
PERCENT_IO_DELAY = 117,
|
PERCENT_IO_DELAY = 117,
|
||||||
PERCENT_SWAP_DELAY = 118,
|
PERCENT_SWAP_DELAY = 118,
|
||||||
#endif
|
#endif
|
||||||
LAST_PROCESSFIELD = 119,
|
M_PSS = 119,
|
||||||
|
M_SWAP = 120,
|
||||||
|
M_PSSWP = 121,
|
||||||
|
LAST_PROCESSFIELD = 122,
|
||||||
} LinuxProcessField;
|
} LinuxProcessField;
|
||||||
|
|
||||||
#include "IOPriority.h"
|
#include "IOPriority.h"
|
||||||
|
@ -94,6 +98,9 @@ typedef struct LinuxProcess_ {
|
||||||
unsigned long long int cutime;
|
unsigned long long int cutime;
|
||||||
unsigned long long int cstime;
|
unsigned long long int cstime;
|
||||||
long m_share;
|
long m_share;
|
||||||
|
long m_pss;
|
||||||
|
long m_swap;
|
||||||
|
long m_psswp;
|
||||||
long m_trs;
|
long m_trs;
|
||||||
long m_drs;
|
long m_drs;
|
||||||
long m_lrs;
|
long m_lrs;
|
||||||
|
|
|
@ -486,6 +486,58 @@ static bool LinuxProcessList_readStatmFile(LinuxProcess* process, const char* di
|
||||||
return (errno == 0);
|
return (errno == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool LinuxProcessList_readSmapsFile(LinuxProcess* process, const char* dirname, const char* name) {
|
||||||
|
//http://elixir.free-electrons.com/linux/v4.10/source/fs/proc/task_mmu.c#L719
|
||||||
|
//kernel will return data in chunks of size PAGE_SIZE or less.
|
||||||
|
|
||||||
|
char buffer[PAGE_SIZE];// 4k
|
||||||
|
char *start,*end;
|
||||||
|
ssize_t nread=0;
|
||||||
|
int tmp=0;
|
||||||
|
snprintf(buffer, MAX_NAME, "%s/%s/smaps", dirname, name);
|
||||||
|
int fd = open(buffer, O_RDONLY);
|
||||||
|
if (fd == -1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
process->m_pss = 0;
|
||||||
|
process->m_swap = 0;
|
||||||
|
process->m_psswp = 0;
|
||||||
|
|
||||||
|
while ( ( nread = read(fd,buffer, sizeof(buffer)) ) > 0 ){
|
||||||
|
start = (char *)&buffer;
|
||||||
|
end = start + nread;
|
||||||
|
do{//parse 4k block
|
||||||
|
|
||||||
|
if( (tmp = (end - start)) > 0 &&
|
||||||
|
(start = memmem(start,tmp,"\nPss:",5)) != NULL )
|
||||||
|
{
|
||||||
|
process->m_pss += strtol(start+5, &start, 10);
|
||||||
|
start += 3;//now we must be at the end of line "Pss: 0 kB"
|
||||||
|
}else
|
||||||
|
break; //read next 4k block
|
||||||
|
|
||||||
|
if( (tmp = (end - start)) > 0 &&
|
||||||
|
(start = memmem(start,tmp,"\nSwap:",6)) != NULL )
|
||||||
|
{
|
||||||
|
process->m_swap += strtol(start+6, &start, 10);
|
||||||
|
start += 3;
|
||||||
|
}else
|
||||||
|
break;
|
||||||
|
|
||||||
|
if( (tmp = (end - start)) > 0 &&
|
||||||
|
(start = memmem(start,tmp,"\nSwapPss:",9)) != NULL )
|
||||||
|
{
|
||||||
|
process->m_psswp += strtol(start+9, &start, 10);
|
||||||
|
start += 3;
|
||||||
|
}else
|
||||||
|
break;
|
||||||
|
|
||||||
|
}while(1);
|
||||||
|
}//while read
|
||||||
|
close(fd);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_OPENVZ
|
#ifdef HAVE_OPENVZ
|
||||||
|
|
||||||
static void LinuxProcessList_readOpenVZData(LinuxProcess* process, const char* dirname, const char* name) {
|
static void LinuxProcessList_readOpenVZData(LinuxProcess* process, const char* dirname, const char* name) {
|
||||||
|
@ -815,6 +867,21 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char*
|
||||||
if (! LinuxProcessList_readStatmFile(lp, dirname, name))
|
if (! LinuxProcessList_readStatmFile(lp, dirname, name))
|
||||||
goto errorReadingProcess;
|
goto errorReadingProcess;
|
||||||
|
|
||||||
|
if ((settings->flags & PROCESS_FLAG_LINUX_SMAPS) && !Process_isKernelThread(proc)){
|
||||||
|
if (!parent){
|
||||||
|
// Read smaps file of each process only every second pass to improve performance
|
||||||
|
static int smaps_flag = 0;
|
||||||
|
if ((pid & 1) == smaps_flag){
|
||||||
|
LinuxProcessList_readSmapsFile(lp, dirname, name);
|
||||||
|
}
|
||||||
|
if (pid == 1) {
|
||||||
|
smaps_flag = !smaps_flag;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lp->m_pss = ((LinuxProcess*)parent)->m_pss;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc)));
|
proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc)));
|
||||||
|
|
||||||
char command[MAX_NAME+1];
|
char command[MAX_NAME+1];
|
||||||
|
|
Loading…
Reference in New Issue