Stat aggregation
This commit is contained in:
parent
5902bc0bb5
commit
89b05452a0
@ -28,12 +28,12 @@ typedef struct st_process {
|
||||
uint64_t swap;
|
||||
uint64_t written;
|
||||
uint64_t read;
|
||||
|
||||
uint64_t childCpuTime;
|
||||
uint64_t childMemory;
|
||||
uint64_t childSwap;
|
||||
uint64_t childRead;
|
||||
uint64_t childWrite;
|
||||
// cumulative fields - process + children
|
||||
uint64_t cCpuTime;
|
||||
uint64_t cMemory;
|
||||
uint64_t cSwap;
|
||||
uint64_t cRead;
|
||||
uint64_t cWrite;
|
||||
} Process;
|
||||
|
||||
#endif
|
||||
|
||||
82
src/server.c
82
src/server.c
@ -59,6 +59,7 @@ int parseStatFile(Process *proc, char *filedata) {
|
||||
|
||||
// (15) stime - %lu
|
||||
proc->cpuTime += fast_str2ull(&location);
|
||||
proc->cCpuTime = proc->cpuTime;
|
||||
location += 1;
|
||||
|
||||
// skip 16-19
|
||||
@ -81,12 +82,16 @@ int parseStatusFile(Process *proc, char *filedata) {
|
||||
|
||||
proc->resident = 1024 * findAndParseField(&filedata, "VmRSS");
|
||||
proc->swap = 1024 * findAndParseField(&filedata, "VmSwap");
|
||||
proc->cMemory = proc->resident;
|
||||
proc->cSwap = proc->swap;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parseIOFile(Process *proc, char *filedata) {
|
||||
proc->read = findAndParseField(&filedata, "read_bytes");
|
||||
proc->written = findAndParseField(&filedata, "write_bytes");
|
||||
proc->cRead = proc->read;
|
||||
proc->cWrite = proc->written;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -172,7 +177,60 @@ nextProcess:
|
||||
}
|
||||
|
||||
void aggregateStats(Process *head) {
|
||||
int processCount = resetVisits(head);
|
||||
Process *current = head;
|
||||
int depth = 0;
|
||||
int maxdepth = 0;
|
||||
int visited = 0;
|
||||
|
||||
// assign depth (aka level) of each process
|
||||
while (visited < processCount) {
|
||||
if (current == NULL) {
|
||||
printf("Bad visit count: %d visited of %d processes\n", visited, processCount);
|
||||
break;
|
||||
}
|
||||
|
||||
current->visited = 1;
|
||||
current->level = depth;
|
||||
visited++;
|
||||
|
||||
if (depth > maxdepth) maxdepth = depth;
|
||||
|
||||
nextProcess:
|
||||
if (current->child != NULL && !current->child->visited) {
|
||||
// process children first
|
||||
depth++;
|
||||
current = current->child;
|
||||
} else if (current->sibling != NULL) {
|
||||
// process siblings next
|
||||
current = current->sibling;
|
||||
} else if (current->parent != NULL) {
|
||||
// return to parent when tree is exhausted
|
||||
depth--;
|
||||
current = current->parent;
|
||||
goto nextProcess; // parent was already visited, so find next process from parent
|
||||
} else {
|
||||
// no parent - scan for unvisited process
|
||||
while (current != NULL && current->visited == 1) current = current->next;
|
||||
}
|
||||
}
|
||||
|
||||
// scan for each depth level, tally stats upwards
|
||||
for (depth=maxdepth; depth>0; depth--) {
|
||||
current = head;
|
||||
while (current != NULL) {
|
||||
while (current != NULL && current->level != depth) current = current->next;
|
||||
if (current == NULL) continue;
|
||||
|
||||
Process *parent = current->parent;
|
||||
parent->cCpuTime += current->cCpuTime;
|
||||
parent->cMemory += current->cCpuTime;
|
||||
parent->cSwap += current->cSwap;
|
||||
parent->cRead += current->cRead;
|
||||
parent->cWrite += current->cWrite;
|
||||
current = current->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *readProcesses(char *procdir) {
|
||||
@ -256,10 +314,10 @@ char *readProcesses(char *procdir) {
|
||||
cur = cur->prev;
|
||||
free(cur->next);
|
||||
cur->next = NULL;
|
||||
|
||||
printFamilyTree(head);
|
||||
|
||||
linkFamily(head);
|
||||
printFamilyTree(head);
|
||||
aggregateStats(head);
|
||||
// printFamilyTree(head);
|
||||
|
||||
int clocks = sysconf(_SC_CLK_TCK);
|
||||
char *output = malloc(8 * 1024 * 1024);
|
||||
@ -272,14 +330,18 @@ char *readProcesses(char *procdir) {
|
||||
"pid=\"%d\",ppid=\"%d\",label=\"%s\",lxc=\"%d\"",
|
||||
cur->pid, cur->ppid, cur->label, cur->lxc);
|
||||
ptr += sprintf(ptr, "process_cpu_time_seconds{%s} %f\n", buffer, (double) cur->cpuTime / clocks);
|
||||
ptr += sprintf(ptr, "process_child_cpu_time_seconds{%s} %f\n", buffer,(double) cur->childCpuTime / clocks);
|
||||
ptr += sprintf(ptr, "process_num_threads{%s} %llu\n", buffer, cur->nThreads);
|
||||
ptr += sprintf(ptr, "process_resident_bytes{%s} %llu\n", buffer, cur->resident);
|
||||
ptr += sprintf(ptr, "process_swap_bytes{%s} %llu\n", buffer, cur->swap);
|
||||
ptr += sprintf(ptr, "process_fileio_bytes_written{%s} %llu\n", buffer, cur->written);
|
||||
ptr += sprintf(ptr, "process_fileio_bytes_read{%s} %llu\n", buffer, cur->read);
|
||||
ptr += sprintf(ptr, "process_num_threads{%s} %lu\n", buffer, cur->nThreads);
|
||||
ptr += sprintf(ptr, "process_resident_bytes{%s} %lu\n", buffer, cur->resident);
|
||||
ptr += sprintf(ptr, "process_swap_bytes{%s} %lu\n", buffer, cur->swap);
|
||||
ptr += sprintf(ptr, "process_fileio_bytes_written{%s} %lu\n", buffer, cur->written);
|
||||
ptr += sprintf(ptr, "process_fileio_bytes_read{%s} %lu\n", buffer, cur->read);
|
||||
ptr += sprintf(ptr, "process_is_kernel_process{%s} %d\n", buffer, cur->iskernel);
|
||||
ptr += sprintf(ptr, "process_tree_depth{%s} %d\n", buffer, cur->level);
|
||||
ptr += sprintf(ptr, "process_cumulative_cpu_time_seconds{%s} %lu\n", buffer, cur->cCpuTime);
|
||||
ptr += sprintf(ptr, "process_cumulative_resident_bytes{%s} %lu\n", buffer, cur->cMemory);
|
||||
ptr += sprintf(ptr, "process_cumulative_swap_bytes{%s} %lu\n", buffer, cur->cSwap);
|
||||
ptr += sprintf(ptr, "process_cumulative_bytes_read{%s} %lu\n", buffer, cur->cRead);
|
||||
ptr += sprintf(ptr, "process_cumulative_bytes_written{%s} %lu\n", buffer, cur->cWrite);
|
||||
// free and proceed
|
||||
Process *prev = cur;
|
||||
cur = cur->next;
|
||||
@ -361,7 +423,7 @@ int main(int argc, char *argv[]) {
|
||||
if (argc == 1) {
|
||||
char *buf = readProcesses("/proc");
|
||||
if (buf == NULL) return 4;
|
||||
//printf(buf);
|
||||
printf(buf);
|
||||
free(buf);
|
||||
return 0;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user