diff --git a/py/stat_flags.py b/py/stat_flags.py new file mode 100644 index 0000000..3ec1113 --- /dev/null +++ b/py/stat_flags.py @@ -0,0 +1,39 @@ +reverse_lookup = { + 0x00000001: "PF_VCPU", # I'm a virtual CPU + 0x00000002: "PF_IDLE", # I am an IDLE thread + 0x00000004: "PF_EXITING", # Getting shut down + 0x00000008: "PF_POSTCOREDUMP", # Coredumps should ignore this task + 0x00000010: "PF_IO_WORKER", # Task is an IO worker + 0x00000020: "PF_WQ_WORKER", # I'm a workqueue worker + 0x00000040: "PF_FORKNOEXEC", # Forked but didn't exec + 0x00000080: "PF_MCE_PROCESS", # Process policy on mce errors + 0x00000100: "PF_SUPERPRIV", # Used super-user privileges + 0x00000200: "PF_DUMPCORE", # Dumped core + 0x00000400: "PF_SIGNALED", # Killed by a signal + 0x00000800: "PF_MEMALLOC", # Allocating memory + 0x00001000: "PF_NPROC_EXCEEDED", # set_user() noticed that RLIMIT_NPROC was exceeded + 0x00002000: "PF_USED_MATH", # If unset the fpu must be initialized before use + 0x00004000: "PF_USER_WORKER", # Kernel thread cloned from userspace thread + 0x00008000: "PF_NOFREEZE", # This thread should not be frozen + 0x00010000: "PF__HOLE__00010000", + 0x00020000: "PF_KSWAPD", # I am kswapd + 0x00040000: "PF_MEMALLOC_NOFS", # All allocation requests will inherit GFP_NOFS + 0x00080000: "PF_MEMALLOC_NOIO", # All allocation requests will inherit GFP_NOIO + 0x00100000: "PF_LOCAL_THROTTLE", # Throttle writes only against the bdi I write to, I am cleaning dirty pages from some other bdi. + 0x00200000: "PF_KTHREAD", # I am a kernel thread + 0x00400000: "PF_RANDOMIZE", # Randomize virtual address space + 0x00800000: "PF__HOLE__00800000", + 0x01000000: "PF__HOLE__01000000", + 0x02000000: "PF__HOLE__02000000", + 0x04000000: "PF_NO_SETAFFINITY", # Userland is not allowed to meddle with cpus_mask + 0x08000000: "PF_MCE_EARLY", # Early kill for mce process policy + 0x10000000: "PF_MEMALLOC_PIN", # Allocation context constrained to zones which allow long term pinning. + 0x20000000: "PF__HOLE__20000000", + 0x40000000: "PF__HOLE__40000000", + 0x80000000: "PF_SUSPEND_TASK", # This thread called freeze_processes() and should not be frozen +} + +def listFlags(flag): + for i in reverse_lookup.keys(): + if flag & i: + print(reverse_lookup[i]) \ No newline at end of file diff --git a/src/process.h b/src/process.h index 688271c..822483f 100644 --- a/src/process.h +++ b/src/process.h @@ -14,13 +14,16 @@ typedef struct st_process { int ppid; int tgid; int level; - char *label; + char label[128]; int iskernel; // statistics - each outputs 1 line per process uint64_t cpuTime; uint64_t childCpuTime; uint64_t nThreads; uint64_t resident; + uint64_t swap; + uint64_t written; + uint64_t read; } Process; #endif diff --git a/src/server.c b/src/server.c index b36f2f2..34e67f2 100644 --- a/src/server.c +++ b/src/server.c @@ -65,28 +65,17 @@ int parseStatFile(Process *proc, char *filedata) { proc->ppid = fast_str2ull(&location); location += 1; - // (5) pgrp - %d - proc->tgid = fast_str2ll(&location); - location += 1; - - if (proc->tgid && proc->tgid != proc->pid) return -1; - - // (6) session - %d - location = strchr(location, ' ') + 1; - - // skip [7 - 14) - //skipRange(7,14); - skipRange(7, 9); + // skip [5 - 9) + skipRange(5, 9); // (9) flags - %u proc->flags = fast_str2ull(&location); location += 1; - printf("Flags for %d: %u %d\n", proc->pid, proc->flags, proc->flags & PF_KTHREAD); proc->iskernel = (proc->flags & PF_KTHREAD) ? true : false; - location += 1; - //skipRange(10, 14); + // skip [10 - 14) + skipRange(10, 14); // (14) utime - %lu proc->cpuTime = fast_str2ull(&location); @@ -107,34 +96,45 @@ int parseStatFile(Process *proc, char *filedata) { // skip 18-19 skipRange(18, 20); - // (20) - num_threads %ld + // (20) num_threads - %ld proc->nThreads = fast_str2ull(&location); location += 1; - // Skip 21-23 - skipRange(21,24); - - // (24) - rss %ld - proc->resident = fast_str2ull(&location); - location += 1; - return 0; } -int main(int argc, char *argv[]) { +inline int findAndParseField(char **filedata, char *fld) { + char *field = strstr(filedata, fld); + while (*(++field) != ':'); + while (*(++field) == ' '); + *filedata = field; + return fast_str2ull(filedata); +} + +int parseStatusFile(Process *proc, char *filedata) { + proc->pid = findAndParseField(&filedata, "Pid"); + proc->tgid = findAndParseField(&filedata, "Tgid"); + + if (proc->pid != proc->tgid) return -1; // ignore child threads, as their stats are the same as the parent + + proc->resident = 1024 * findAndParseField(&filedata, "VmRSS"); + proc->swap = 1024 * findAndParseField(&filedata, "VmSwap"); +} + +int parseIOFile(Process *proc, char *filedata) { + proc->read = findAndParseField(&filedata, "read_bytes"); + proc->written = findAndParseField(&filedata, "write_bytes"); + return 0; +} + +char *readProcesses(char *procdir) { + int len, rc = 1; struct dirent *pDirent; DIR *pDir; - // Ensure correct argument count. - - if (argc != 2) { - printf("Usage: testprog \n"); - return 1; - } - // Ensure we can open directory. - pDir = opendir(argv[1]); + pDir = opendir(procdir); if (pDir == NULL) { printf("Cannot open directory '%s'\n", argv[1]); return 1; @@ -144,35 +144,48 @@ int main(int argc, char *argv[]) { char *buffer = malloc(4096); char *fname = malloc(1024); + char first; FILE *file; Process *cur = malloc(sizeof(Process)); - cur->label = malloc(256); + cur->prev = NULL; + cur->next = NULL; Process *head = cur; while ((pDirent = readdir(pDir)) != NULL) { - char first = pDirent->d_name[0]; + first = pDirent->d_name[0]; if (first < '0' || first > '9') continue; - sprintf(fname, "/proc/%s/stat", pDirent->d_name); + sprintf(fname, "/proc/%s/status", pDirent->d_name); file = fopen(fname, "rb"); + if (file == NULL) continue; fread(buffer, 1, 4096, file); fclose(file); - if (parseStatFile(cur, buffer)) continue; - cur->next = malloc(sizeof(Process)); - cur->next->label = malloc(256); - cur->next->prev = cur; - cur = cur->next; + if (parseStatusFile(cur, buffer)) continue; + + // truncate 'status' to 'stat' + len = strlen(fname); + fname[len-2] = 0; - strcat(fname, "us"); file = fopen(fname, "rb"); + if (file == NULL) continue; fread(buffer, 1, 4096, file); fclose(file); - strtok(buffer, "\n"); + + if (parseStatFile(cur, buffer)) continue; + + file = fopen(fname, "rb"); + if (file == NULL) continue; + fread(buffer, 1, 4096, file); + fclose(file); + + if (parseIOFile(cur, buffer)) continue; + + cur->next = malloc(sizeof(Process)); + cur->next->prev = cur; + cur = cur->next; } - - closedir(pDir); - + // clean up unused last node cur = cur->prev; free(cur->next); cur->next = NULL; @@ -181,19 +194,35 @@ int main(int argc, char *argv[]) { cur = head; while (cur != NULL) { - // create process descriptor - sprintf(buffer, "pid=\"%d\",ppid=\"%d\",label=\"%s\",kernel=\"%d\"", cur->pid, cur->ppid, cur->label, cur->iskernel); - printf("proc_cpu_time{%s} %d\n", buffer, cur->cpuTime); - printf("proc_child_cpu_time{%s} %d\n", buffer, cur->childCpuTime / clocks); - printf("proc_num_threads{%s} %d\n", buffer, cur->nThreads); - printf("proc_resident_bytes{%s} %d\n", buffer, cur->resident); - cur = cur->next; + // create process descriptor + sprintf(buffer, "pid=\"%d\",ppid=\"%d\",label=\"%s\",kernel=\"%d\"", cur->pid, cur->ppid, cur->label, cur->iskernel); + printf("proc_cpu_time{%s} %lf\n", buffer, (double) cur->cpuTime / clocks); + printf("proc_child_cpu_time{%s} %lf\n", buffer, (double) cur->childCpuTime / clocks); + printf("proc_num_threads{%s} %llu\n", buffer, cur->nThreads); + printf("proc_resident_bytes{%s} %llu\n", buffer, cur->resident); + printf("proc_swap_bytes{%s} %llu\n", buffer, cur->swap); + printf("proc_fileio_bytes_written{%s} %llu\n", buffer, cur->written); + printf("proc_fileio_bytes_read{%s} %llu\n", buffer, cur->read); + cur = cur->next; } - return 0; + rc = 0; + +freeChain: + cur = head; + while (cur != NULL) { + Process *prev = cur; + cur = cur->next; + free(prev); + } + + closedir(pDir); + free(buffer); + free(fname); + return rc; } -#define PORT 8080 +#define PORT 9101 #define BUFFER_SIZE 1024 void handle_client(int client_socket) { @@ -201,10 +230,10 @@ void handle_client(int client_socket) { const char *http_response = "HTTP/1.1 200 OK\r\n" "Content-Type: text/plain\r\n" - "Content-Length: 13\r\n" + "Content-Length: 25\r\n" "Connection: close\r\n" "\r\n" - "Hello, World!"; + "test{data=\"something\"} 25"; // Send the response to the client send(client_socket, http_response, strlen(http_response), 0); @@ -213,7 +242,13 @@ void handle_client(int client_socket) { close(client_socket); } -int main2() { +int main(int argc, char *argv[]) { + + if (argc == 1) { + readProcesses("/proc"); + return; + } + int server_socket, client_socket; struct sockaddr_in server_addr, client_addr; socklen_t addr_len = sizeof(client_addr);