diff options
Diffstat (limited to 'linux/LinuxProcessList.c')
-rw-r--r-- | linux/LinuxProcessList.c | 103 |
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; |