mirror of https://github.com/xzeldon/htop.git
Linux: add process->starttime and use it for STARTTIME column (#700)
this way a remount of /proc will not reset starttimes and we can also see startup times for processes started before the mount of /proc also record btime (boot time in seconds since epoch) as Linux semi-global
This commit is contained in:
parent
ca1cce4ce7
commit
bd1d719a61
|
@ -15,6 +15,7 @@ in the source distribution for its full text.
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
/*{
|
/*{
|
||||||
|
|
||||||
|
@ -106,6 +107,7 @@ typedef struct LinuxProcess_ {
|
||||||
long m_drs;
|
long m_drs;
|
||||||
long m_lrs;
|
long m_lrs;
|
||||||
long m_dt;
|
long m_dt;
|
||||||
|
unsigned long long starttime;
|
||||||
#ifdef HAVE_TASKSTATS
|
#ifdef HAVE_TASKSTATS
|
||||||
unsigned long long io_rchar;
|
unsigned long long io_rchar;
|
||||||
unsigned long long io_wchar;
|
unsigned long long io_wchar;
|
||||||
|
@ -152,6 +154,8 @@ typedef struct LinuxProcess_ {
|
||||||
|
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
long long btime; /* semi-global */
|
||||||
|
|
||||||
ProcessFieldData Process_fields[] = {
|
ProcessFieldData Process_fields[] = {
|
||||||
[0] = { .name = "", .title = NULL, .description = NULL, .flags = 0, },
|
[0] = { .name = "", .title = NULL, .description = NULL, .flags = 0, },
|
||||||
[PID] = { .name = "PID", .title = " PID ", .description = "Process/thread ID", .flags = 0, },
|
[PID] = { .name = "PID", .title = " PID ", .description = "Process/thread ID", .flags = 0, },
|
||||||
|
@ -344,6 +348,13 @@ void LinuxProcess_writeField(Process* this, RichString* str, ProcessField field)
|
||||||
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;
|
||||||
case CSTIME: Process_printTime(str, lp->cstime); return;
|
case CSTIME: Process_printTime(str, lp->cstime); return;
|
||||||
|
case STARTTIME: {
|
||||||
|
struct tm date;
|
||||||
|
time_t starttimewall = btime + (lp->starttime / sysconf(_SC_CLK_TCK));
|
||||||
|
(void) localtime_r(&starttimewall, &date);
|
||||||
|
strftime(buffer, n, ((starttimewall > time(NULL) - 86400) ? "%R " : "%b%d "), &date);
|
||||||
|
break;
|
||||||
|
}
|
||||||
#ifdef HAVE_TASKSTATS
|
#ifdef HAVE_TASKSTATS
|
||||||
case RCHAR: Process_colorNumber(str, lp->io_rchar, coloring); return;
|
case RCHAR: Process_colorNumber(str, lp->io_rchar, coloring); return;
|
||||||
case WCHAR: Process_colorNumber(str, lp->io_wchar, coloring); return;
|
case WCHAR: Process_colorNumber(str, lp->io_wchar, coloring); return;
|
||||||
|
@ -428,6 +439,12 @@ long LinuxProcess_compare(const void* v1, const void* v2) {
|
||||||
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;
|
||||||
case CSTIME: diff = p2->cstime - p1->cstime; goto test_diff;
|
case CSTIME: diff = p2->cstime - p1->cstime; goto test_diff;
|
||||||
|
case STARTTIME: {
|
||||||
|
if (p1->starttime == p2->starttime)
|
||||||
|
return (p1->super.pid - p2->super.pid);
|
||||||
|
else
|
||||||
|
return (p1->starttime - p2->starttime);
|
||||||
|
}
|
||||||
#ifdef HAVE_TASKSTATS
|
#ifdef HAVE_TASKSTATS
|
||||||
case RCHAR: diff = p2->io_rchar - p1->io_rchar; goto test_diff;
|
case RCHAR: diff = p2->io_rchar - p1->io_rchar; goto test_diff;
|
||||||
case WCHAR: diff = p2->io_wchar - p1->io_wchar; goto test_diff;
|
case WCHAR: diff = p2->io_wchar - p1->io_wchar; goto test_diff;
|
||||||
|
|
|
@ -98,6 +98,7 @@ typedef struct LinuxProcess_ {
|
||||||
long m_drs;
|
long m_drs;
|
||||||
long m_lrs;
|
long m_lrs;
|
||||||
long m_dt;
|
long m_dt;
|
||||||
|
unsigned long long starttime;
|
||||||
#ifdef HAVE_TASKSTATS
|
#ifdef HAVE_TASKSTATS
|
||||||
unsigned long long io_rchar;
|
unsigned long long io_rchar;
|
||||||
unsigned long long io_wchar;
|
unsigned long long io_wchar;
|
||||||
|
@ -143,6 +144,8 @@ typedef struct LinuxProcess_ {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
long long btime; /* semi-global */
|
||||||
|
|
||||||
extern ProcessFieldData Process_fields[];
|
extern ProcessFieldData Process_fields[];
|
||||||
|
|
||||||
extern ProcessPidColumn Process_pidColumns[];
|
extern ProcessPidColumn Process_pidColumns[];
|
||||||
|
|
|
@ -47,6 +47,8 @@ in the source distribution for its full text.
|
||||||
|
|
||||||
#include "ProcessList.h"
|
#include "ProcessList.h"
|
||||||
|
|
||||||
|
extern long long btime;
|
||||||
|
|
||||||
typedef struct CPUData_ {
|
typedef struct CPUData_ {
|
||||||
unsigned long long int totalTime;
|
unsigned long long int totalTime;
|
||||||
unsigned long long int userTime;
|
unsigned long long int userTime;
|
||||||
|
@ -111,7 +113,7 @@ typedef struct LinuxProcessList_ {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef PROC_LINE_LENGTH
|
#ifndef PROC_LINE_LENGTH
|
||||||
#define PROC_LINE_LENGTH 512
|
#define PROC_LINE_LENGTH 4096
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}*/
|
}*/
|
||||||
|
@ -230,8 +232,8 @@ static void LinuxProcessList_initNetlinkSocket(LinuxProcessList* this) {
|
||||||
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId) {
|
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId) {
|
||||||
LinuxProcessList* this = xCalloc(1, sizeof(LinuxProcessList));
|
LinuxProcessList* this = xCalloc(1, sizeof(LinuxProcessList));
|
||||||
ProcessList* pl = &(this->super);
|
ProcessList* pl = &(this->super);
|
||||||
ProcessList_init(pl, Class(LinuxProcess), usersTable, pidWhiteList, userId);
|
|
||||||
|
|
||||||
|
ProcessList_init(pl, Class(LinuxProcess), usersTable, pidWhiteList, userId);
|
||||||
LinuxProcessList_initTtyDrivers(this);
|
LinuxProcessList_initTtyDrivers(this);
|
||||||
|
|
||||||
#ifdef HAVE_DELAYACCT
|
#ifdef HAVE_DELAYACCT
|
||||||
|
@ -243,13 +245,19 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
CRT_fatalError("Cannot open " PROCSTATFILE);
|
CRT_fatalError("Cannot open " PROCSTATFILE);
|
||||||
}
|
}
|
||||||
char buffer[PROC_LINE_LENGTH + 1];
|
|
||||||
int cpus = -1;
|
int cpus = -1;
|
||||||
do {
|
do {
|
||||||
|
char buffer[PROC_LINE_LENGTH + 1];
|
||||||
|
if (fgets(buffer, PROC_LINE_LENGTH + 1, file) == NULL) {
|
||||||
|
CRT_fatalError("No btime in " PROCSTATFILE);
|
||||||
|
} else if (String_startsWith(buffer, "cpu")) {
|
||||||
cpus++;
|
cpus++;
|
||||||
char * s = fgets(buffer, PROC_LINE_LENGTH, file);
|
} else if (String_startsWith(buffer, "btime ")) {
|
||||||
(void) s;
|
sscanf(buffer, "btime %lld\n", &btime);
|
||||||
} while (String_startsWith(buffer, "cpu"));
|
break;
|
||||||
|
}
|
||||||
|
} while(true);
|
||||||
|
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
|
||||||
pl->cpuCount = MAX(cpus - 1, 1);
|
pl->cpuCount = MAX(cpus - 1, 1);
|
||||||
|
@ -259,7 +267,6 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui
|
||||||
this->cpus[i].totalTime = 1;
|
this->cpus[i].totalTime = 1;
|
||||||
this->cpus[i].totalPeriod = 1;
|
this->cpus[i].totalPeriod = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pl;
|
return pl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,7 +362,10 @@ static bool LinuxProcessList_readStatFile(Process *process, const char* dirname,
|
||||||
location += 1;
|
location += 1;
|
||||||
process->nlwp = strtol(location, &location, 10);
|
process->nlwp = strtol(location, &location, 10);
|
||||||
location += 1;
|
location += 1;
|
||||||
for (int i=0; i<17; i++) location = strchr(location, ' ')+1;
|
location = strchr(location, ' ')+1;
|
||||||
|
lp->starttime = strtoll(location, &location, 10);
|
||||||
|
location += 1;
|
||||||
|
for (int i=0; i<15; i++) location = strchr(location, ' ')+1;
|
||||||
process->exit_signal = strtol(location, &location, 10);
|
process->exit_signal = strtol(location, &location, 10);
|
||||||
location += 1;
|
location += 1;
|
||||||
assert(location != NULL);
|
assert(location != NULL);
|
||||||
|
@ -377,13 +387,6 @@ static bool LinuxProcessList_statProcessDir(Process* process, const char* dirnam
|
||||||
if (statok == -1)
|
if (statok == -1)
|
||||||
return false;
|
return false;
|
||||||
process->st_uid = sstat.st_uid;
|
process->st_uid = sstat.st_uid;
|
||||||
|
|
||||||
struct tm date;
|
|
||||||
time_t ctime = sstat.st_ctime;
|
|
||||||
process->starttime_ctime = ctime;
|
|
||||||
(void) localtime_r((time_t*) &ctime, &date);
|
|
||||||
strftime(process->starttime_show, 7, ((ctime > curTime - 86400) ? "%R " : "%b%d "), &date);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,8 @@ in the source distribution for its full text.
|
||||||
|
|
||||||
#include "ProcessList.h"
|
#include "ProcessList.h"
|
||||||
|
|
||||||
|
extern long long btime;
|
||||||
|
|
||||||
typedef struct CPUData_ {
|
typedef struct CPUData_ {
|
||||||
unsigned long long int totalTime;
|
unsigned long long int totalTime;
|
||||||
unsigned long long int userTime;
|
unsigned long long int userTime;
|
||||||
|
@ -84,7 +86,7 @@ typedef struct LinuxProcessList_ {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef PROC_LINE_LENGTH
|
#ifndef PROC_LINE_LENGTH
|
||||||
#define PROC_LINE_LENGTH 512
|
#define PROC_LINE_LENGTH 4096
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue