Major advances in FreeBSD port.

This commit is contained in:
Hisham Muhammad 2015-03-16 23:01:48 -03:00
parent 9ff5d2b243
commit 272e2d9b34
12 changed files with 228 additions and 104 deletions

View File

@ -6,8 +6,8 @@ in the source distribution for its full text.
*/
#include "Process.h"
#include "Settings.h"
#include "CRT.h"
#include "String.h"
#include "RichString.h"
@ -55,6 +55,7 @@ typedef enum ProcessFields {
PRIORITY = 18,
NICE = 19,
STARTTIME = 21,
PROCESSOR = 38,
M_SIZE = 39,
M_RESIDENT = 40,
ST_UID = 46,
@ -91,6 +92,7 @@ typedef struct Process_ {
int tpgid;
uid_t st_uid;
unsigned long int flags;
int processor;
float percent_cpu;
float percent_mem;
@ -147,6 +149,8 @@ extern ProcessFieldData Process_fields[];
extern char* Process_pidFormat;
extern char* Process_tpgidFormat;
typedef Process*(*Process_new_fn)(struct Settings_*);
}*/
static int Process_getuid = -1;
@ -234,19 +238,13 @@ void Process_colorNumber(RichString* str, unsigned long long number, bool colori
}
}
static double jiffy = 0.0;
void Process_printTime(RichString* str, unsigned long long totalHundredths) {
unsigned long long totalSeconds = totalHundredths / 100;
void Process_printTime(RichString* str, unsigned long long t) {
if(jiffy == 0.0) jiffy = sysconf(_SC_CLK_TCK);
double jiffytime = 1.0 / jiffy;
double realTime = t * jiffytime;
unsigned long long iRealTime = (unsigned long long) realTime;
unsigned long long hours = iRealTime / 3600;
int minutes = (iRealTime / 60) % 60;
int seconds = iRealTime % 60;
int hundredths = (realTime - iRealTime) * 100;
unsigned long long hours = totalSeconds / 3600;
int minutes = (totalSeconds / 60) % 60;
int seconds = totalSeconds % 60;
int hundredths = totalHundredths - (totalSeconds * 100);
char buffer[11];
if (hours >= 100) {
snprintf(buffer, 10, "%7lluh ", hours);
@ -389,6 +387,7 @@ void Process_writeDefaultField(Process* this, RichString* str, ProcessField fiel
snprintf(buffer, n, "%3ld ", this->priority);
break;
}
case PROCESSOR: snprintf(buffer, n, "%3d ", Settings_cpuId(this->settings, this->processor)); break;
case SESSION: snprintf(buffer, n, Process_pidFormat, this->session); break;
case STARTTIME: snprintf(buffer, n, "%s", this->starttime_show); break;
case STATE: {
@ -527,6 +526,8 @@ long Process_defaultCompare(const void* v1, const void* v2) {
return (p1->ppid - p2->ppid);
case PRIORITY:
return (p1->priority - p2->priority);
case PROCESSOR:
return (p1->processor - p2->processor);
case SESSION:
return (p1->session - p2->session);
case STARTTIME: {

View File

@ -36,6 +36,7 @@ typedef enum ProcessFields {
PRIORITY = 18,
NICE = 19,
STARTTIME = 21,
PROCESSOR = 38,
M_SIZE = 39,
M_RESIDENT = 40,
ST_UID = 46,
@ -72,6 +73,7 @@ typedef struct Process_ {
int tpgid;
uid_t st_uid;
unsigned long int flags;
int processor;
float percent_cpu;
float percent_mem;
@ -128,6 +130,8 @@ extern ProcessFieldData Process_fields[];
extern char* Process_pidFormat;
extern char* Process_tpgidFormat;
typedef Process*(*Process_new_fn)(struct Settings_*);
#define ONE_K 1024L
#define ONE_M (ONE_K * ONE_K)
@ -141,7 +145,7 @@ void Process_humanNumber(RichString* str, unsigned long number, bool coloring);
void Process_colorNumber(RichString* str, unsigned long long number, bool coloring);
void Process_printTime(RichString* str, unsigned long long t);
void Process_printTime(RichString* str, unsigned long long totalHundredths);
void Process_outputRate(RichString* str, char* buffer, int n, double rate, int coloring);

View File

@ -49,6 +49,11 @@ typedef struct ProcessList_ {
bool topologyOk;
#endif
int totalTasks;
int runningTasks;
int userlandThreads;
int kernelThreads;
unsigned long long int totalMem;
unsigned long long int usedMem;
unsigned long long int freeMem;
@ -65,7 +70,7 @@ typedef struct ProcessList_ {
ProcessList* ProcessList_new(UsersTable* ut, Hashtable* pidWhiteList, uid_t userId);
void ProcessList_delete(ProcessList* pl);
void ProcessList_scan(ProcessList* pl);
void ProcessList_goThroughEntries(ProcessList* pl);
}*/
@ -282,3 +287,40 @@ void ProcessList_rebuildPanel(ProcessList* this) {
}
}
Process* ProcessList_getProcess(ProcessList* this, pid_t pid, bool* preExisting, Process_new_fn constructor) {
Process* proc = (Process*) Hashtable_get(this->processTable, pid);
*preExisting = proc;
if (proc) {
assert(Vector_indexOf(this->processes, proc, Process_pidCompare) != -1);
assert(proc->pid == pid);
} else {
proc = constructor(this->settings);
assert(proc->comm == NULL);
proc->pid = pid;
}
return proc;
}
void ProcessList_scan(ProcessList* this) {
// mark all process as "dirty"
for (int i = 0; i < Vector_size(this->processes); i++) {
Process* p = (Process*) Vector_get(this->processes, i);
p->updated = false;
}
this->totalTasks = 0;
this->userlandThreads = 0;
this->kernelThreads = 0;
this->runningTasks = 0;
ProcessList_goThroughEntries(this);
for (int i = Vector_size(this->processes) - 1; i >= 0; i--) {
Process* p = (Process*) Vector_get(this->processes, i);
if (p->updated == false)
ProcessList_remove(this, p);
else
p->updated = false;
}
}

View File

@ -43,6 +43,11 @@ typedef struct ProcessList_ {
bool topologyOk;
#endif
int totalTasks;
int runningTasks;
int userlandThreads;
int kernelThreads;
unsigned long long int totalMem;
unsigned long long int usedMem;
unsigned long long int freeMem;
@ -59,7 +64,7 @@ typedef struct ProcessList_ {
ProcessList* ProcessList_new(UsersTable* ut, Hashtable* pidWhiteList, uid_t userId);
void ProcessList_delete(ProcessList* pl);
void ProcessList_scan(ProcessList* pl);
void ProcessList_goThroughEntries(ProcessList* pl);
ProcessList* ProcessList_init(ProcessList* this, UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId);
@ -86,5 +91,8 @@ void ProcessList_expandTree(ProcessList* this);
void ProcessList_rebuildPanel(ProcessList* this);
Process* ProcessList_getProcess(ProcessList* this, pid_t pid, bool* preExisting, Process_new_fn constructor);
void ProcessList_scan(ProcessList* this);
#endif

View File

@ -19,7 +19,14 @@ int TasksMeter_attributes[] = {
};
static void TasksMeter_setValues(Meter* this, char* buffer, int len) {
Platform_setTasksValues(this);
ProcessList* pl = this->pl;
this->values[0] = pl->kernelThreads;
this->values[1] = pl->userlandThreads;
this->values[2] = pl->totalTasks - pl->kernelThreads - pl->userlandThreads;
this->values[3] = pl->runningTasks;
if (pl->totalTasks > this->total) {
this->total = pl->totalTasks;
}
if (this->pl->settings->hideKernelThreads) {
this->values[0] = 0;
}

View File

@ -26,6 +26,14 @@ typedef struct FreeBSDProcess_ {
Process super;
} FreeBSDProcess;
#ifndef Process_isKernelThread
#define Process_isKernelThread(_process) (_process->pgrp == 0)
#endif
#ifndef Process_isUserlandThread
#define Process_isUserlandThread(_process) (_process->pid != _process->tgid)
#endif
}*/
ProcessFieldData Process_fields[] = {
@ -44,6 +52,7 @@ ProcessFieldData Process_fields[] = {
[NICE] = { .name = "NICE", .title = " NI ", .description = "Nice value (the higher the value, the more it lets other processes take priority)", .flags = 0, },
[STARTTIME] = { .name = "STARTTIME", .title = "START ", .description = "Time the process was started", .flags = 0, },
[PROCESSOR] = { .name = "PROCESSOR", .title = "CPU ", .description = "Id of the CPU the process last executed on", .flags = 0, },
[M_SIZE] = { .name = "M_SIZE", .title = " VIRT ", .description = "Total program size in virtual memory", .flags = 0, },
[M_RESIDENT] = { .name = "M_RESIDENT", .title = " RES ", .description = "Resident set size, size of the text and data sections, plus stack usage", .flags = 0, },
[ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, },
@ -128,7 +137,5 @@ long Process_compare(const void* v1, const void* v2) {
}
bool Process_isThread(Process* this) {
(void) this;
// TODO
return false;
return (Process_isKernelThread(this));
}

View File

@ -19,6 +19,14 @@ typedef struct FreeBSDProcess_ {
Process super;
} FreeBSDProcess;
#ifndef Process_isKernelThread
#define Process_isKernelThread(_process) (_process->pgrp == 0)
#endif
#ifndef Process_isUserlandThread
#define Process_isUserlandThread(_process) (_process->pid != _process->tgid)
#endif
extern ProcessFieldData Process_fields[];

View File

@ -7,12 +7,15 @@ in the source distribution for its full text.
#include "ProcessList.h"
#include "FreeBSDProcessList.h"
#include "FreeBSDProcess.h"
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <fcntl.h>
#include <string.h>
/*{
@ -103,10 +106,101 @@ static inline void FreeBSDProcessList_scanMemoryInfo(ProcessList* pl) {
pl->buffersMem = 0; // not exposed to userspace
}
void ProcessList_scan(ProcessList* this) {
(void) this;
FreeBSDProcessList_scanMemoryInfo(this);
// stub!
char* FreeBSDProcessList_readProcessName(kvm_t* kd, struct kinfo_proc* kproc, int* basenameEnd) {
char** argv = kvm_getargv(kd, kproc, 0);
if (!argv) {
return strdup(kproc->ki_comm);
}
int len = 0;
for (int i = 0; argv[i]; i++) {
len += strlen(argv[i]) + 1;
}
char* comm = malloc(len * sizeof(char));
char* at = comm;
*basenameEnd = 0;
for (int i = 0; argv[i]; i++) {
at = stpcpy(at, argv[i]);
if (!*basenameEnd) {
*basenameEnd = at - comm;
}
*at = ' ';
at++;
}
at--;
*at = '\0';
return comm;
}
void ProcessList_goThroughEntries(ProcessList* this) {
FreeBSDProcessList* fpl = (FreeBSDProcessList*) this;
Settings* settings = this->settings;
bool hideKernelThreads = settings->hideKernelThreads;
bool hideUserlandThreads = settings->hideUserlandThreads;
FreeBSDProcessList_scanMemoryInfo(this);
int count = 0;
struct kinfo_proc* kprocs = kvm_getprocs(fpl->kd, KERN_PROC_ALL, 0, &count);
for (int i = 0; i < count; i++) {
struct kinfo_proc* kproc = &kprocs[i];
bool preExisting = false;
Process* proc = ProcessList_getProcess(this, kproc->ki_pid, &preExisting, (Process_new_fn) FreeBSDProcess_new);
FreeBSDProcess* fp = (FreeBSDProcess*) proc;
proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc)));
if (!preExisting) {
proc->ppid = kproc->ki_ppid;
proc->tpgid = kproc->ki_tpgid;
proc->tgid = kproc->ki_pid;
proc->session = kproc->ki_sid;
proc->tty_nr = kproc->ki_tdev;
proc->pgrp = kproc->ki_pgid;
proc->st_uid = kproc->ki_uid;
proc->starttime_ctime = kproc->ki_start.tv_sec;
proc->user = UsersTable_getRef(this->usersTable, proc->st_uid);
ProcessList_add((ProcessList*)this, proc);
proc->comm = FreeBSDProcessList_readProcessName(fpl->kd, kproc, &proc->basenameOffset);
} else {
if (settings->updateProcessNames) {
free(proc->comm);
proc->comm = FreeBSDProcessList_readProcessName(fpl->kd, kproc, &proc->basenameOffset);
}
}
proc->m_size = kproc->ki_size / pageSizeKb / 1000;
proc->m_resident = kproc->ki_rssize; // * pageSizeKb;
proc->nlwp = kproc->ki_numthreads;
proc->time = (kproc->ki_runtime + 5000) / 10000;
proc->priority = kproc->ki_pri.pri_level - PZERO;
if (kproc->ki_pri.pri_class == PRI_TIMESHARE) {
proc->nice = kproc->ki_nice - NZERO;
} else if (PRI_IS_REALTIME(kproc->ki_pri.pri_class)) {
proc->nice = PRIO_MIN - 1 - (PRI_MAX_REALTIME - kproc->ki_pri.pri_level);
} else {
proc->nice = PRIO_MAX + 1 + kproc->ki_pri.pri_level - PRI_MIN_IDLE;
}
switch (kproc->ki_stat) {
case SIDL: proc->state = 'I'; break;
case SRUN: proc->state = 'R'; break;
case SSLEEP: proc->state = 'S'; break;
case SSTOP: proc->state = 'T'; break;
case SZOMB: proc->state = 'Z'; break;
case SWAIT: proc->state = 'D'; break;
case SLOCK: proc->state = 'L'; break;
default: proc->state = '?';
}
if (Process_isKernelThread(proc)) {
this->kernelThreads++;
}
this->totalTasks++;
if (proc->state == 'R')
this->runningTasks++;
proc->updated = true;
}
}

View File

@ -30,6 +30,8 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui
void ProcessList_delete(ProcessList* this);
void ProcessList_scan(ProcessList* this);
char* FreeBSDProcessList_readProcessName(kvm_t* kd, struct kinfo_proc* kproc, int* basenameEnd);
void ProcessList_goThroughEntries(ProcessList* this);
#endif

View File

@ -51,7 +51,6 @@ typedef enum LinuxProcessFields {
STIME = 15,
CUTIME = 16,
CSTIME = 17,
PROCESSOR = 38,
M_SHARE = 41,
M_TRS = 42,
M_DRS = 43,
@ -97,7 +96,6 @@ typedef struct LinuxProcess_ {
unsigned long long int stime;
unsigned long long int cutime;
unsigned long long int cstime;
int processor;
long m_share;
long m_trs;
long m_drs;
@ -309,7 +307,6 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) {
switch ((int)field) {
case CMINFLT: Process_colorNumber(str, lp->cminflt, coloring); return;
case CMAJFLT: Process_colorNumber(str, lp->cmajflt, coloring); return;
case PROCESSOR: snprintf(buffer, n, "%3d ", Settings_cpuId(this->settings, lp->processor)); break;
case M_DRS: Process_humanNumber(str, lp->m_drs * PAGE_SIZE_KB, coloring); return;
case M_DT: Process_humanNumber(str, lp->m_dt * PAGE_SIZE_KB, coloring); return;
case M_LRS: Process_humanNumber(str, lp->m_lrs * PAGE_SIZE_KB, coloring); return;
@ -381,8 +378,6 @@ long Process_compare(const void* v1, const void* v2) {
}
long long diff;
switch ((int)settings->sortKey) {
case PROCESSOR:
return (p1->processor - p2->processor);
case M_DRS:
return (p2->m_drs - p1->m_drs);
case M_DT:

View File

@ -61,11 +61,6 @@ typedef struct CPUData_ {
typedef struct LinuxProcessList_ {
ProcessList super;
int totalTasks;
int userlandThreads;
int kernelThreads;
int runningTasks;
CPUData* cpus;
@ -141,6 +136,14 @@ static ssize_t xread(int fd, void *buf, size_t count) {
}
}
static double jiffy = 0.0;
static inline unsigned long long LinuxProcess_adjustTime(unsigned long long t) {
if(jiffy == 0.0) jiffy = sysconf(_SC_CLK_TCK);
double jiffytime = 1.0 / jiffy;
return (unsigned long long) t * jiffytime * 100;
}
static bool LinuxProcessList_readStatFile(Process *process, const char* dirname, const char* name, char* command) {
LinuxProcess* lp = (LinuxProcess*) process;
char filename[MAX_NAME+1];
@ -191,13 +194,13 @@ static bool LinuxProcessList_readStatFile(Process *process, const char* dirname,
location += 1;
lp->cmajflt = strtoull(location, &location, 10);
location += 1;
lp->utime = strtoull(location, &location, 10);
lp->utime = LinuxProcess_adjustTime(strtoull(location, &location, 10));
location += 1;
lp->stime = strtoull(location, &location, 10);
lp->stime = LinuxProcess_adjustTime(strtoull(location, &location, 10));
location += 1;
lp->cutime = strtoull(location, &location, 10);
lp->cutime = LinuxProcess_adjustTime(strtoull(location, &location, 10));
location += 1;
lp->cstime = strtoull(location, &location, 10);
lp->cstime = LinuxProcess_adjustTime(strtoull(location, &location, 10));
location += 1;
process->priority = strtol(location, &location, 10);
location += 1;
@ -474,11 +477,11 @@ static bool LinuxProcessList_readCmdlineFile(Process* process, const char* dirna
return true;
}
static bool LinuxProcessList_processEntries(LinuxProcessList* this, const char* dirname, Process* parent, double period, struct timeval tv) {
static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char* dirname, Process* parent, double period, struct timeval tv) {
ProcessList* pl = (ProcessList*) this;
DIR* dir;
struct dirent* entry;
Settings* settings = this->super.settings;
Settings* settings = pl->settings;
time_t curTime = tv.tv_sec;
#ifdef HAVE_TASKSTATS
@ -487,7 +490,7 @@ static bool LinuxProcessList_processEntries(LinuxProcessList* this, const char*
dir = opendir(dirname);
if (!dir) return false;
int cpus = this->super.cpuCount;
int cpus = pl->cpuCount;
bool hideKernelThreads = settings->hideKernelThreads;
bool hideUserlandThreads = settings->hideUserlandThreads;
while ((entry = readdir(dir)) != NULL) {
@ -513,25 +516,15 @@ static bool LinuxProcessList_processEntries(LinuxProcessList* this, const char*
if (pid <= 0)
continue;
Process* proc = NULL;
Process* existingProc = (Process*) Hashtable_get(this->super.processTable, pid);
if (existingProc) {
assert(Vector_indexOf(this->processes, existingProc, Process_pidCompare) != -1);
proc = existingProc;
assert(proc->pid == pid);
} else {
proc = (Process*) LinuxProcess_new(settings);
assert(proc->comm == NULL);
proc->pid = pid;
proc->tgid = parent ? parent->pid : pid;
}
bool preExisting = false;
Process* proc = ProcessList_getProcess(pl, pid, &preExisting, (Process_new_fn) LinuxProcess_new);
proc->tgid = parent ? parent->pid : pid;
LinuxProcess* lp = (LinuxProcess*) proc;
char subdirname[MAX_NAME+1];
snprintf(subdirname, MAX_NAME, "%s/%s/task", dirname, name);
LinuxProcessList_processEntries(this, subdirname, proc, period, tv);
LinuxProcessList_recurseProcTree(this, subdirname, proc, period, tv);
#ifdef HAVE_TASKSTATS
if (settings->flags & PROCESS_FLAG_IO)
@ -554,12 +547,12 @@ static bool LinuxProcessList_processEntries(LinuxProcessList* this, const char*
if (isnan(proc->percent_cpu)) proc->percent_cpu = 0.0;
proc->percent_mem = (proc->m_resident * PAGE_SIZE_KB) / (double)(pl->totalMem) * 100.0;
if(!existingProc) {
if(!preExisting) {
if (! LinuxProcessList_statProcessDir(proc, dirname, name, curTime))
goto errorReadingProcess;
proc->user = UsersTable_getRef(this->super.usersTable, proc->st_uid);
proc->user = UsersTable_getRef(pl->usersTable, proc->st_uid);
#ifdef HAVE_OPENVZ
LinuxProcessList_readOpenVZData(this, lp, dirname, name);
@ -573,7 +566,7 @@ static bool LinuxProcessList_processEntries(LinuxProcessList* this, const char*
if (! LinuxProcessList_readCmdlineFile(proc, dirname, name))
goto errorReadingProcess;
ProcessList_add((ProcessList*)this, proc);
ProcessList_add(pl, proc);
} else {
if (settings->updateProcessNames) {
if (! LinuxProcessList_readCmdlineFile(proc, dirname, name))
@ -614,20 +607,15 @@ static bool LinuxProcessList_processEntries(LinuxProcessList* this, const char*
if (proc->state == 'R')
this->runningTasks++;
proc->updated = true;
continue;
// Exception handler.
errorReadingProcess: {
if (proc->comm) {
free(proc->comm);
proc->basenameOffset = -1;
proc->comm = NULL;
}
if (existingProc)
ProcessList_remove((ProcessList*)this, proc);
else
if (preExisting) {
ProcessList_remove((pl, proc);
} else {
Process_delete((Object*)proc);
}
}
}
closedir(dir);
@ -752,35 +740,13 @@ static inline double LinuxProcessList_scanCPUTime(LinuxProcessList* this) {
return period;
}
void ProcessList_scan(ProcessList* super) {
void ProcessList_goThroughEntries(ProcessList* super) {
LinuxProcessList* this = (LinuxProcessList*) super;
LinuxProcessList_scanMemoryInfo(super);
double period = LinuxProcessList_scanCPUTime(this);
// mark all process as "dirty"
for (int i = 0; i < Vector_size(super->processes); i++) {
Process* p = (Process*) Vector_get(super->processes, i);
p->updated = false;
}
this->totalTasks = 0;
this->userlandThreads = 0;
this->kernelThreads = 0;
this->runningTasks = 0;
struct timeval tv;
gettimeofday(&tv, NULL);
LinuxProcessList_processEntries(this, PROCDIR, NULL, period, tv);
for (int i = Vector_size(this->super.processes) - 1; i >= 0; i--) {
Process* p = (Process*) Vector_get(this->super.processes, i);
if (p->updated == false)
ProcessList_remove(super, p);
else
p->updated = false;
}
LinuxProcessList_recurseProcTree(this, PROCDIR, NULL, period, tv);
}

View File

@ -165,13 +165,3 @@ void Platform_setSwapValues(Meter* this) {
this->total = pl->totalSwap;
this->values[0] = pl->usedSwap;
}
void Platform_setTasksValues(Meter* this) {
LinuxProcessList* pl = (LinuxProcessList*) this->pl;
this->values[0] = pl->kernelThreads;
this->values[1] = pl->userlandThreads;
this->values[2] = pl->totalTasks - pl->kernelThreads - pl->userlandThreads;
this->values[3] = pl->runningTasks;
if (pl->totalTasks > this->total)
this->total = pl->totalTasks;
}