mirror of https://github.com/xzeldon/htop.git
LinuxProcessList: refactor /proc/stat parsing
Combine reading CPU count and CPU usage, only open the file once. Do not separately initialize totalPeriod and totalTime, cause the value 0 is handled in Platform_setCPUValues(). Take the number of currently running process from the entry procs_running in /proc/stat instead of counting all scanned process with state 'R', to include hidden tasks, e.g. threads.
This commit is contained in:
parent
521f1343e3
commit
0cfc9b0980
|
@ -163,43 +163,29 @@ static void LinuxProcessList_initNetlinkSocket(LinuxProcessList* this) {
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int LinuxProcessList_computeCPUcount(void) {
|
static void LinuxProcessList_updateCPUcount(ProcessList* super, FILE* stream) {
|
||||||
FILE* file = fopen(PROCSTATFILE, "r");
|
LinuxProcessList* this = (LinuxProcessList*) super;
|
||||||
if (file == NULL) {
|
|
||||||
CRT_fatalError("Cannot open " PROCSTATFILE);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cpus = 0;
|
int cpus = 0;
|
||||||
char buffer[PROC_LINE_LENGTH + 1];
|
char buffer[PROC_LINE_LENGTH + 1];
|
||||||
while (fgets(buffer, sizeof(buffer), file)) {
|
while (fgets(buffer, sizeof(buffer), stream)) {
|
||||||
if (String_startsWith(buffer, "cpu")) {
|
if (String_startsWith(buffer, "cpu")) {
|
||||||
cpus++;
|
cpus++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(file);
|
if (cpus == 0)
|
||||||
|
CRT_fatalError("No cpu entry in " PROCSTATFILE);
|
||||||
|
if (cpus == 1)
|
||||||
|
CRT_fatalError("No cpu aggregate or cpuN entry in " PROCSTATFILE);
|
||||||
|
|
||||||
/* subtract raw cpu entry */
|
/* Subtract aggregate cpu entry */
|
||||||
if (cpus > 0) {
|
cpus--;
|
||||||
cpus--;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cpus;
|
if (cpus != super->cpuCount || !this->cpus) {
|
||||||
}
|
super->cpuCount = MAXIMUM(cpus, 1);
|
||||||
|
free(this->cpus);
|
||||||
static void LinuxProcessList_updateCPUcount(LinuxProcessList* this) {
|
this->cpus = xCalloc(cpus + 1, sizeof(CPUData));
|
||||||
ProcessList* pl = &(this->super);
|
|
||||||
int cpus = LinuxProcessList_computeCPUcount();
|
|
||||||
if (cpus == 0 || cpus == pl->cpuCount)
|
|
||||||
return;
|
|
||||||
|
|
||||||
pl->cpuCount = cpus;
|
|
||||||
free(this->cpus);
|
|
||||||
this->cpus = xCalloc(cpus + 1, sizeof(CPUData));
|
|
||||||
|
|
||||||
for (int i = 0; i <= cpus; i++) {
|
|
||||||
this->cpus[i].totalTime = 1;
|
|
||||||
this->cpus[i].totalPeriod = 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,37 +211,29 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui
|
||||||
this->haveSmapsRollup = (access(PROCDIR "/self/smaps_rollup", R_OK) == 0);
|
this->haveSmapsRollup = (access(PROCDIR "/self/smaps_rollup", R_OK) == 0);
|
||||||
|
|
||||||
// Read btime (the kernel boot time, as number of seconds since the epoch)
|
// Read btime (the kernel boot time, as number of seconds since the epoch)
|
||||||
{
|
FILE* statfile = fopen(PROCSTATFILE, "r");
|
||||||
FILE* statfile = fopen(PROCSTATFILE, "r");
|
if (statfile == NULL)
|
||||||
if (statfile == NULL)
|
CRT_fatalError("Cannot open " PROCSTATFILE);
|
||||||
CRT_fatalError("Cannot open " PROCSTATFILE);
|
while (true) {
|
||||||
while (true) {
|
char buffer[PROC_LINE_LENGTH + 1];
|
||||||
char buffer[PROC_LINE_LENGTH + 1];
|
if (fgets(buffer, sizeof(buffer), statfile) == NULL)
|
||||||
if (fgets(buffer, sizeof(buffer), statfile) == NULL)
|
break;
|
||||||
break;
|
if (String_startsWith(buffer, "btime ") == false)
|
||||||
if (String_startsWith(buffer, "btime ") == false)
|
continue;
|
||||||
continue;
|
if (sscanf(buffer, "btime %lld\n", &btime) == 1)
|
||||||
if (sscanf(buffer, "btime %lld\n", &btime) == 1)
|
break;
|
||||||
break;
|
CRT_fatalError("Failed to parse btime from " PROCSTATFILE);
|
||||||
CRT_fatalError("Failed to parse btime from " PROCSTATFILE);
|
|
||||||
}
|
|
||||||
fclose(statfile);
|
|
||||||
|
|
||||||
if (btime == -1)
|
|
||||||
CRT_fatalError("No btime in " PROCSTATFILE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (btime == -1)
|
||||||
|
CRT_fatalError("No btime in " PROCSTATFILE);
|
||||||
|
|
||||||
|
rewind(statfile);
|
||||||
|
|
||||||
// Initialize CPU count
|
// Initialize CPU count
|
||||||
{
|
LinuxProcessList_updateCPUcount(pl, statfile);
|
||||||
int cpus = LinuxProcessList_computeCPUcount();
|
|
||||||
pl->cpuCount = MAXIMUM(cpus, 1);
|
|
||||||
this->cpus = xCalloc(cpus + 1, sizeof(CPUData));
|
|
||||||
|
|
||||||
for (int i = 0; i <= cpus; i++) {
|
fclose(statfile);
|
||||||
this->cpus[i].totalTime = 1;
|
|
||||||
this->cpus[i].totalPeriod = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return pl;
|
return pl;
|
||||||
}
|
}
|
||||||
|
@ -1498,8 +1476,7 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_
|
||||||
proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc)));
|
proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc)));
|
||||||
|
|
||||||
pl->totalTasks++;
|
pl->totalTasks++;
|
||||||
if (proc->state == 'R')
|
/* runningTasks is set in LinuxProcessList_scanCPUTime() from /proc/stat */
|
||||||
pl->runningTasks++;
|
|
||||||
proc->updated = true;
|
proc->updated = true;
|
||||||
Compat_openatArgClose(procFd);
|
Compat_openatArgClose(procFd);
|
||||||
continue;
|
continue;
|
||||||
|
@ -1772,26 +1749,28 @@ static inline void LinuxProcessList_scanZfsArcstats(LinuxProcessList* lpl) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline double LinuxProcessList_scanCPUTime(LinuxProcessList* this) {
|
static inline double LinuxProcessList_scanCPUTime(ProcessList* super) {
|
||||||
|
LinuxProcessList* this = (LinuxProcessList*) super;
|
||||||
|
|
||||||
FILE* file = fopen(PROCSTATFILE, "r");
|
FILE* file = fopen(PROCSTATFILE, "r");
|
||||||
if (file == NULL) {
|
if (!file)
|
||||||
CRT_fatalError("Cannot open " PROCSTATFILE);
|
CRT_fatalError("Cannot open " PROCSTATFILE);
|
||||||
}
|
|
||||||
int cpus = this->super.cpuCount;
|
LinuxProcessList_updateCPUcount(super, file);
|
||||||
assert(cpus > 0);
|
|
||||||
|
rewind(file);
|
||||||
|
|
||||||
|
int cpus = super->cpuCount;
|
||||||
for (int i = 0; i <= cpus; i++) {
|
for (int i = 0; i <= cpus; i++) {
|
||||||
char buffer[PROC_LINE_LENGTH + 1];
|
char buffer[PROC_LINE_LENGTH + 1];
|
||||||
unsigned long long int usertime, nicetime, systemtime, idletime;
|
unsigned long long int usertime, nicetime, systemtime, idletime;
|
||||||
unsigned long long int ioWait, irq, softIrq, steal, guest, guestnice;
|
unsigned long long int ioWait = 0, irq = 0, softIrq = 0, steal = 0, guest = 0, guestnice = 0;
|
||||||
ioWait = irq = softIrq = steal = guest = guestnice = 0;
|
|
||||||
// Depending on your kernel version,
|
// Depending on your kernel version,
|
||||||
// 5, 7, 8 or 9 of these fields will be set.
|
// 5, 7, 8 or 9 of these fields will be set.
|
||||||
// The rest will remain at zero.
|
// The rest will remain at zero.
|
||||||
const char* ok = fgets(buffer, PROC_LINE_LENGTH, file);
|
const char* ok = fgets(buffer, sizeof(buffer), file);
|
||||||
if (!ok) {
|
if (!ok)
|
||||||
buffer[0] = '\0';
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
(void) sscanf(buffer, "cpu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu", &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice);
|
(void) sscanf(buffer, "cpu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu", &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice);
|
||||||
|
@ -1801,8 +1780,8 @@ static inline double LinuxProcessList_scanCPUTime(LinuxProcessList* this) {
|
||||||
assert(cpuid == i - 1);
|
assert(cpuid == i - 1);
|
||||||
}
|
}
|
||||||
// Guest time is already accounted in usertime
|
// Guest time is already accounted in usertime
|
||||||
usertime = usertime - guest;
|
usertime -= guest;
|
||||||
nicetime = nicetime - guestnice;
|
nicetime -= guestnice;
|
||||||
// Fields existing on kernels >= 2.6
|
// Fields existing on kernels >= 2.6
|
||||||
// (and RHEL's patched kernel 2.4...)
|
// (and RHEL's patched kernel 2.4...)
|
||||||
unsigned long long int idlealltime = idletime + ioWait;
|
unsigned long long int idlealltime = idletime + ioWait;
|
||||||
|
@ -1842,7 +1821,17 @@ static inline double LinuxProcessList_scanCPUTime(LinuxProcessList* this) {
|
||||||
}
|
}
|
||||||
|
|
||||||
double period = (double)this->cpus[0].totalPeriod / cpus;
|
double period = (double)this->cpus[0].totalPeriod / cpus;
|
||||||
|
|
||||||
|
char buffer[PROC_LINE_LENGTH + 1];
|
||||||
|
while (fgets(buffer, sizeof(buffer), file)) {
|
||||||
|
if (String_startsWith(buffer, "procs_running")) {
|
||||||
|
super->runningTasks = strtoul(buffer + strlen("procs_running"), NULL, 10);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
|
||||||
return period;
|
return period;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1978,10 +1967,9 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) {
|
||||||
LinuxProcessList_scanMemoryInfo(super);
|
LinuxProcessList_scanMemoryInfo(super);
|
||||||
LinuxProcessList_scanHugePages(this);
|
LinuxProcessList_scanHugePages(this);
|
||||||
LinuxProcessList_scanZfsArcstats(this);
|
LinuxProcessList_scanZfsArcstats(this);
|
||||||
LinuxProcessList_updateCPUcount(this);
|
|
||||||
LinuxProcessList_scanZramInfo(this);
|
LinuxProcessList_scanZramInfo(this);
|
||||||
|
|
||||||
double period = LinuxProcessList_scanCPUTime(this);
|
double period = LinuxProcessList_scanCPUTime(super);
|
||||||
|
|
||||||
if (settings->showCPUFrequency) {
|
if (settings->showCPUFrequency) {
|
||||||
LinuxProcessList_scanCPUFrequency(this);
|
LinuxProcessList_scanCPUFrequency(this);
|
||||||
|
|
Loading…
Reference in New Issue