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:
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);