summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Bradley <jcb@pikum.xyz>2025-08-26 18:36:56 -0400
committerJonathan Bradley <jcb@pikum.xyz>2025-08-26 18:36:56 -0400
commit8086417171fd782e84d1e31a2dbfdf6ed7f97c75 (patch)
tree55181afaa03a2e7c3424be7fda072a6e49e06568
parent78956339691db1fb0de02e63823dc9100c0cd7e7 (diff)
pkfuncinstr: write json to file
-rw-r--r--.gitignore1
-rw-r--r--config.mk2
-rw-r--r--pkfuncinstr.h114
-rw-r--r--test/pkuuid.c4
4 files changed, 97 insertions, 24 deletions
diff --git a/.gitignore b/.gitignore
index 3eb7760..75a773b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
pk.h
+*.json
diff --git a/config.mk b/config.mk
index fdd9cfa..3728005 100644
--- a/config.mk
+++ b/config.mk
@@ -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();