Commit bd1d719a authored by Shawn Landden's avatar Shawn Landden Committed by Hisham Muhammad
Browse files

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
parent ca1cce4c
...@@ -15,6 +15,7 @@ in the source distribution for its full text. ...@@ -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_ { ...@@ -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_ { ...@@ -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) ...@@ -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) { ...@@ -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_ { ...@@ -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_ { ...@@ -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. ...@@ -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_ { ...@@ -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) { ...@@ -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 ...@@ -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 ...@@ -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, ...@@ -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 ...@@ -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. ...@@ -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_ { ...@@ -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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment