diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2025-08-26 18:36:56 -0400 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2025-08-26 18:36:56 -0400 |
| commit | 8086417171fd782e84d1e31a2dbfdf6ed7f97c75 (patch) | |
| tree | 55181afaa03a2e7c3424be7fda072a6e49e06568 | |
| parent | 78956339691db1fb0de02e63823dc9100c0cd7e7 (diff) | |
pkfuncinstr: write json to file
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | config.mk | 2 | ||||
| -rw-r--r-- | pkfuncinstr.h | 114 | ||||
| -rw-r--r-- | test/pkuuid.c | 4 |
4 files changed, 97 insertions, 24 deletions
@@ -1 +1,2 @@ pk.h +*.json @@ -1,5 +1,5 @@ # pk.h version -VERSION = 0.7.1 +VERSION = 0.8.0 # paths PREFIX = /usr/local diff --git a/pkfuncinstr.h b/pkfuncinstr.h index 3a30bd3..151c60d 100644 --- a/pkfuncinstr.h +++ b/pkfuncinstr.h @@ -3,6 +3,8 @@ #include "./pktmr.h" /* deleteme */ +#include <stdio.h> + #define PK_FUNCINSTR_CHILDREN_INCREMENT_COUNT 8 struct pk_funcinstr; @@ -17,6 +19,7 @@ struct pk_funcinstr { }; void pk_funcinstr_init(); +void pk_funcinstr_set_ouputs(FILE *out, FILE *err); void pk_funcinstr_teardown(); #if defined(__cplusplus) @@ -27,6 +30,17 @@ extern "C" { // clang #elif defined(__GNUC__) || defined(__GNUG__) +#ifndef __USE_GNU + #define __USE_GNU +#endif +#if defined(__cplusplus) +#include <cxxabi.h> +#endif +#include <dlfcn.h> +#include <link.h> +#include <string.h> + + void __cyg_profile_func_enter(void* this_fn, void* call_site); void __cyg_profile_func_exit(void* this_fn, void* call_site); @@ -51,11 +65,11 @@ void __cyg_profile_func_exit(void* this_fn, void* call_site); // OR use some type of bucket // - might be a good chance to isolate some of the pkmem logic -#define PK_FUNCINSTR_BKT_START_COUNT 4 -#define PK_FUNCINSTR_BKT_GROW_AMOUNT 4 -#define PK_FUNCINSTR_BKT_DATA_COUNT 255 +#define PK_FUNCINSTR_BKT_START_COUNT 64 +#define PK_FUNCINSTR_BKT_GROW_RATIO 2.0 +#define PK_FUNCINSTR_BKT_DATA_COUNT 0xFFFF struct pk_funcinstr_bkt { - uint8_t used_count; + uint16_t used_count; uint8_t guard_enter; uint8_t guard_exit; struct timespec reset_time; @@ -63,6 +77,8 @@ struct pk_funcinstr_bkt { }; struct pk_funcinstr_mstr { mtx_t mtx; + FILE *out; + FILE *err; struct timespec reset_time; struct pk_funcinstr_bkt **buckets; size_t r_buckets; @@ -76,12 +92,16 @@ static struct pk_funcinstr_mstr thrd_mstr; __attribute__((no_instrument_function)) void pk_funcinstr_init() { + assert(thrd_mstr.out == NULL); + assert(thrd_mstr.err == NULL); assert(thrd_mstr.reset_time.tv_sec == 0); assert(thrd_mstr.reset_time.tv_nsec == 0); assert(thrd_mstr.buckets == NULL); assert(thrd_mstr.r_buckets == 0); assert(thrd_mstr.n_buckets == 0); mtx_init(&thrd_mstr.mtx, mtx_plain); + thrd_mstr.out = stdout; + thrd_mstr.err = stderr; thrd_mstr.r_buckets = PK_FUNCINSTR_BKT_START_COUNT; thrd_mstr.buckets = (struct pk_funcinstr_bkt**)aligned_alloc(alignof(struct pk_funcinstr_bkt *), (sizeof(struct pk_funcinstr_bkt *) * PK_FUNCINSTR_BKT_START_COUNT)); memset(thrd_mstr.buckets, 0, (sizeof(struct pk_funcinstr_bkt *) * PK_FUNCINSTR_BKT_START_COUNT)); @@ -89,6 +109,56 @@ void pk_funcinstr_init() { } __attribute__((no_instrument_function)) +void pk_funcinstr_set_ouputs(FILE *out, FILE *err) { + thrd_mstr.out = out; + thrd_mstr.err = err; +} + +__attribute__((no_instrument_function)) +void pk_funcinstr_write(FILE *f) { + int64_t i, k, s; + struct pk_funcinstr_bkt *bkt = nullptr; + struct pk_funcinstr *instr = nullptr; + struct pk_tmr fake_tmr; + Dl_info info; + mtx_lock(&thrd_mstr.mtx); + fake_tmr.b = thrd_mstr.reset_time; + fprintf(f, "["); + for (i = 0; i < (int64_t)thrd_mstr.n_buckets; ++i) { + bkt = thrd_mstr.buckets[i]; + for (k = 0; k < (int64_t)bkt->used_count; ++k) { + instr = &bkt->data[k]; + for (s = 0; s < 2; ++s) { + if (i == 0 && k == 0 && s == 0) { + fprintf(f, "{"); + } else { + fprintf(f, ",{"); + } + if (dladdr(instr->fn, &info) != 0) { + fprintf(f, "\"name\": \"%s\",", info.dli_sname); + } else { + fprintf(f, "\"name\": \"unknown\","); + } + fprintf(f, "\"cat\": \"%s\",", "funcinstr"); + if (s == 0) { + fake_tmr.e = instr->tmr.b; + fprintf(f, "\"ph\": \"%c\",", 'B'); + } else { + fake_tmr.e = instr->tmr.e; + fprintf(f, "\"ph\": \"%c\",", 'E'); + } + fprintf(f, "\"ts\": %lli,", pk_tmr_duration_u64_nano(fake_tmr)); + fprintf(f, "\"pid\": %i,", 69); + fprintf(f, "\"tid\": %ld", thrd_current()); + fprintf(f, "}"); + } + } + } + fprintf(f, "]"); + mtx_unlock(&thrd_mstr.mtx); +} + +__attribute__((no_instrument_function)) void pk_funcinstr_teardown() { int64_t i, k; mtx_lock(&thrd_mstr.mtx); @@ -99,6 +169,8 @@ void pk_funcinstr_teardown() { } } free(thrd_mstr.buckets); + thrd_mstr.out = NULL; + thrd_mstr.err = NULL; thrd_mstr.reset_time.tv_sec = 0; thrd_mstr.reset_time.tv_nsec = 0; thrd_mstr.buckets = NULL; @@ -113,16 +185,6 @@ void pk_funcinstr_teardown() { // Come up with pk macros since XRay requires attributes to instrument? #elif defined(__GNUC__) || defined(__GNUG__) -#ifndef __USE_GNU - #define __USE_GNU -#endif -#if defined(__cplusplus) -#include <cxxabi.h> -#endif -#include <dlfcn.h> -#include <link.h> -#include <string.h> - __attribute__((no_instrument_function)) bool pk_funcinstr_detect_not_initialized() { if (thrd_mstr.buckets == NULL) return true; @@ -148,7 +210,7 @@ void pk_funcinstr_detect_and_handle_reset() { if (should_reset) { if (thrd_mstr.n_buckets == thrd_mstr.r_buckets) { mtx_lock(&thrd_mstr.mtx); - thrd_mstr.r_buckets += PK_FUNCINSTR_BKT_GROW_AMOUNT; + thrd_mstr.r_buckets *= PK_FUNCINSTR_BKT_GROW_RATIO; struct pk_funcinstr_bkt **buckets = (struct pk_funcinstr_bkt**)aligned_alloc(alignof(void *), sizeof(void *) * thrd_mstr.r_buckets); memcpy(buckets, thrd_mstr.buckets, sizeof(void *) * (thrd_mstr.n_buckets)); memset((char*)buckets + (sizeof(void *) * (thrd_mstr.n_buckets)), 0, (sizeof(void *) * thrd_mstr.r_buckets) - sizeof(void *) * (thrd_mstr.n_buckets)); @@ -259,20 +321,24 @@ void __cyg_profile_func_exit(void* this_fn, void* call_site) { struct pk_tmr tmr = pk_funcinstr_thrd_instr->tmr; pk_funcinstr_thrd_instr = pk_funcinstr_create_funcinstr(this_fn); pk_funcinstr_thrd_instr->tmr = tmr; - fprintf(stdout, "[pkfuncinstr] func mismatch; Parent func? Duration not accurate."); +#ifdef PK_FUNCINSTR_PRINT + fprintf(thrd_mstr.out, "[pkfuncinstr] func mismatch; Parent func? Duration not accurate."); +#endif /* PK_FUNCINSTR_PRINT */ } else { - fprintf(stderr, "[pkfuncinstr] func mismatch. Last: '"); +#ifdef PK_FUNCINSTR_PRINT + fprintf(thrd_mstr.err, "[pkfuncinstr] func mismatch. Last: '"); if (dladdr(pk_funcinstr_thrd_instr->fn, &info) != 0) { - fprintf(stderr, "%s", info.dli_sname); + fprintf(thrd_mstr.err, "%s", info.dli_sname); } else { - fprintf(stderr, "(unknown)"); + fprintf(thrd_mstr.err, "(unknown)"); } - fprintf(stderr, "'. Current: '"); + fprintf(thrd_mstr.err, "'. Current: '"); if (dladdr(this_fn, &info) != 0) { - fprintf(stderr, "%s'.\n", info.dli_sname); + fprintf(thrd_mstr.err, "%s'.\n", info.dli_sname); } else { - fprintf(stderr, "(unknown)'.\n"); + fprintf(thrd_mstr.err, "(unknown)'.\n"); } +#endif /* PK_FUNCINSTR_PRINT */ pk_funcinstr_thrd_bkt->guard_exit=0; return; } @@ -293,12 +359,14 @@ void __cyg_profile_func_exit(void* this_fn, void* call_site) { demangled = abi::__cxa_demangle(info.dli_sname, NULL, NULL, NULL); #endif } - fprintf(stdout, "[pkfuncinstr] %p %*s %s took %.6f ms\n" +#ifdef PK_FUNCINSTR_PRINT + fprintf(thrd_mstr.out, "[pkfuncinstr] %p %*s %s took %.6f ms\n" ,this_fn ,depth, "" ,demangled != NULL ? demangled : info.dli_sname != NULL ? info.dli_sname : "???" ,pk_tmr_duration_dbl_mili(pk_funcinstr_thrd_instr->tmr) ); +#endif /* PK_FUNCINSTR_PRINT */ if (demangled != NULL) free(demangled); } pk_funcinstr_thrd_bkt->guard_exit=0; diff --git a/test/pkuuid.c b/test/pkuuid.c index d4f47ed..932d6c3 100644 --- a/test/pkuuid.c +++ b/test/pkuuid.c @@ -95,6 +95,7 @@ main(int argc, char *argv[]) if (equals != false) exit(1); } + FILE *f = fopen("perf.json", "w"); pk_funcinstr_init(); { const int count = 4; @@ -114,7 +115,10 @@ main(int argc, char *argv[]) } fprintf(stdout, "\n"); } + pk_funcinstr_write(f); pk_funcinstr_teardown(); + fflush(f); + fclose(f); // test parse pk_funcinstr_init(); |
