bunkum

an old and silly c99 web server with some fun features
Log | Files | Refs | README

commit 14ef848d116e7ab9178b8bff94fab25d118a89ff
parent f778a27c607ba779cae44fd074cf8eec3fbda50c
Author: quantumish <freifeld.david@gmail.com>
Date:   Tue, 16 May 2023 00:19:57 -0700

Profiling utilities, breaking change to shitvec_check()

Diffstat:
Mhttp.c | 44+-------------------------------------------
Autils/profile.c | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Autils/profile.h | 12++++++++++++
Mutils/shitvec.c | 6+++---
Mutils/shitvec.h | 2+-
5 files changed, 109 insertions(+), 47 deletions(-)

diff --git a/http.c b/http.c @@ -21,10 +21,6 @@ #include <netinet/in.h> #include <arpa/inet.h> -#include <pthread.h> -#include <libunwind.h> -#include <libunwind-ptrace.h> - #include "utils/log.h" #include "utils/time.h" #include "utils/shitvec.h" @@ -159,7 +155,7 @@ response_t make_response (request_t* req, int pfd) { strcpy(req->path, mapped_path); } - if (!shitvec_check(&paths, req->path, (sv_cmp_t)strcmp)) { + if (shitvec_check(&paths, req->path, (sv_cmp_t)strcmp) == -1) { return serve_error(NotFound); } @@ -232,43 +228,6 @@ void* listen_for_conns(void* ctxt) { } } -#define MAX_SYMLEN 32 - -shitvec_t profile(pid_t tid) { - shitvec_t stack = shitvec_new(MAX_SYMLEN); - errno = 0; - log_debug("Tracing %d", tid); - if (ptrace(PTRACE_ATTACH, tid) < 0) { - log_error("ptrace() fail, errno %d", errno); - } - kill(tid, SIGSTOP); - waitpid(tid, NULL, 0); - void* ui = _UPT_create(tid); - if (!ui) return -1; - unw_cursor_t c; - unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, 0); - unw_init_remote(&c, as, ui); - do { - unw_word_t offset; - char fname[MAX_SYMLEN] = {0}; - int resp = unw_get_proc_name(&c, fname, sizeof(fname), &offset); - log_trace("%s (code %d, errno %d)", fname, resp, errno); - shitvec_push(&stack, fname); - } while(unw_step(&c) > 0); - _UPT_resume(as, &c, ui); - _UPT_destroy(ui); - kill(tid, SIGSTOP); - waitpid(tid, NULL, 0); - ptrace(PTRACE_DETACH, tid, NULL, NULL); - return stack; -} - -struct tree_node { - struct tree_node* left; - struct tree_node* right; - char name[MAX_SYMLEN]; -}; - struct conn_ctxt { pid_t pid; int fd; @@ -340,7 +299,6 @@ int main() { } } - // meta todos: // - TODO true dependencyless (no zlib, no pthread) // - TODO HTML parsing maybe but that makes me want to cry diff --git a/utils/profile.c b/utils/profile.c @@ -0,0 +1,92 @@ +#include <string.h> +#include <errno.h> + +#include <sys/ptrace.h> +#include <sys/wait.h> +#include <sys/fcntl.h> + +#include <pthread.h> +#include <libunwind.h> +#include <libunwind-ptrace.h> + +#include "log.h" +#include "profile.h" + +struct profile_node { + char symbol[MAX_SYMLEN]; + unsigned int samples; + shitvec_t children; +}; + +shitvec_t profile(pid_t tid) { + shitvec_t stack = shitvec_new(MAX_SYMLEN); + errno = 0; + log_debug("Tracing %d", tid); + if (ptrace(PTRACE_ATTACH, tid) < 0) { + log_error("ptrace() fail, errno %d", errno); + } + kill(tid, SIGSTOP); + waitpid(tid, NULL, 0); + void* ui = _UPT_create(tid); + unw_cursor_t c; + unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, 0); + unw_init_remote(&c, as, ui); + do { + unw_word_t offset; + char fname[MAX_SYMLEN] = {0}; + int resp = unw_get_proc_name(&c, fname, sizeof(fname), &offset); + log_trace("%s (code %d, errno %d)", fname, resp, errno); + shitvec_push(&stack, fname); + } while(unw_step(&c) > 0); + _UPT_resume(as, &c, ui); + _UPT_destroy(ui); + kill(tid, SIGSTOP); + waitpid(tid, NULL, 0); + ptrace(PTRACE_DETACH, tid, NULL, NULL); + return stack; +} + +struct profile_node profile_node_new(char* name) { + struct profile_node out = { + .children = shitvec_new(sizeof(struct profile_node)), + .samples = 0, + .symbol = {0} + }; + strcpy(out.symbol, name); + return out; +} + +shitvec_t profile_res_new() { + return shitvec_new(sizeof(shitvec_t)); +} + +int cmp_prof_node(void* _a, void* _b) { + struct profile_node* a = _a; + struct profile_node* b = _b; + return strcmp(a->symbol, b->symbol); +} + +void profile_proc_stack(shitvec_t* prof_res, shitvec_t* stack) { + if (stack->vec_sz == 0) return; + // NOTE maybe just have a fake root node (would make this base case not needed) + int index = shitvec_check(prof_res, shitvec_get(stack, 0), cmp_prof_node); + if (index == -1) { + struct profile_node new = profile_node_new(shitvec_get(stack, 0)); + shitvec_push(prof_res, &new); + index = prof_res->vec_sz - 1; + } + struct profile_node* node = shitvec_get(prof_res, index); + node->samples += 1; + + for (int i = 0; i < stack->vec_sz; i++) { + char* sym = shitvec_get(stack, i); + int index = shitvec_check(&node->children, sym, cmp_prof_node); + if (index == -1) { + struct profile_node new = profile_node_new(sym); + shitvec_push(prof_res, &new); + index = prof_res->vec_sz - 1; + } + node = shitvec_get(&node->children, index); + node->samples += 1; + } +} diff --git a/utils/profile.h b/utils/profile.h @@ -0,0 +1,12 @@ +#ifndef PROFILE_H +#define PROFILE_H + +#include <sys/types.h> + +#include "shitvec.h" + +#define MAX_SYMLEN 32 +shitvec_t profile(pid_t pid); + + +#endif diff --git a/utils/shitvec.c b/utils/shitvec.c @@ -41,13 +41,13 @@ void shitvec_subpush(shitvec_t* sv, void* item, size_t sz) { memcpy(sv->arr+(sv->vec_sz * sv->e_sz), item, sz); } -bool shitvec_check(shitvec_t* sv, void* item, sv_cmp_t cmp) { +int shitvec_check(shitvec_t* sv, void* item, sv_cmp_t cmp) { for (size_t i = 0; i < sv->vec_sz; i++) { if (cmp(sv->arr+(i*sv->e_sz), item) == 0) { - return true; + return i; } } - return false; + return -1; } void shitvec_sort(shitvec_t* sv, int(*cmp)(const void*, const void*)) { diff --git a/utils/shitvec.h b/utils/shitvec.h @@ -20,7 +20,7 @@ void* shitvec_get(shitvec_t* sv, size_t index); void* shitvec_last(shitvec_t* sv); void shitvec_push(shitvec_t* sv, void* item); void shitvec_subpush(shitvec_t* sv, void* item, size_t sz); -bool shitvec_check(shitvec_t* sv, void* item, sv_cmp_t cmp); +int shitvec_check(shitvec_t* sv, void* item, sv_cmp_t cmp); void shitvec_sort(shitvec_t* sv, int(*cmp)(const void*, const void*)); void shitvec_free(shitvec_t* sv);