summaryrefslogtreecommitdiffstats
path: root/linux/LinuxProcessList.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/LinuxProcessList.c')
-rw-r--r--linux/LinuxProcessList.c103
1 files changed, 92 insertions, 11 deletions
diff --git a/linux/LinuxProcessList.c b/linux/LinuxProcessList.c
index 027cca4f..c6ab4807 100644
--- a/linux/LinuxProcessList.c
+++ b/linux/LinuxProcessList.c
@@ -88,6 +88,7 @@ typedef struct LinuxProcessList_ {
CPUData* cpus;
TtyDriver* ttyDrivers;
+ bool haveSmapsRollup;
#ifdef HAVE_DELAYACCT
struct nl_sock *netlink_socket;
@@ -239,8 +240,17 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui
LinuxProcessList_initNetlinkSocket(this);
#endif
+ // Check for /proc/*/smaps_rollup availability (improves smaps parsing speed, Linux 4.14+)
+ FILE* file = fopen(PROCDIR "/self/smaps_rollup", "r");
+ if(file != NULL) {
+ this->haveSmapsRollup = true;
+ fclose(file);
+ } else {
+ this->haveSmapsRollup = false;
+ }
+
// Update CPU count:
- FILE* file = fopen(PROCSTATFILE, "r");
+ file = fopen(PROCSTATFILE, "r");
if (file == NULL) {
CRT_fatalError("Cannot open " PROCSTATFILE);
}
@@ -485,6 +495,62 @@ static bool LinuxProcessList_readStatmFile(LinuxProcess* process, const char* di
return (errno == 0);
}
+static bool LinuxProcessList_readSmapsFile(LinuxProcess* process, const char* dirname, const char* name, bool haveSmapsRollup) {
+ //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;
+ if(haveSmapsRollup) {// only available in Linux 4.14+
+ snprintf(buffer, PAGE_SIZE-1, "%s/%s/smaps_rollup", dirname, name);
+ } else {
+ snprintf(buffer, PAGE_SIZE-1, "%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
static void LinuxProcessList_readOpenVZData(LinuxProcess* process, const char* dirname, const char* name) {
@@ -814,6 +880,21 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char*
if (! LinuxProcessList_readStatmFile(lp, dirname, name))
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, this->haveSmapsRollup);
+ }
+ 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)));
char command[MAX_NAME+1];
@@ -926,30 +1007,30 @@ static inline void LinuxProcessList_scanMemoryInfo(ProcessList* this) {
char buffer[128];
while (fgets(buffer, 128, file)) {
- #define tryRead(label, variable) (String_startsWith(buffer, label) && sscanf(buffer + strlen(label), " %32llu kB", variable))
+ #define tryRead(label, variable) do { if (String_startsWith(buffer, label) && sscanf(buffer + strlen(label), " %32llu kB", variable)) { break; } } while(0)
switch (buffer[0]) {
case 'M':
- if (tryRead("MemTotal:", &this->totalMem)) {}
- else if (tryRead("MemFree:", &this->freeMem)) {}
- else if (tryRead("MemShared:", &this->sharedMem)) {}
+ tryRead("MemTotal:", &this->totalMem);
+ tryRead("MemFree:", &this->freeMem);
+ tryRead("MemShared:", &this->sharedMem);
break;
case 'B':
- if (tryRead("Buffers:", &this->buffersMem)) {}
+ tryRead("Buffers:", &this->buffersMem);
break;
case 'C':
- if (tryRead("Cached:", &this->cachedMem)) {}
+ tryRead("Cached:", &this->cachedMem);
break;
case 'S':
switch (buffer[1]) {
case 'w':
- if (tryRead("SwapTotal:", &this->totalSwap)) {}
- else if (tryRead("SwapFree:", &swapFree)) {}
+ tryRead("SwapTotal:", &this->totalSwap);
+ tryRead("SwapFree:", &swapFree);
break;
case 'h':
- if (tryRead("Shmem:", &shmem)) {}
+ tryRead("Shmem:", &shmem);
break;
case 'R':
- if (tryRead("SReclaimable:", &sreclaimable)) {}
+ tryRead("SReclaimable:", &sreclaimable);
break;
}
break;