kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit 5e69b646150a00a9b2db85dc89f5fdc5eacd1f3e
parent 62709d0deefba724be60743649962c604f808d87
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Sun, 14 Jun 2026 11:28:40 -0700

Add concrete profiler API

Diffstat:
Mdriver/cmd/run.c | 243+++++++++++++++++++++++++------------------------------------------------------
Mdriver/env.h | 12++++++------
Mdriver/env/posix.c | 4++--
Mdriver/env/windows.c | 4++--
Mdriver/lib/inputs.c | 33++++++++++++++++++++++-----------
Minclude/kit/core.h | 45++++++++++++++++++++++++++++++++++++---------
Minclude/kit/frontend.h | 15++++++++++-----
Ainclude/kit/profile.h | 387+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlang/c/c.c | 102++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Mmk/test_unit.mk | 5++++-
Msrc/api/frontend.c | 25++++++++++++++++++-------
Msrc/core/metrics.h | 230+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Asrc/core/profile.c | 299+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/core/profile.h | 33+++++++++++++++++++++++++++++++++
Atest/api/profile_test.c | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtest/elf/unit/align_4k.c | 1-
Mtest/elf/unit/groupiter.c | 1-
Mtest/elf/unit/mutate.c | 1-
18 files changed, 1278 insertions(+), 243 deletions(-)

diff --git a/driver/cmd/run.c b/driver/cmd/run.c @@ -54,177 +54,83 @@ typedef struct RunOptions { uint32_t prog_argc; } RunOptions; -/* Buffered metrics sink. The hot path (scope_begin/end/count called from - * libkit during compile/link/JIT) does no I/O: each event is appended to - * a segmented event log, and scopes maintain only a small live stack to - * carry the start_ns across to scope_end. All formatting and stderr writes - * happen once in run_metrics_finish at the very end of the run. - * - * Storage is a singly-linked list of fixed-size segments. Each segment is - * allocated once and never moves — geometric vector growth would amortize - * to O(log N) copies, but with a chunk list we get zero copies and the - * hot path is just an index increment + 24-byte store. We only ever drain - * the log sequentially, so a segment table is unnecessary. */ - -#define RUN_METRIC_MAX_DEPTH 64u -#define RUN_METRIC_SEG_EVENTS 256u - -typedef enum RunMetricEventKind { - RUN_METRIC_EVENT_SCOPE = 0, - RUN_METRIC_EVENT_COUNT = 1, -} RunMetricEventKind; - -typedef struct RunMetricEvent { - const char* name; /* aliased; callers pass string literals */ - uint64_t value; /* SCOPE: elapsed_ns; COUNT: count value */ - uint16_t depth; /* nesting depth at emit time (0-based) */ - uint16_t kind; -} RunMetricEvent; - -typedef struct RunMetricSeg { - struct RunMetricSeg* next; - uint32_t nused; - RunMetricEvent events[RUN_METRIC_SEG_EVENTS]; -} RunMetricSeg; - -typedef struct RunMetricFrame { - const char* name; - uint64_t start_ns; -} RunMetricFrame; +/* `kit run` owns the concrete profiler storage and only formats it after the + * run completes. Libkit's hot path just updates the arrays in KitProfiler. */ + +#define RUN_PROFILE_SCOPE_TOTAL \ + ((KitProfileScope)(KIT_PROFILE_SCOPE_EXTERNAL_FIRST + 0u)) +#define RUN_PROFILE_SCOPE_COMPILE_AND_JIT \ + ((KitProfileScope)(KIT_PROFILE_SCOPE_EXTERNAL_FIRST + 1u)) +#define RUN_PROFILE_SCOPE_JIT_LOOKUP \ + ((KitProfileScope)(KIT_PROFILE_SCOPE_EXTERNAL_FIRST + 2u)) +#define RUN_PROFILE_SCOPE_ENTRY_CALL \ + ((KitProfileScope)(KIT_PROFILE_SCOPE_EXTERNAL_FIRST + 3u)) typedef struct RunMetrics { - KitMetrics iface; - RunMetricFrame stack[RUN_METRIC_MAX_DEPTH]; - uint32_t depth; - int bench_time; - + KitProfiler profile; DriverEnv* env; - RunMetricSeg* head; - RunMetricSeg* tail; - int oom; /* sticky: drop further events after an allocation failure */ } RunMetrics; -static void run_metrics_push_event(RunMetrics* m, RunMetricEventKind kind, - const char* name, uint64_t value, - uint32_t depth) { - RunMetricSeg* seg; - RunMetricEvent* ev; - if (m->oom) return; - seg = m->tail; - if (!seg || seg->nused == RUN_METRIC_SEG_EVENTS) { - RunMetricSeg* ns = driver_alloc_zeroed(m->env, sizeof(RunMetricSeg)); - if (!ns) { - m->oom = 1; - return; - } - if (m->tail) - m->tail->next = ns; - else - m->head = ns; - m->tail = ns; - seg = ns; - } - ev = &seg->events[seg->nused++]; - ev->name = name; - ev->value = value; - ev->depth = (uint16_t)depth; - ev->kind = (uint16_t)kind; -} - -static void run_metrics_scope_begin(void* user, const char* name) { - RunMetrics* m = (RunMetrics*)user; - if (!m || m->depth >= RUN_METRIC_MAX_DEPTH) return; - m->stack[m->depth].name = name; - m->stack[m->depth].start_ns = driver_now_ns(); - m->depth++; -} - -static void run_metrics_scope_end(void* user, const char* name) { - RunMetrics* m = (RunMetrics*)user; - RunMetricFrame f; - uint64_t end_ns; - uint64_t elapsed; - uint32_t depth; - const char* scope_name; - if (!m || m->depth == 0) return; - m->depth--; - depth = m->depth; - f = m->stack[depth]; - end_ns = driver_now_ns(); - elapsed = (end_ns >= f.start_ns) ? (end_ns - f.start_ns) : 0; - scope_name = f.name ? f.name : name; - run_metrics_push_event(m, RUN_METRIC_EVENT_SCOPE, scope_name, elapsed, depth); -} - -static void run_metrics_count(void* user, const char* name, uint64_t value) { - RunMetrics* m = (RunMetrics*)user; - if (!m) return; - run_metrics_push_event(m, RUN_METRIC_EVENT_COUNT, name, value, m->depth); +static void run_profile_define_run_scopes(RunMetrics* m) { + kit_profiler_define_scope(&m->profile, RUN_PROFILE_SCOPE_TOTAL, "run.total"); + kit_profiler_define_scope(&m->profile, RUN_PROFILE_SCOPE_COMPILE_AND_JIT, + "run.compile_and_jit"); + kit_profiler_define_scope(&m->profile, RUN_PROFILE_SCOPE_JIT_LOOKUP, + "run.jit_lookup"); + kit_profiler_define_scope(&m->profile, RUN_PROFILE_SCOPE_ENTRY_CALL, + "run.entry_call"); } -static void run_metrics_init(RunMetrics* m, DriverEnv* env, int bench_time) { - m->iface.scope_begin = run_metrics_scope_begin; - m->iface.scope_end = run_metrics_scope_end; - m->iface.count = run_metrics_count; - m->iface.user = m; - m->depth = 0; - m->bench_time = bench_time; +static void run_metrics_init(RunMetrics* m, DriverEnv* env) { + kit_profiler_reset(&m->profile); m->env = env; - m->head = NULL; - m->tail = NULL; - m->oom = 0; + run_profile_define_run_scopes(m); } -static void run_metrics_begin(RunMetrics* m, const char* name) { - if (m) m->iface.scope_begin(m->iface.user, name); +static void run_metrics_begin(RunMetrics* m, KitProfileScope scope) { + if (m) kit_profiler_scope_begin(&m->profile, scope); } -static void run_metrics_end(RunMetrics* m, const char* name) { - if (m) m->iface.scope_end(m->iface.user, name); +static void run_metrics_end(RunMetrics* m, KitProfileScope scope) { + if (m) kit_profiler_scope_end(&m->profile, scope); } -/* Close any still-open scopes (early-return paths emit synthesized ends), - * then walk the segmented event log in push order and format each event - * to stderr. Free segments after draining. Called exactly once per run. */ +/* Close any still-open scopes, then export aggregate profiler state. */ static void run_metrics_finish(RunMetrics* m) { - RunMetricSeg* seg; + uint32_t id; if (!m) return; - while (m->depth) { - const char* name = m->stack[m->depth - 1u].name; - run_metrics_scope_end(m, name); + while (m->profile.depth) { + KitProfileFrame* f = &m->profile.stack[m->profile.depth - 1u]; + kit_profiler_scope_end(&m->profile, (KitProfileScope)f->id); } - for (seg = m->head; seg; seg = seg->next) { - uint32_t i; - for (i = 0; i < seg->nused; ++i) { - const RunMetricEvent* e = &seg->events[i]; - if (e->kind == RUN_METRIC_EVENT_SCOPE) { - if (m->bench_time) { - driver_logf("kit-run %.*s -- %.3f msec", - KIT_SLICE_ARG(kit_slice_cstr(e->name)), - (double)e->value / 1000000.0); - } else { - driver_logf("%*s%.*s %.3f ms", (int)((unsigned)e->depth * 2u), "", - KIT_SLICE_ARG(kit_slice_cstr(e->name)), - (double)e->value / 1000000.0); - } - } else { - driver_logf("%*s%.*s=%llu", (int)((unsigned)e->depth * 2u), "", - KIT_SLICE_ARG(kit_slice_cstr(e->name)), - (unsigned long long)e->value); - } + for (id = 1; id < KIT_PROFILE_ID_COUNT; ++id) { + uint64_t count = m->profile.scope_count[id]; + uint64_t ticks = m->profile.scope_ticks[id]; + if (count) { + const char* name = + kit_profiler_scope_name(&m->profile, (KitProfileScope)id); + if (!name) name = "profile.scope"; + driver_logf("%.*s %llu ticks (%llu calls)", + KIT_SLICE_ARG(kit_slice_cstr(name)), + (unsigned long long)ticks, (unsigned long long)count); } } - if (m->oom) { - driver_logf("(metrics: event buffer allocation failed; some events lost)"); - } - seg = m->head; - while (seg) { - RunMetricSeg* next = seg->next; - driver_free(m->env, seg, sizeof(RunMetricSeg)); - seg = next; + for (id = 1; id < KIT_PROFILE_ID_COUNT; ++id) { + uint64_t value = m->profile.counters[id]; + if (value) { + const char* name = + kit_profiler_counter_name(&m->profile, (KitProfileCounter)id); + if (!name) name = "profile.counter"; + driver_logf("%.*s=%llu", KIT_SLICE_ARG(kit_slice_cstr(name)), + (unsigned long long)value); + } } - m->head = NULL; - m->tail = NULL; + if (m->profile.stack_overflow) + driver_logf("profile.stack_overflow=%u", + (unsigned)m->profile.stack_overflow); + if (m->profile.def_overflow) + driver_logf("profile.def_overflow=%u", (unsigned)m->profile.def_overflow); + driver_free(m->env, m, sizeof(*m)); } static void run_bench_time(const char* name, uint64_t ns) { @@ -277,7 +183,7 @@ void driver_help_run(void) { "-O1\n" " minimum so the optimizer IR is available)\n" " -g Emit DWARF debug info\n" - " --time, --metrics Emit scoped compile/link/JIT timing to stderr\n" + " --time, --metrics Emit scoped compile/link/JIT ticks to stderr\n" " --bench-time Emit parseable compile/JIT/execution timings\n" " -e SYMBOL Entry symbol (default `main`)\n" " -target TRIPLE Cross-compile target (see `kit cc --help`)\n" @@ -920,7 +826,6 @@ int driver_run(int argc, char** argv) { KitCompiler* compiler = NULL; KitJit* jit = NULL; KitInterpProgram* interp = NULL; - RunMetrics metrics_storage; RunMetrics* metrics = NULL; void* sym; MainFn entry_fn; @@ -945,12 +850,18 @@ int driver_run(int argc, char** argv) { return 2; } - if (ro.metrics || ro.bench_time) { - run_metrics_init(&metrics_storage, &env, ro.bench_time); - metrics = &metrics_storage; - env.metrics = &metrics->iface; + if (ro.metrics) { + metrics = driver_alloc_zeroed(&env, sizeof(*metrics)); + if (!metrics) { + driver_errf(RUN_TOOL, "out of memory"); + run_options_release(&ro); + driver_env_fini(&env); + return 1; + } + run_metrics_init(metrics, &env); + env.profiler = &metrics->profile; if (ro.metrics && !ro.bench_time) driver_logf("kit metrics:"); - run_metrics_begin(metrics, "run.total"); + run_metrics_begin(metrics, RUN_PROFILE_SCOPE_TOTAL); } if (ro.bench_time) bench_total_start = driver_now_ns(); @@ -988,9 +899,9 @@ int driver_run(int argc, char** argv) { } if (ro.bench_time) bench_compile_start = driver_now_ns(); - run_metrics_begin(metrics, "run.compile_and_jit"); + run_metrics_begin(metrics, RUN_PROFILE_SCOPE_COMPILE_AND_JIT); rc = run_compile_and_jit(&ro, compiler, &jhost, &jit); - run_metrics_end(metrics, "run.compile_and_jit"); + run_metrics_end(metrics, RUN_PROFILE_SCOPE_COMPILE_AND_JIT); if (ro.bench_time) bench_compile_end = driver_now_ns(); if (rc != 0) { if (ro.bench_time) @@ -1020,9 +931,9 @@ int driver_run(int argc, char** argv) { return 1; } - run_metrics_begin(metrics, "run.jit_lookup"); + run_metrics_begin(metrics, RUN_PROFILE_SCOPE_JIT_LOOKUP); sym = kit_jit_lookup(jit, kit_slice_cstr(ro.entry)); - run_metrics_end(metrics, "run.jit_lookup"); + run_metrics_end(metrics, RUN_PROFILE_SCOPE_JIT_LOOKUP); if (!sym) { driver_errf(RUN_TOOL, "entry symbol not found: %.*s", KIT_SLICE_ARG(kit_slice_cstr(ro.entry))); @@ -1081,11 +992,11 @@ int driver_run(int argc, char** argv) { rc = 1; goto after_entry; } - run_metrics_begin(metrics, "run.entry_call"); + run_metrics_begin(metrics, RUN_PROFILE_SCOPE_ENTRY_CALL); if (ro.bench_time) bench_exec_start = driver_now_ns(); s = kit_interp_call(interp, ifn, (int)ro.prog_argc, ro.prog_argv, &ret); if (ro.bench_time) bench_exec_end = driver_now_ns(); - run_metrics_end(metrics, "run.entry_call"); + run_metrics_end(metrics, RUN_PROFILE_SCOPE_ENTRY_CALL); if (s == KIT_INTERP_DONE) { rc = (int)ret; } else { @@ -1098,7 +1009,7 @@ int driver_run(int argc, char** argv) { goto after_entry; } - run_metrics_begin(metrics, "run.entry_call"); + run_metrics_begin(metrics, RUN_PROFILE_SCOPE_ENTRY_CALL); if (ro.bench_time) bench_exec_start = driver_now_ns(); if (!driver_wasm_run_call_entry(&ro.wasm, RUN_TOOL, compiler, jit, sym, &rc)) { @@ -1117,7 +1028,7 @@ int driver_run(int argc, char** argv) { } } if (ro.bench_time) bench_exec_end = driver_now_ns(); - run_metrics_end(metrics, "run.entry_call"); + run_metrics_end(metrics, RUN_PROFILE_SCOPE_ENTRY_CALL); after_entry: if (ro.bench_time) { run_bench_time("compile_and_jit", bench_compile_end - bench_compile_start); diff --git a/driver/env.h b/driver/env.h @@ -24,10 +24,10 @@ typedef struct DriverEnv { KitDiagSink* diag; KitFileIO file_io; const KitExecMem* execmem; - const KitDbgOs* dbg_os; /* NULL unless `kit dbg` paths run */ - const KitMetrics* metrics; /* optional scoped metrics sink */ - int64_t now; /* unix seconds; -1 = unknown */ - const char* cache_dir; /* base cache dir, e.g. ~/.cache/kit */ + const KitDbgOs* dbg_os; /* NULL unless `kit dbg` paths run */ + KitProfiler* profiler; /* optional low-overhead profiling storage */ + int64_t now; /* unix seconds; -1 = unknown */ + const char* cache_dir; /* base cache dir, e.g. ~/.cache/kit */ } DriverEnv; void driver_env_init(DriverEnv*); @@ -241,8 +241,8 @@ int driver_walk_regular_files(DriverEnv*, const char* root, DriverWalkFileFn, void driver_errf(const char* tool, const char* fmt, ...); void driver_verrf(const char* tool, const char* fmt, va_list ap); -/* Raw hosted stderr log. Used by optional metrics so libkit stays callback- - * only and freestanding. */ +/* Raw hosted stderr log. Used by optional metrics/profiling output so libkit + * stays free of hosted I/O. */ void driver_logf(const char* fmt, ...); /* Formatted output to stdout. */ diff --git a/driver/env/posix.c b/driver/env/posix.c @@ -1445,7 +1445,7 @@ void driver_env_init(DriverEnv* e) { e->execmem = &g_execmem_posix; e->dbg_os = &g_dbg_os_posix; - e->metrics = NULL; + e->profiler = NULL; { const char* xdg = getenv("XDG_CACHE_HOME"); @@ -1484,7 +1484,7 @@ KitContext driver_env_to_context(const DriverEnv* e) { c.heap = e->heap; c.file_io = &e->file_io; c.diag = e->diag; - c.metrics = e->metrics; + c.profiler = e->profiler; c.now = e->now; return c; } diff --git a/driver/env/windows.c b/driver/env/windows.c @@ -1955,7 +1955,7 @@ void driver_env_init(DriverEnv* e) { e->execmem = &g_execmem_win; e->dbg_os = &g_dbg_os_win; - e->metrics = NULL; + e->profiler = NULL; { /* XDG_CACHE_HOME wins if set (cross-platform tooling convention), @@ -1994,7 +1994,7 @@ KitContext driver_env_to_context(const DriverEnv* e) { c.heap = e->heap; c.file_io = &e->file_io; c.diag = e->diag; - c.metrics = e->metrics; + c.profiler = e->profiler; c.now = e->now; return c; } diff --git a/driver/lib/inputs.c b/driver/lib/inputs.c @@ -171,15 +171,18 @@ int driver_inputs_compile_and_jit( } /* Load source files into KitSlice and compile them into object builders. */ - kit_frontend_metrics_scope_begin(compiler, "driver.load_sources"); + kit_frontend_profile_scope_begin(compiler, + KIT_PROFILE_SCOPE_DRIVER_LOAD_SOURCES); for (i = 0; i < in->nsources; ++i) { if (driver_load_bytes(io, tool, in->sources[i], &src_lf[i], &src_bytes[i]) != 0) { - kit_frontend_metrics_scope_end(compiler, "driver.load_sources"); + kit_frontend_profile_scope_end(compiler, + KIT_PROFILE_SCOPE_DRIVER_LOAD_SOURCES); goto out; } } - kit_frontend_metrics_scope_end(compiler, "driver.load_sources"); + kit_frontend_profile_scope_end(compiler, + KIT_PROFILE_SCOPE_DRIVER_LOAD_SOURCES); for (i = 0; i < in->nsources; ++i) { KitLanguage lang = kit_language_for_path(compiler, in->sources[i]); @@ -218,27 +221,33 @@ int driver_inputs_compile_and_jit( if (st != KIT_OK) goto out; } - kit_frontend_metrics_scope_begin(compiler, "driver.load_objects"); + kit_frontend_profile_scope_begin(compiler, + KIT_PROFILE_SCOPE_DRIVER_LOAD_OBJECTS); for (i = 0; i < in->nobject_files; ++i) { if (driver_load_bytes(io, tool, in->object_files[i], &obj_lf[i], &obj_in[i]) != 0) { - kit_frontend_metrics_scope_end(compiler, "driver.load_objects"); + kit_frontend_profile_scope_end(compiler, + KIT_PROFILE_SCOPE_DRIVER_LOAD_OBJECTS); goto out; } } - kit_frontend_metrics_scope_end(compiler, "driver.load_objects"); - kit_frontend_metrics_scope_begin(compiler, "driver.load_archives"); + kit_frontend_profile_scope_end(compiler, + KIT_PROFILE_SCOPE_DRIVER_LOAD_OBJECTS); + kit_frontend_profile_scope_begin(compiler, + KIT_PROFILE_SCOPE_DRIVER_LOAD_ARCHIVES); for (i = 0; i < in->narchives; ++i) { if (driver_load_bytes(io, tool, in->archives[i], &arch_lf[i], &arch_in[i].bytes) != 0) { - kit_frontend_metrics_scope_end(compiler, "driver.load_archives"); + kit_frontend_profile_scope_end(compiler, + KIT_PROFILE_SCOPE_DRIVER_LOAD_ARCHIVES); goto out; } arch_in[i].link_mode = KIT_LM_DEFAULT; arch_in[i].whole_archive = 0; arch_in[i].group_id = 0; } - kit_frontend_metrics_scope_end(compiler, "driver.load_archives"); + kit_frontend_profile_scope_end(compiler, + KIT_PROFILE_SCOPE_DRIVER_LOAD_ARCHIVES); { KitLinkSessionOptions lopts; @@ -249,7 +258,8 @@ int driver_inputs_compile_and_jit( lopts.jit_host = host; lopts.extern_resolver = extern_resolver; lopts.extern_resolver_user = extern_resolver_user; - kit_frontend_metrics_scope_begin(compiler, "driver.link_setup"); + kit_frontend_profile_scope_begin(compiler, + KIT_PROFILE_SCOPE_DRIVER_LINK_SETUP); st = kit_link_session_new(compiler, &lopts, &link); for (i = 0; st == KIT_OK && i < nsrc; ++i) st = kit_link_session_add_obj(link, objs[i]); @@ -258,7 +268,8 @@ int driver_inputs_compile_and_jit( link, kit_slice_cstr(in->object_files[i]), &obj_in[i]); for (i = 0; st == KIT_OK && i < in->narchives; ++i) st = kit_link_session_add_archive_bytes(link, &arch_in[i]); - kit_frontend_metrics_scope_end(compiler, "driver.link_setup"); + kit_frontend_profile_scope_end(compiler, + KIT_PROFILE_SCOPE_DRIVER_LINK_SETUP); if (st == KIT_OK) st = kit_link_session_jit(link, out_jit); rc = st == KIT_OK ? 0 : 1; } diff --git a/include/kit/core.h b/include/kit/core.h @@ -26,7 +26,9 @@ #endif #endif -/* Developer tracing (KIT_TRACE / KIT_LOG*) is part of the core substrate. */ +/* Developer tracing (KIT_TRACE / KIT_LOG*) and profiling are part of the core + * substrate. */ +#include <kit/profile.h> #include <kit/trace.h> /* Opaque handles shared across component headers. */ @@ -373,13 +375,6 @@ typedef struct KitFileIO { void* user; } KitFileIO; -typedef struct KitMetrics { - void (*scope_begin)(void* user, const char* name); - void (*scope_end)(void* user, const char* name); - void (*count)(void* user, const char* name, uint64_t value); - void* user; -} KitMetrics; - typedef struct KitContext { KitHeap* heap; /* Optional. Source compilation uses this for include resolution and output @@ -387,11 +382,43 @@ typedef struct KitContext { * disassembly ignore it. */ const KitFileIO* file_io; KitDiagSink* diag; - const KitMetrics* metrics; + KitProfiler* profiler; /* Unix seconds, or negative when the host provides no clock. */ int64_t now; } KitContext; +static inline KitProfiler* kit_context_profiler(const KitContext* ctx) { + return ctx ? ctx->profiler : (KitProfiler*)0; +} + +static inline void kit_profile_scope_begin(const KitContext* ctx, + KitProfileScope scope) { + kit_profiler_scope_begin(kit_context_profiler(ctx), scope); +} + +static inline void kit_profile_scope_end(const KitContext* ctx, + KitProfileScope scope) { + kit_profiler_scope_end(kit_context_profiler(ctx), scope); +} + +static inline void kit_profile_count(const KitContext* ctx, + KitProfileCounter counter, + uint64_t value) { + kit_profiler_count(kit_context_profiler(ctx), counter, value); +} + +static inline void kit_profile_define_scope(const KitContext* ctx, + KitProfileScope scope, + const char* name) { + kit_profiler_define_scope(kit_context_profiler(ctx), scope, name); +} + +static inline void kit_profile_define_counter(const KitContext* ctx, + KitProfileCounter counter, + const char* name) { + kit_profiler_define_counter(kit_context_profiler(ctx), counter, name); +} + KIT_API KitStatus kit_target_new(const KitContext*, const KitTargetOptions*, KitTarget** out); KIT_API void kit_target_free(KitTarget*); diff --git a/include/kit/frontend.h b/include/kit/frontend.h @@ -34,13 +34,18 @@ typedef KitStatus (*KitFrontendRunFn)(KitCompiler*, void* user); KIT_API KitStatus kit_frontend_run(KitCompiler*, KitFrontendRunFn, void* user); -/* Optional metrics bridge for frontends. These are no-ops unless the host - * supplied KitContext.metrics. Frontends use this public shim instead of +/* Optional profiling bridge for frontends. These are no-ops unless the host + * supplied KitContext.profiler. Frontends use this public shim instead of * depending on libkit's internal core headers. */ -KIT_API void kit_frontend_metrics_scope_begin(KitCompiler*, const char* name); -KIT_API void kit_frontend_metrics_scope_end(KitCompiler*, const char* name); -KIT_API void kit_frontend_metrics_count(KitCompiler*, const char* name, +KIT_API void kit_frontend_profile_scope_begin(KitCompiler*, KitProfileScope); +KIT_API void kit_frontend_profile_scope_end(KitCompiler*, KitProfileScope); +KIT_API void kit_frontend_profile_count(KitCompiler*, KitProfileCounter, uint64_t value); +KIT_API void kit_frontend_profile_define_scope(KitCompiler*, KitProfileScope, + const char* name); +KIT_API void kit_frontend_profile_define_counter(KitCompiler*, + KitProfileCounter, + const char* name); KIT_API _Noreturn void kit_frontend_fatal(KitCompiler*, KitSrcLoc, const char* fmt, ...); diff --git a/include/kit/profile.h b/include/kit/profile.h @@ -0,0 +1,387 @@ +#ifndef KIT_PROFILE_H +#define KIT_PROFILE_H + +/* + * Low-overhead profiling. + * + * The profiler API is numeric on the hot path: scopes and counters are open + * enum values, not strings. Kit owns the low scope/counter ranges; language + * frontends and external embedders get reserved ranges and may attach names + * once into the concrete profiler. A disabled profiler costs one pointer check. + * + * The concrete KitProfiler owns counters/timers only. It performs no I/O and + * does not allocate; embedders export/report the exposed arrays however they + * want. Scope timers are accumulated in raw cycle/tick units from the host CPU + * counter where available. + */ + +#include <stdint.h> + +#ifndef KIT_API +#if defined(__GNUC__) || defined(__clang__) || defined(__kit__) +#define KIT_API __attribute__((visibility("default"))) +#else +#define KIT_API +#endif +#endif + +typedef enum KitProfileScope { + KIT_PROFILE_SCOPE_NONE = 0, + + KIT_PROFILE_SCOPE_KIT_FIRST = 1, + KIT_PROFILE_SCOPE_COMPILE_TU = KIT_PROFILE_SCOPE_KIT_FIRST, + KIT_PROFILE_SCOPE_COMPILE_FRONTEND, + KIT_PROFILE_SCOPE_COMPILE_OBJ_FINALIZE, + KIT_PROFILE_SCOPE_COMPILE_ASM_LEX_OPEN, + KIT_PROFILE_SCOPE_COMPILE_ASM_MC_NEW, + KIT_PROFILE_SCOPE_COMPILE_ASM_PARSE, + KIT_PROFILE_SCOPE_COMPILE_ASM_MC_FREE, + + KIT_PROFILE_SCOPE_CG, + KIT_PROFILE_SCOPE_NDT, + KIT_PROFILE_SCOPE_NATIVE_TARGET, + KIT_PROFILE_SCOPE_MC_EMIT, + + KIT_PROFILE_SCOPE_OPT_CFG_BUILD_1, + KIT_PROFILE_SCOPE_OPT_CFG_JUMP_CLEANUP_CFG, + KIT_PROFILE_SCOPE_OPT_CFG_BUILD_2, + KIT_PROFILE_SCOPE_OPT_CFG_SIMPLIFY_LOCAL, + KIT_PROFILE_SCOPE_OPT_CFG_VERIFY, + KIT_PROFILE_SCOPE_OPT_MACHINIZE, + KIT_PROFILE_SCOPE_OPT_MACHINIZE_VERIFY, + KIT_PROFILE_SCOPE_OPT_O1_ADDR_XFORM_PREGS, + KIT_PROFILE_SCOPE_OPT_O1_ADDR_XFORM_VERIFY, + KIT_PROFILE_SCOPE_OPT_O1_PROMOTE_SCALAR_LOCALS, + KIT_PROFILE_SCOPE_OPT_O1_PROMOTE_SCALAR_VERIFY, + KIT_PROFILE_SCOPE_OPT_O1_ADDR_OF_GLOBAL_CSE, + KIT_PROFILE_SCOPE_OPT_O1_ADDR_OF_GLOBAL_VERIFY, + KIT_PROFILE_SCOPE_OPT_BUILD_LOOP_TREE, + KIT_PROFILE_SCOPE_OPT_O1_LOWER_LOOP_IMM, + KIT_PROFILE_SCOPE_OPT_O1_HOIST_LOOP_CONSTS, + KIT_PROFILE_SCOPE_OPT_LIVE_BLOCKS_PRE_DDE, + KIT_PROFILE_SCOPE_OPT_DEAD_DEF_ELIM, + KIT_PROFILE_SCOPE_OPT_REGALLOC, + KIT_PROFILE_SCOPE_OPT_REGALLOC_VERIFY, + KIT_PROFILE_SCOPE_OPT_LIVE_RANGES_REGALLOC, + KIT_PROFILE_SCOPE_OPT_LOWER_MIR, + KIT_PROFILE_SCOPE_OPT_LOWER_MIR_VERIFY, + KIT_PROFILE_SCOPE_OPT_COMBINE, + KIT_PROFILE_SCOPE_OPT_COMBINE_VERIFY, + KIT_PROFILE_SCOPE_OPT_DCE, + KIT_PROFILE_SCOPE_OPT_DCE_VERIFY, + KIT_PROFILE_SCOPE_OPT_POST_RA_JUMP_CLEANUP_CFG, + KIT_PROFILE_SCOPE_OPT_POST_RA_BUILD_CFG, + KIT_PROFILE_SCOPE_OPT_POST_RA_VERIFY, + KIT_PROFILE_SCOPE_OPT_POST_RA_JUMP_CLEANUP_LAYOUT, + KIT_PROFILE_SCOPE_OPT_EMIT, + KIT_PROFILE_SCOPE_OPT_O1_TINY_INLINE, + KIT_PROFILE_SCOPE_OPT_O1_CG_IR_LOWER, + KIT_PROFILE_SCOPE_OPT_INLINE_TOTAL, + KIT_PROFILE_SCOPE_OPT_O1_TOTAL, + KIT_PROFILE_SCOPE_OPT_INTERP_TOTAL, + KIT_PROFILE_SCOPE_OPT_NATIVE_EMIT_SETUP, + KIT_PROFILE_SCOPE_OPT_NATIVE_EMIT_FUNC_BEGIN, + KIT_PROFILE_SCOPE_OPT_NATIVE_EMIT_BODY, + KIT_PROFILE_SCOPE_OPT_NATIVE_EMIT_FUNC_END, + + KIT_PROFILE_SCOPE_LINK_RESOLVE_TOTAL, + KIT_PROFILE_SCOPE_LINK_INGEST_ARCHIVES, + KIT_PROFILE_SCOPE_LINK_RESOLVE_SYMBOLS, + KIT_PROFILE_SCOPE_LINK_GC, + KIT_PROFILE_SCOPE_LINK_LAYOUT_SECTIONS, + KIT_PROFILE_SCOPE_LINK_EMIT_SEGMENT_BYTES, + KIT_PROFILE_SCOPE_LINK_LAYOUT_DEBUG, + KIT_PROFILE_SCOPE_LINK_ASSIGN_VADDRS, + KIT_PROFILE_SCOPE_LINK_EMIT_BOUNDARIES, + KIT_PROFILE_SCOPE_LINK_RESOLVE_UNDEFS, + KIT_PROFILE_SCOPE_LINK_GC_DROP_DEAD, + KIT_PROFILE_SCOPE_LINK_LAYOUT_IPLT, + KIT_PROFILE_SCOPE_LINK_LAYOUT_JIT_STUBS, + KIT_PROFILE_SCOPE_LINK_LAYOUT_GOT, + KIT_PROFILE_SCOPE_LINK_EMIT_RELOCATIONS, + KIT_PROFILE_SCOPE_LINK_LAYOUT_DYN, + KIT_PROFILE_SCOPE_LINK_RESOLVE_ENTRY, + KIT_PROFILE_SCOPE_LINK_CAPTURE_DEBUG, + + KIT_PROFILE_SCOPE_JIT_RESERVE, + KIT_PROFILE_SCOPE_JIT_COPY_SEGMENTS, + KIT_PROFILE_SCOPE_JIT_APPLY_RELOCS, + KIT_PROFILE_SCOPE_JIT_PROTECT, + KIT_PROFILE_SCOPE_JIT_FLUSH_ICACHE, + KIT_PROFILE_SCOPE_JIT_CTORS, + + KIT_PROFILE_SCOPE_DRIVER_LOAD_SOURCES, + KIT_PROFILE_SCOPE_DRIVER_LOAD_OBJECTS, + KIT_PROFILE_SCOPE_DRIVER_LOAD_ARCHIVES, + KIT_PROFILE_SCOPE_DRIVER_LINK_SETUP, + + /* Kit-owned scope ids are [1, KIT_PROFILE_SCOPE_KIT_LAST]. */ + KIT_PROFILE_SCOPE_KIT_LAST = 0x3fff, + + /* Language frontends own this range. Define frontend-local enums relative + * to KIT_PROFILE_SCOPE_LANG_FIRST; kit will not allocate ids here. */ + KIT_PROFILE_SCOPE_LANG_FIRST = 0x4000, + KIT_PROFILE_SCOPE_LANG_LAST = 0x7fff, + + /* Embedders/tools own this range. */ + KIT_PROFILE_SCOPE_EXTERNAL_FIRST = 0x8000, + KIT_PROFILE_SCOPE_EXTERNAL_LAST = 0xffff, +} KitProfileScope; + +typedef enum KitProfileCounter { + KIT_PROFILE_COUNTER_NONE = 0, + + KIT_PROFILE_COUNTER_KIT_FIRST = 1, + KIT_PROFILE_COUNTER_COMPILE_INPUT_BYTES = KIT_PROFILE_COUNTER_KIT_FIRST, + KIT_PROFILE_COUNTER_COMPILE_OBJ_SECTIONS, + KIT_PROFILE_COUNTER_COMPILE_OBJ_RELOCS, + + KIT_PROFILE_COUNTER_CG_SWITCH_TABLE, + KIT_PROFILE_COUNTER_CG_SWITCH_CHAIN, + + KIT_PROFILE_COUNTER_OPT_FUNCS, + KIT_PROFILE_COUNTER_OPT_BLOCKS, + KIT_PROFILE_COUNTER_OPT_PREGS, + KIT_PROFILE_COUNTER_OPT_LIVE_WORDS, + KIT_PROFILE_COUNTER_OPT_RANGES, + KIT_PROFILE_COUNTER_OPT_RANGE_POINTS, + KIT_PROFILE_COUNTER_OPT_RANGE_RAW_POINTS, + KIT_PROFILE_COUNTER_OPT_RANGE_MAX_PER_PREG, + KIT_PROFILE_COUNTER_OPT_RANGE_MAX_LENGTH, + KIT_PROFILE_COUNTER_OPT_RANGE_WHOLE_BLOCK_SPANS, + KIT_PROFILE_COUNTER_OPT_LIVE_BITSET_WORDS_TOUCHED, + KIT_PROFILE_COUNTER_OPT_LIVE_DATAFLOW_ITERATIONS, + KIT_PROFILE_COUNTER_OPT_LIVE_DATAFLOW_BLOCK_VISITS, + KIT_PROFILE_COUNTER_OPT_RANGE_POINT_VISITS, + KIT_PROFILE_COUNTER_OPT_RANGE_PREG_SCANS, + KIT_PROFILE_COUNTER_OPT_RANGE_LIVE_WORDS_TOUCHED, + KIT_PROFILE_COUNTER_OPT_CONFLICT_BYTES, + KIT_PROFILE_COUNTER_OPT_COALESCE_MOVES_SEEN, + KIT_PROFILE_COUNTER_OPT_COALESCE_CANDIDATES, + KIT_PROFILE_COUNTER_OPT_COALESCE_CONFLICTS, + KIT_PROFILE_COUNTER_OPT_COALESCE_MERGE_ATTEMPTS, + KIT_PROFILE_COUNTER_OPT_COALESCE_MERGES, + KIT_PROFILE_COUNTER_OPT_INLINE_CANDIDATES, + KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_POLICY, + KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_SCC, + KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_SHAPE, + KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_GROWTH, + KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_REWRITE_SHAPE, + KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_REWRITE, + KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_SHAPE_VARIADIC, + KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_SHAPE_ENTRY, + KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_SHAPE_OP, + KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_SHAPE_RET_POS, + KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_SHAPE_RET_COUNT, + KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_SHAPE_BUDGET, + KIT_PROFILE_COUNTER_OPT_INLINE_INLINED, + KIT_PROFILE_COUNTER_OPT_TINY_INLINE_CANDIDATES, + KIT_PROFILE_COUNTER_OPT_TINY_INLINE_REFUSE_POLICY, + KIT_PROFILE_COUNTER_OPT_TINY_INLINE_REFUSE_SCC, + KIT_PROFILE_COUNTER_OPT_TINY_INLINE_REFUSE_SHAPE, + KIT_PROFILE_COUNTER_OPT_TINY_INLINE_REFUSE_BUDGET, + KIT_PROFILE_COUNTER_OPT_TINY_INLINE_REFUSE_REWRITE_SHAPE, + KIT_PROFILE_COUNTER_OPT_TINY_INLINE_REFUSE_REWRITE, + KIT_PROFILE_COUNTER_OPT_TINY_INLINE_INLINED, + + KIT_PROFILE_COUNTER_LINK_INPUTS, + KIT_PROFILE_COUNTER_LINK_SECTIONS, + KIT_PROFILE_COUNTER_LINK_SEGMENTS, + KIT_PROFILE_COUNTER_LINK_SYMS, + KIT_PROFILE_COUNTER_LINK_RELOCS, + + KIT_PROFILE_COUNTER_JIT_INPUT_SECTION_BYTES, + KIT_PROFILE_COUNTER_JIT_MASTER_SIZE, + KIT_PROFILE_COUNTER_JIT_NSEGMENTS, + KIT_PROFILE_COUNTER_JIT_SEGMENT_BYTES, + + /* Kit-owned counter ids are [1, KIT_PROFILE_COUNTER_KIT_LAST]. */ + KIT_PROFILE_COUNTER_KIT_LAST = 0x3fff, + + KIT_PROFILE_COUNTER_LANG_FIRST = 0x4000, + KIT_PROFILE_COUNTER_LANG_LAST = 0x7fff, + + KIT_PROFILE_COUNTER_EXTERNAL_FIRST = 0x8000, + KIT_PROFILE_COUNTER_EXTERNAL_LAST = 0xffff, +} KitProfileCounter; + +#define KIT_PROFILE_ID_COUNT 0x10000u +#define KIT_PROFILE_STACK_MAX 256u +#define KIT_PROFILE_DEF_MAX 256u + +typedef enum KitProfileDefKind { + KIT_PROFILE_DEF_SCOPE = 1, + KIT_PROFILE_DEF_COUNTER = 2, +} KitProfileDefKind; + +typedef struct KitProfileFrame { + uint32_t id; + uint64_t start_tick; +} KitProfileFrame; + +typedef struct KitProfileDef { + uint32_t id; + uint16_t kind; + uint16_t reserved; + const char* name; +} KitProfileDef; + +typedef struct KitProfiler KitProfiler; + +KIT_API const char* kit_profile_scope_name(KitProfileScope scope); +KIT_API const char* kit_profile_counter_name(KitProfileCounter counter); +KIT_API void kit_profiler_reset(KitProfiler* p); + +struct KitProfiler { + uint64_t scope_ticks[KIT_PROFILE_ID_COUNT]; + uint64_t scope_count[KIT_PROFILE_ID_COUNT]; + uint64_t counters[KIT_PROFILE_ID_COUNT]; + KitProfileFrame stack[KIT_PROFILE_STACK_MAX]; + KitProfileDef defs[KIT_PROFILE_DEF_MAX]; + uint32_t depth; + uint32_t ndefs; + uint32_t stack_overflow; + uint32_t def_overflow; +}; + +static inline uint64_t kit_profile_ticks(void) { +#if defined(__clang__) && (defined(__x86_64__) || defined(__i386__) || \ + defined(__aarch64__) || defined(__arm__) || \ + defined(__riscv)) + return __builtin_readcyclecounter(); +#elif (defined(__GNUC__) || defined(__clang__)) && defined(__x86_64__) + uint32_t lo; + uint32_t hi; + __asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi)); + return ((uint64_t)hi << 32) | lo; +#elif (defined(__GNUC__) || defined(__clang__)) && defined(__i386__) + uint64_t v; + __asm__ __volatile__("rdtsc" : "=A"(v)); + return v; +#elif (defined(__GNUC__) || defined(__clang__)) && defined(__aarch64__) + uint64_t v; + __asm__ __volatile__("mrs %0, cntvct_el0" : "=r"(v)); + return v; +#elif (defined(__GNUC__) || defined(__clang__)) && defined(__riscv) + uint64_t v; + __asm__ __volatile__("rdcycle %0" : "=r"(v)); + return v; +#else + return 0; +#endif +} + +static inline void kit_profiler_scope_begin(KitProfiler* p, + KitProfileScope scope) { + if (!p || scope == KIT_PROFILE_SCOPE_NONE) return; + if (p->depth >= KIT_PROFILE_STACK_MAX) { + p->stack_overflow++; + return; + } + p->stack[p->depth].id = (uint32_t)scope; + p->stack[p->depth].start_tick = kit_profile_ticks(); + p->depth++; +} + +static inline void kit_profiler_scope_end(KitProfiler* p, + KitProfileScope scope) { + KitProfileFrame f; + uint64_t end_tick; + uint32_t id; + if (!p || p->depth == 0) return; + p->depth--; + f = p->stack[p->depth]; + id = f.id ? f.id : (uint32_t)scope; + if (id >= KIT_PROFILE_ID_COUNT) return; + end_tick = kit_profile_ticks(); + if (end_tick >= f.start_tick) p->scope_ticks[id] += end_tick - f.start_tick; + p->scope_count[id]++; +} + +static inline void kit_profiler_count(KitProfiler* p, + KitProfileCounter counter, + uint64_t value) { + uint32_t id = (uint32_t)counter; + if (!p || counter == KIT_PROFILE_COUNTER_NONE || id >= KIT_PROFILE_ID_COUNT) + return; + p->counters[id] += value; +} + +static inline void kit_profiler_define_name(KitProfiler* p, uint16_t kind, + uint32_t id, const char* name) { + uint32_t i; + if (!p || !id || id >= KIT_PROFILE_ID_COUNT || !name) return; + for (i = 0; i < p->ndefs; ++i) { + if (p->defs[i].id == id && p->defs[i].kind == kind) { + p->defs[i].name = name; + return; + } + } + if (p->ndefs >= KIT_PROFILE_DEF_MAX) { + p->def_overflow++; + return; + } + p->defs[p->ndefs].id = id; + p->defs[p->ndefs].kind = kind; + p->defs[p->ndefs].reserved = 0; + p->defs[p->ndefs].name = name; + p->ndefs++; +} + +static inline void kit_profiler_define_scope(KitProfiler* p, + KitProfileScope scope, + const char* name) { + kit_profiler_define_name(p, KIT_PROFILE_DEF_SCOPE, (uint32_t)scope, name); +} + +static inline void kit_profiler_define_counter(KitProfiler* p, + KitProfileCounter counter, + const char* name) { + kit_profiler_define_name(p, KIT_PROFILE_DEF_COUNTER, (uint32_t)counter, name); +} + +static inline const char* kit_profiler_defined_name(const KitProfiler* p, + uint16_t kind, + uint32_t id) { + uint32_t i; + if (!p || !id || id >= KIT_PROFILE_ID_COUNT) return 0; + for (i = 0; i < p->ndefs; ++i) + if (p->defs[i].id == id && p->defs[i].kind == kind) return p->defs[i].name; + return 0; +} + +static inline const char* kit_profiler_scope_name(const KitProfiler* p, + KitProfileScope scope) { + const char* name = kit_profile_scope_name(scope); + return name ? name + : kit_profiler_defined_name(p, KIT_PROFILE_DEF_SCOPE, + (uint32_t)scope); +} + +static inline const char* kit_profiler_counter_name(const KitProfiler* p, + KitProfileCounter counter) { + const char* name = kit_profile_counter_name(counter); + return name ? name + : kit_profiler_defined_name(p, KIT_PROFILE_DEF_COUNTER, + (uint32_t)counter); +} + +static inline uint64_t kit_profiler_scope_ticks(const KitProfiler* p, + KitProfileScope scope) { + uint32_t id = (uint32_t)scope; + return (p && id < KIT_PROFILE_ID_COUNT) ? p->scope_ticks[id] : 0; +} + +static inline uint64_t kit_profiler_scope_count(const KitProfiler* p, + KitProfileScope scope) { + uint32_t id = (uint32_t)scope; + return (p && id < KIT_PROFILE_ID_COUNT) ? p->scope_count[id] : 0; +} + +static inline uint64_t kit_profiler_counter_value(const KitProfiler* p, + KitProfileCounter counter) { + uint32_t id = (uint32_t)counter; + return (p && id < KIT_PROFILE_ID_COUNT) ? p->counters[id] : 0; +} + +#endif diff --git a/lang/c/c.c b/lang/c/c.c @@ -5,6 +5,63 @@ #include "parse/parse.h" #include "pp/pp.h" +#define C_PROFILE_SCOPE_SETUP \ + ((KitProfileScope)(KIT_PROFILE_SCOPE_LANG_FIRST + 0u)) +#define C_PROFILE_SCOPE_POOL_NEW \ + ((KitProfileScope)(KIT_PROFILE_SCOPE_LANG_FIRST + 1u)) +#define C_PROFILE_SCOPE_LEX_OPEN \ + ((KitProfileScope)(KIT_PROFILE_SCOPE_LANG_FIRST + 2u)) +#define C_PROFILE_SCOPE_PP_NEW \ + ((KitProfileScope)(KIT_PROFILE_SCOPE_LANG_FIRST + 3u)) +#define C_PROFILE_SCOPE_DECL_NEW \ + ((KitProfileScope)(KIT_PROFILE_SCOPE_LANG_FIRST + 4u)) +#define C_PROFILE_SCOPE_PP_OPTIONS \ + ((KitProfileScope)(KIT_PROFILE_SCOPE_LANG_FIRST + 5u)) +#define C_PROFILE_SCOPE_PP_PUSH_INPUT \ + ((KitProfileScope)(KIT_PROFILE_SCOPE_LANG_FIRST + 6u)) +#define C_PROFILE_SCOPE_PARSE_CODEGEN \ + ((KitProfileScope)(KIT_PROFILE_SCOPE_LANG_FIRST + 7u)) +#define C_PROFILE_SCOPE_CLEANUP \ + ((KitProfileScope)(KIT_PROFILE_SCOPE_LANG_FIRST + 8u)) + +#define C_PROFILE_COUNTER_PP_INCLUDE_DIRS \ + ((KitProfileCounter)(KIT_PROFILE_COUNTER_LANG_FIRST + 0u)) +#define C_PROFILE_COUNTER_PP_SYSTEM_INCLUDE_DIRS \ + ((KitProfileCounter)(KIT_PROFILE_COUNTER_LANG_FIRST + 1u)) +#define C_PROFILE_COUNTER_PP_DEFINES \ + ((KitProfileCounter)(KIT_PROFILE_COUNTER_LANG_FIRST + 2u)) +#define C_PROFILE_COUNTER_PP_UNDEFINES \ + ((KitProfileCounter)(KIT_PROFILE_COUNTER_LANG_FIRST + 3u)) + +static void c_profile_define(KitCompiler* c) { + kit_frontend_profile_define_scope(c, C_PROFILE_SCOPE_SETUP, + "compile.c.setup"); + kit_frontend_profile_define_scope(c, C_PROFILE_SCOPE_POOL_NEW, + "compile.c.pool_new"); + kit_frontend_profile_define_scope(c, C_PROFILE_SCOPE_LEX_OPEN, + "compile.c.lex_open"); + kit_frontend_profile_define_scope(c, C_PROFILE_SCOPE_PP_NEW, + "compile.c.pp_new"); + kit_frontend_profile_define_scope(c, C_PROFILE_SCOPE_DECL_NEW, + "compile.c.decl_new"); + kit_frontend_profile_define_scope(c, C_PROFILE_SCOPE_PP_OPTIONS, + "compile.c.pp_options"); + kit_frontend_profile_define_scope(c, C_PROFILE_SCOPE_PP_PUSH_INPUT, + "compile.c.pp_push_input"); + kit_frontend_profile_define_scope(c, C_PROFILE_SCOPE_PARSE_CODEGEN, + "compile.c.parse_codegen"); + kit_frontend_profile_define_scope(c, C_PROFILE_SCOPE_CLEANUP, + "compile.c.cleanup"); + kit_frontend_profile_define_counter(c, C_PROFILE_COUNTER_PP_INCLUDE_DIRS, + "compile.c.pp_include_dirs"); + kit_frontend_profile_define_counter(c, C_PROFILE_COUNTER_PP_SYSTEM_INCLUDE_DIRS, + "compile.c.pp_system_include_dirs"); + kit_frontend_profile_define_counter(c, C_PROFILE_COUNTER_PP_DEFINES, + "compile.c.pp_defines"); + kit_frontend_profile_define_counter(c, C_PROFILE_COUNTER_PP_UNDEFINES, + "compile.c.pp_undefines"); +} + static SrcLoc c_no_loc(void) { SrcLoc loc; loc.file_id = 0; @@ -69,57 +126,58 @@ static KitStatus c_frontend_compile_cg(KitFrontendState* frontend, c = fe->c; if (!fe_opts || !input || !cg) c_bad_options(c, "compile args missing"); bytes = &input->bytes; + c_profile_define(c); - kit_frontend_metrics_scope_begin(c, "compile.c.setup"); - kit_frontend_metrics_scope_begin(c, "compile.c.pool_new"); + kit_frontend_profile_scope_begin(c, C_PROFILE_SCOPE_SETUP); + kit_frontend_profile_scope_begin(c, C_PROFILE_SCOPE_POOL_NEW); pool = c_pool_new(c); - kit_frontend_metrics_scope_end(c, "compile.c.pool_new"); + kit_frontend_profile_scope_end(c, C_PROFILE_SCOPE_POOL_NEW); if (!pool) compiler_panic(c, c_no_loc(), "C compiler out of memory"); - kit_frontend_metrics_scope_begin(c, "compile.c.lex_open"); + kit_frontend_profile_scope_begin(c, C_PROFILE_SCOPE_LEX_OPEN); lex = lex_open_mem(c, input->name.s, bytes->s, bytes->len); if (lex) lex_skip_shebang(lex); - kit_frontend_metrics_scope_end(c, "compile.c.lex_open"); - kit_frontend_metrics_scope_begin(c, "compile.c.pp_new"); + kit_frontend_profile_scope_end(c, C_PROFILE_SCOPE_LEX_OPEN); + kit_frontend_profile_scope_begin(c, C_PROFILE_SCOPE_PP_NEW); pp = pp_new(c); - kit_frontend_metrics_scope_end(c, "compile.c.pp_new"); + kit_frontend_profile_scope_end(c, C_PROFILE_SCOPE_PP_NEW); if (!lex || !pp || !cg) compiler_panic(c, c_no_loc(), "C compiler out of memory"); - kit_frontend_metrics_scope_begin(c, "compile.c.decl_new"); + kit_frontend_profile_scope_begin(c, C_PROFILE_SCOPE_DECL_NEW); decls = decl_new(c, pool, cg); - kit_frontend_metrics_scope_end(c, "compile.c.decl_new"); - kit_frontend_metrics_scope_end(c, "compile.c.setup"); + kit_frontend_profile_scope_end(c, C_PROFILE_SCOPE_DECL_NEW); + kit_frontend_profile_scope_end(c, C_PROFILE_SCOPE_SETUP); - kit_frontend_metrics_scope_begin(c, "compile.c.pp_options"); - kit_frontend_metrics_count(c, "compile.c.pp_include_dirs", + kit_frontend_profile_scope_begin(c, C_PROFILE_SCOPE_PP_OPTIONS); + kit_frontend_profile_count(c, C_PROFILE_COUNTER_PP_INCLUDE_DIRS, fe_opts->preprocess.ninclude_dirs); - kit_frontend_metrics_count(c, "compile.c.pp_system_include_dirs", + kit_frontend_profile_count(c, C_PROFILE_COUNTER_PP_SYSTEM_INCLUDE_DIRS, fe_opts->preprocess.nsystem_include_dirs); - kit_frontend_metrics_count(c, "compile.c.pp_defines", + kit_frontend_profile_count(c, C_PROFILE_COUNTER_PP_DEFINES, fe_opts->preprocess.ndefines); - kit_frontend_metrics_count(c, "compile.c.pp_undefines", + kit_frontend_profile_count(c, C_PROFILE_COUNTER_PP_UNDEFINES, fe_opts->preprocess.nundefines); c_apply_pp_options(pp, &fe_opts->preprocess); - kit_frontend_metrics_scope_end(c, "compile.c.pp_options"); + kit_frontend_profile_scope_end(c, C_PROFILE_SCOPE_PP_OPTIONS); /* The C parser drops preprocessor newlines, so suppress non-directive * newline tokens at the lexer (primary source + #includes) — ~51% of lexer * outputs. Directive-terminating newlines are still emitted, so the PP's * directive handling is unaffected. Must be set before pp_push_input so the * primary lexer inherits the mode. */ pp_set_suppress_lexer_newlines(pp, 1); - kit_frontend_metrics_scope_begin(c, "compile.c.pp_push_input"); + kit_frontend_profile_scope_begin(c, C_PROFILE_SCOPE_PP_PUSH_INPUT); pp_push_input(pp, lex); - kit_frontend_metrics_scope_end(c, "compile.c.pp_push_input"); + kit_frontend_profile_scope_end(c, C_PROFILE_SCOPE_PP_PUSH_INPUT); - kit_frontend_metrics_scope_begin(c, "compile.c.parse_codegen"); + kit_frontend_profile_scope_begin(c, C_PROFILE_SCOPE_PARSE_CODEGEN); parse_c(c, pool, pp, decls, cg, (KitSymVis)fe_opts->code.default_visibility, (int)fe_opts->code.trivial_auto_var_init); - kit_frontend_metrics_scope_end(c, "compile.c.parse_codegen"); + kit_frontend_profile_scope_end(c, C_PROFILE_SCOPE_PARSE_CODEGEN); - kit_frontend_metrics_scope_begin(c, "compile.c.cleanup"); + kit_frontend_profile_scope_begin(c, C_PROFILE_SCOPE_CLEANUP); decl_free(decls); pp_free(pp); c_pool_free(pool); - kit_frontend_metrics_scope_end(c, "compile.c.cleanup"); + kit_frontend_profile_scope_end(c, C_PROFILE_SCOPE_CLEANUP); return KIT_OK; } diff --git a/mk/test_unit.mk b/mk/test_unit.mk @@ -32,13 +32,14 @@ UNIT_CFLAGS_INTERNAL = $(HOST_CFLAGS) -Iinclude -Isrc -Itest UNIT_TESTS_PUBLIC := \ ar_test target_test cg_api_test cg_switch_test cg_fp_cmp_test \ cg_control_test hash_test \ - panic_recovery_test \ + panic_recovery_test profile_test \ rv64_jit_test rv32_jit_test aa64_inline_test rv64_inline_test x64_inline_test \ strength_reduce_test ar_test_SRC := test/ar/ar_test.c target_test_SRC := test/api/target_test.c hash_test_SRC := test/api/hash_test.c panic_recovery_test_SRC := test/api/panic_recovery_test.c +profile_test_SRC := test/api/profile_test.c cg_api_test_SRC := test/api/cg_type_test.c cg_switch_test_SRC := test/api/cg_switch_test.c cg_fp_cmp_test_SRC := test/api/cg_fp_cmp_test.c @@ -55,6 +56,7 @@ UNIT_TESTS_INTERNAL := \ aa64_isa_test rv64_decode_test rv32_decode_test aa64_sweep_gen \ reloc_uleb128_unit reloc_desc_test reloc_apply_test emu_rv64_unit_test \ interp_smoke_test jit_tls_relax_test coff_weak_alias_test \ + elf_version_import_test \ rv64_interp_smoke_test abi_classify_test ir_recorder_test \ native_direct_target_test x64_dbg_test cg_ir_lower_test tiny_inline_test dwarf_test_SRC := test/dwarf/dwarf_test.c @@ -69,6 +71,7 @@ reloc_desc_test_SRC := test/link/reloc_desc_test.c reloc_apply_test_SRC := test/link/reloc_apply_test.c jit_tls_relax_test_SRC := test/link/jit_tls_relax_test.c coff_weak_alias_test_SRC := test/link/coff_weak_alias_test.c +elf_version_import_test_SRC := test/link/elf_version_import_test.c emu_rv64_unit_test_SRC := test/emu/rv64_vm_unit_test.c interp_smoke_test_SRC := test/interp/interp_smoke_test.c rv64_interp_smoke_test_SRC := test/emu/rv64_interp_smoke_test.c diff --git a/src/api/frontend.c b/src/api/frontend.c @@ -3,7 +3,7 @@ #include <stdarg.h> #include "core/core.h" -#include "core/metrics.h" +#include "core/profile.h" KitStatus kit_frontend_run(KitCompiler* c, KitFrontendRunFn fn, void* user) { PanicFrame panic; @@ -20,17 +20,28 @@ KitStatus kit_frontend_run(KitCompiler* c, KitFrontendRunFn fn, void* user) { return rc; } -void kit_frontend_metrics_scope_begin(KitCompiler* c, const char* name) { - metrics_scope_begin((Compiler*)c, name); +void kit_frontend_profile_scope_begin(KitCompiler* c, KitProfileScope scope) { + profile_scope_begin((Compiler*)c, scope); } -void kit_frontend_metrics_scope_end(KitCompiler* c, const char* name) { - metrics_scope_end((Compiler*)c, name); +void kit_frontend_profile_scope_end(KitCompiler* c, KitProfileScope scope) { + profile_scope_end((Compiler*)c, scope); } -void kit_frontend_metrics_count(KitCompiler* c, const char* name, +void kit_frontend_profile_count(KitCompiler* c, KitProfileCounter counter, uint64_t value) { - metrics_count((Compiler*)c, name, (u64)value); + profile_count((Compiler*)c, counter, (u64)value); +} + +void kit_frontend_profile_define_scope(KitCompiler* c, KitProfileScope scope, + const char* name) { + profile_define_scope((Compiler*)c, scope, name); +} + +void kit_frontend_profile_define_counter(KitCompiler* c, + KitProfileCounter counter, + const char* name) { + profile_define_counter((Compiler*)c, counter, name); } void kit_frontend_fatal(KitCompiler* c, KitSrcLoc loc, const char* fmt, ...) { diff --git a/src/core/metrics.h b/src/core/metrics.h @@ -1,25 +1,237 @@ #ifndef KIT_METRICS_H #define KIT_METRICS_H -#include "core/core.h" +#include "core/profile.h" -static inline const KitMetrics* metrics_sink(Compiler* c) { - return (c && c->ctx) ? c->ctx->metrics : NULL; +static inline int metrics_streq(const char* a, const char* b) { + while (*a && *b && *a == *b) { + ++a; + ++b; + } + return *a == *b; +} + +static inline KitProfileScope metrics_scope_from_name(const char* name) { + if (!name) return KIT_PROFILE_SCOPE_NONE; +#define METRICS_SCOPE(s, id) \ + if (metrics_streq(name, s)) return id + METRICS_SCOPE("compile.tu", KIT_PROFILE_SCOPE_COMPILE_TU); + METRICS_SCOPE("compile.frontend", KIT_PROFILE_SCOPE_COMPILE_FRONTEND); + METRICS_SCOPE("compile.obj_finalize", KIT_PROFILE_SCOPE_COMPILE_OBJ_FINALIZE); + METRICS_SCOPE("compile.asm.lex_open", KIT_PROFILE_SCOPE_COMPILE_ASM_LEX_OPEN); + METRICS_SCOPE("compile.asm.mc_new", KIT_PROFILE_SCOPE_COMPILE_ASM_MC_NEW); + METRICS_SCOPE("compile.asm.parse", KIT_PROFILE_SCOPE_COMPILE_ASM_PARSE); + METRICS_SCOPE("compile.asm.mc_free", KIT_PROFILE_SCOPE_COMPILE_ASM_MC_FREE); + METRICS_SCOPE("opt.cfg.build_1", KIT_PROFILE_SCOPE_OPT_CFG_BUILD_1); + METRICS_SCOPE("opt.cfg.jump_cleanup_cfg", + KIT_PROFILE_SCOPE_OPT_CFG_JUMP_CLEANUP_CFG); + METRICS_SCOPE("opt.cfg.build_2", KIT_PROFILE_SCOPE_OPT_CFG_BUILD_2); + METRICS_SCOPE("opt.cfg.simplify_local", + KIT_PROFILE_SCOPE_OPT_CFG_SIMPLIFY_LOCAL); + METRICS_SCOPE("opt.cfg.verify", KIT_PROFILE_SCOPE_OPT_CFG_VERIFY); + METRICS_SCOPE("opt.machinize", KIT_PROFILE_SCOPE_OPT_MACHINIZE); + METRICS_SCOPE("opt.machinize.verify", + KIT_PROFILE_SCOPE_OPT_MACHINIZE_VERIFY); + METRICS_SCOPE("opt.o1.addr_xform_pregs", + KIT_PROFILE_SCOPE_OPT_O1_ADDR_XFORM_PREGS); + METRICS_SCOPE("opt.o1.addr_xform.verify", + KIT_PROFILE_SCOPE_OPT_O1_ADDR_XFORM_VERIFY); + METRICS_SCOPE("opt.o1.promote_scalar_locals", + KIT_PROFILE_SCOPE_OPT_O1_PROMOTE_SCALAR_LOCALS); + METRICS_SCOPE("opt.o1.promote_scalar.verify", + KIT_PROFILE_SCOPE_OPT_O1_PROMOTE_SCALAR_VERIFY); + METRICS_SCOPE("opt.o1.addr_of_global_cse", + KIT_PROFILE_SCOPE_OPT_O1_ADDR_OF_GLOBAL_CSE); + METRICS_SCOPE("opt.o1.addr_of_global.verify", + KIT_PROFILE_SCOPE_OPT_O1_ADDR_OF_GLOBAL_VERIFY); + METRICS_SCOPE("opt.build_loop_tree", KIT_PROFILE_SCOPE_OPT_BUILD_LOOP_TREE); + METRICS_SCOPE("opt.o1.lower_loop_imm", + KIT_PROFILE_SCOPE_OPT_O1_LOWER_LOOP_IMM); + METRICS_SCOPE("opt.o1.hoist_loop_consts", + KIT_PROFILE_SCOPE_OPT_O1_HOIST_LOOP_CONSTS); + METRICS_SCOPE("opt.live_blocks.pre_dde", + KIT_PROFILE_SCOPE_OPT_LIVE_BLOCKS_PRE_DDE); + METRICS_SCOPE("opt.dead_def_elim", KIT_PROFILE_SCOPE_OPT_DEAD_DEF_ELIM); + METRICS_SCOPE("opt.regalloc", KIT_PROFILE_SCOPE_OPT_REGALLOC); + METRICS_SCOPE("opt.regalloc.verify", KIT_PROFILE_SCOPE_OPT_REGALLOC_VERIFY); + METRICS_SCOPE("opt.live_ranges.regalloc", + KIT_PROFILE_SCOPE_OPT_LIVE_RANGES_REGALLOC); + METRICS_SCOPE("opt.lower_mir", KIT_PROFILE_SCOPE_OPT_LOWER_MIR); + METRICS_SCOPE("opt.lower_mir.verify", + KIT_PROFILE_SCOPE_OPT_LOWER_MIR_VERIFY); + METRICS_SCOPE("opt.combine", KIT_PROFILE_SCOPE_OPT_COMBINE); + METRICS_SCOPE("opt.combine.verify", KIT_PROFILE_SCOPE_OPT_COMBINE_VERIFY); + METRICS_SCOPE("opt.dce", KIT_PROFILE_SCOPE_OPT_DCE); + METRICS_SCOPE("opt.dce.verify", KIT_PROFILE_SCOPE_OPT_DCE_VERIFY); + METRICS_SCOPE("opt.post_ra.jump_cleanup_cfg", + KIT_PROFILE_SCOPE_OPT_POST_RA_JUMP_CLEANUP_CFG); + METRICS_SCOPE("opt.post_ra.build_cfg", + KIT_PROFILE_SCOPE_OPT_POST_RA_BUILD_CFG); + METRICS_SCOPE("opt.post_ra.verify", KIT_PROFILE_SCOPE_OPT_POST_RA_VERIFY); + METRICS_SCOPE("opt.post_ra.jump_cleanup_layout", + KIT_PROFILE_SCOPE_OPT_POST_RA_JUMP_CLEANUP_LAYOUT); + METRICS_SCOPE("opt.emit", KIT_PROFILE_SCOPE_OPT_EMIT); + METRICS_SCOPE("opt.o1.tiny_inline", KIT_PROFILE_SCOPE_OPT_O1_TINY_INLINE); + METRICS_SCOPE("opt.o1.cg_ir_lower", KIT_PROFILE_SCOPE_OPT_O1_CG_IR_LOWER); + METRICS_SCOPE("opt.inline.total", KIT_PROFILE_SCOPE_OPT_INLINE_TOTAL); + METRICS_SCOPE("opt.o1.total", KIT_PROFILE_SCOPE_OPT_O1_TOTAL); + METRICS_SCOPE("opt.interp.total", KIT_PROFILE_SCOPE_OPT_INTERP_TOTAL); + METRICS_SCOPE("opt.native_emit.setup", + KIT_PROFILE_SCOPE_OPT_NATIVE_EMIT_SETUP); + METRICS_SCOPE("opt.native_emit.func_begin", + KIT_PROFILE_SCOPE_OPT_NATIVE_EMIT_FUNC_BEGIN); + METRICS_SCOPE("opt.native_emit.body", KIT_PROFILE_SCOPE_OPT_NATIVE_EMIT_BODY); + METRICS_SCOPE("opt.native_emit.func_end", + KIT_PROFILE_SCOPE_OPT_NATIVE_EMIT_FUNC_END); + METRICS_SCOPE("link.resolve.total", KIT_PROFILE_SCOPE_LINK_RESOLVE_TOTAL); + METRICS_SCOPE("link.ingest_archives", KIT_PROFILE_SCOPE_LINK_INGEST_ARCHIVES); + METRICS_SCOPE("link.resolve_symbols", KIT_PROFILE_SCOPE_LINK_RESOLVE_SYMBOLS); + METRICS_SCOPE("link.gc", KIT_PROFILE_SCOPE_LINK_GC); + METRICS_SCOPE("link.layout_sections", KIT_PROFILE_SCOPE_LINK_LAYOUT_SECTIONS); + METRICS_SCOPE("link.emit_segment_bytes", + KIT_PROFILE_SCOPE_LINK_EMIT_SEGMENT_BYTES); + METRICS_SCOPE("link.layout_debug", KIT_PROFILE_SCOPE_LINK_LAYOUT_DEBUG); + METRICS_SCOPE("link.assign_vaddrs", KIT_PROFILE_SCOPE_LINK_ASSIGN_VADDRS); + METRICS_SCOPE("link.emit_boundaries", KIT_PROFILE_SCOPE_LINK_EMIT_BOUNDARIES); + METRICS_SCOPE("link.resolve_undefs", KIT_PROFILE_SCOPE_LINK_RESOLVE_UNDEFS); + METRICS_SCOPE("link.gc_drop_dead", KIT_PROFILE_SCOPE_LINK_GC_DROP_DEAD); + METRICS_SCOPE("link.layout_iplt", KIT_PROFILE_SCOPE_LINK_LAYOUT_IPLT); + METRICS_SCOPE("link.layout_jit_stubs", + KIT_PROFILE_SCOPE_LINK_LAYOUT_JIT_STUBS); + METRICS_SCOPE("link.layout_got", KIT_PROFILE_SCOPE_LINK_LAYOUT_GOT); + METRICS_SCOPE("link.emit_relocations", + KIT_PROFILE_SCOPE_LINK_EMIT_RELOCATIONS); + METRICS_SCOPE("link.layout_dyn", KIT_PROFILE_SCOPE_LINK_LAYOUT_DYN); + METRICS_SCOPE("link.resolve_entry", KIT_PROFILE_SCOPE_LINK_RESOLVE_ENTRY); + METRICS_SCOPE("link.capture_debug", KIT_PROFILE_SCOPE_LINK_CAPTURE_DEBUG); + METRICS_SCOPE("jit.reserve", KIT_PROFILE_SCOPE_JIT_RESERVE); + METRICS_SCOPE("jit.copy_segments", KIT_PROFILE_SCOPE_JIT_COPY_SEGMENTS); + METRICS_SCOPE("jit.apply_relocs", KIT_PROFILE_SCOPE_JIT_APPLY_RELOCS); + METRICS_SCOPE("jit.protect", KIT_PROFILE_SCOPE_JIT_PROTECT); + METRICS_SCOPE("jit.flush_icache", KIT_PROFILE_SCOPE_JIT_FLUSH_ICACHE); + METRICS_SCOPE("jit.ctors", KIT_PROFILE_SCOPE_JIT_CTORS); +#undef METRICS_SCOPE + return KIT_PROFILE_SCOPE_NONE; +} + +static inline KitProfileCounter metrics_counter_from_name(const char* name) { + if (!name) return KIT_PROFILE_COUNTER_NONE; +#define METRICS_COUNTER(s, id) \ + if (metrics_streq(name, s)) return id + METRICS_COUNTER("compile.input_bytes", + KIT_PROFILE_COUNTER_COMPILE_INPUT_BYTES); + METRICS_COUNTER("compile.obj_sections", + KIT_PROFILE_COUNTER_COMPILE_OBJ_SECTIONS); + METRICS_COUNTER("compile.obj_relocs", KIT_PROFILE_COUNTER_COMPILE_OBJ_RELOCS); + METRICS_COUNTER("cg.switch.table", KIT_PROFILE_COUNTER_CG_SWITCH_TABLE); + METRICS_COUNTER("cg.switch.chain", KIT_PROFILE_COUNTER_CG_SWITCH_CHAIN); + METRICS_COUNTER("opt.funcs", KIT_PROFILE_COUNTER_OPT_FUNCS); + METRICS_COUNTER("opt.blocks", KIT_PROFILE_COUNTER_OPT_BLOCKS); + METRICS_COUNTER("opt.pregs", KIT_PROFILE_COUNTER_OPT_PREGS); + METRICS_COUNTER("opt.live_words", KIT_PROFILE_COUNTER_OPT_LIVE_WORDS); + METRICS_COUNTER("opt.ranges", KIT_PROFILE_COUNTER_OPT_RANGES); + METRICS_COUNTER("opt.range_points", KIT_PROFILE_COUNTER_OPT_RANGE_POINTS); + METRICS_COUNTER("opt.range_raw_points", + KIT_PROFILE_COUNTER_OPT_RANGE_RAW_POINTS); + METRICS_COUNTER("opt.range_max_per_preg", + KIT_PROFILE_COUNTER_OPT_RANGE_MAX_PER_PREG); + METRICS_COUNTER("opt.range_max_length", + KIT_PROFILE_COUNTER_OPT_RANGE_MAX_LENGTH); + METRICS_COUNTER("opt.range_whole_block_spans", + KIT_PROFILE_COUNTER_OPT_RANGE_WHOLE_BLOCK_SPANS); + METRICS_COUNTER("opt.live.bitset_words_touched", + KIT_PROFILE_COUNTER_OPT_LIVE_BITSET_WORDS_TOUCHED); + METRICS_COUNTER("opt.live.dataflow_iterations", + KIT_PROFILE_COUNTER_OPT_LIVE_DATAFLOW_ITERATIONS); + METRICS_COUNTER("opt.live.dataflow_block_visits", + KIT_PROFILE_COUNTER_OPT_LIVE_DATAFLOW_BLOCK_VISITS); + METRICS_COUNTER("opt.range.point_visits", + KIT_PROFILE_COUNTER_OPT_RANGE_POINT_VISITS); + METRICS_COUNTER("opt.range.preg_scans", + KIT_PROFILE_COUNTER_OPT_RANGE_PREG_SCANS); + METRICS_COUNTER("opt.range.live_words_touched", + KIT_PROFILE_COUNTER_OPT_RANGE_LIVE_WORDS_TOUCHED); + METRICS_COUNTER("opt.conflict_bytes", KIT_PROFILE_COUNTER_OPT_CONFLICT_BYTES); + METRICS_COUNTER("opt.coalesce.moves_seen", + KIT_PROFILE_COUNTER_OPT_COALESCE_MOVES_SEEN); + METRICS_COUNTER("opt.coalesce.candidates", + KIT_PROFILE_COUNTER_OPT_COALESCE_CANDIDATES); + METRICS_COUNTER("opt.coalesce.conflicts", + KIT_PROFILE_COUNTER_OPT_COALESCE_CONFLICTS); + METRICS_COUNTER("opt.coalesce.merge_attempts", + KIT_PROFILE_COUNTER_OPT_COALESCE_MERGE_ATTEMPTS); + METRICS_COUNTER("opt.coalesce.merges", + KIT_PROFILE_COUNTER_OPT_COALESCE_MERGES); + METRICS_COUNTER("opt.inline.candidates", + KIT_PROFILE_COUNTER_OPT_INLINE_CANDIDATES); + METRICS_COUNTER("opt.inline.refuse_policy", + KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_POLICY); + METRICS_COUNTER("opt.inline.refuse_scc", + KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_SCC); + METRICS_COUNTER("opt.inline.refuse_shape", + KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_SHAPE); + METRICS_COUNTER("opt.inline.refuse_growth", + KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_GROWTH); + METRICS_COUNTER("opt.inline.refuse_rewrite_shape", + KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_REWRITE_SHAPE); + METRICS_COUNTER("opt.inline.refuse_rewrite", + KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_REWRITE); + METRICS_COUNTER("opt.inline.refuse_shape_variadic", + KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_SHAPE_VARIADIC); + METRICS_COUNTER("opt.inline.refuse_shape_entry", + KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_SHAPE_ENTRY); + METRICS_COUNTER("opt.inline.refuse_shape_op", + KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_SHAPE_OP); + METRICS_COUNTER("opt.inline.refuse_shape_ret_pos", + KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_SHAPE_RET_POS); + METRICS_COUNTER("opt.inline.refuse_shape_ret_count", + KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_SHAPE_RET_COUNT); + METRICS_COUNTER("opt.inline.refuse_shape_budget", + KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_SHAPE_BUDGET); + METRICS_COUNTER("opt.inline.inlined", KIT_PROFILE_COUNTER_OPT_INLINE_INLINED); + METRICS_COUNTER("opt.tiny_inline.candidates", + KIT_PROFILE_COUNTER_OPT_TINY_INLINE_CANDIDATES); + METRICS_COUNTER("opt.tiny_inline.refuse_policy", + KIT_PROFILE_COUNTER_OPT_TINY_INLINE_REFUSE_POLICY); + METRICS_COUNTER("opt.tiny_inline.refuse_scc", + KIT_PROFILE_COUNTER_OPT_TINY_INLINE_REFUSE_SCC); + METRICS_COUNTER("opt.tiny_inline.refuse_shape", + KIT_PROFILE_COUNTER_OPT_TINY_INLINE_REFUSE_SHAPE); + METRICS_COUNTER("opt.tiny_inline.refuse_budget", + KIT_PROFILE_COUNTER_OPT_TINY_INLINE_REFUSE_BUDGET); + METRICS_COUNTER("opt.tiny_inline.refuse_rewrite_shape", + KIT_PROFILE_COUNTER_OPT_TINY_INLINE_REFUSE_REWRITE_SHAPE); + METRICS_COUNTER("opt.tiny_inline.refuse_rewrite", + KIT_PROFILE_COUNTER_OPT_TINY_INLINE_REFUSE_REWRITE); + METRICS_COUNTER("opt.tiny_inline.inlined", + KIT_PROFILE_COUNTER_OPT_TINY_INLINE_INLINED); + METRICS_COUNTER("link.inputs", KIT_PROFILE_COUNTER_LINK_INPUTS); + METRICS_COUNTER("link.sections", KIT_PROFILE_COUNTER_LINK_SECTIONS); + METRICS_COUNTER("link.segments", KIT_PROFILE_COUNTER_LINK_SEGMENTS); + METRICS_COUNTER("link.syms", KIT_PROFILE_COUNTER_LINK_SYMS); + METRICS_COUNTER("link.relocs", KIT_PROFILE_COUNTER_LINK_RELOCS); + METRICS_COUNTER("jit.input_section_bytes", + KIT_PROFILE_COUNTER_JIT_INPUT_SECTION_BYTES); + METRICS_COUNTER("jit.master_size", KIT_PROFILE_COUNTER_JIT_MASTER_SIZE); + METRICS_COUNTER("jit.nsegments", KIT_PROFILE_COUNTER_JIT_NSEGMENTS); + METRICS_COUNTER("jit.segment_bytes", KIT_PROFILE_COUNTER_JIT_SEGMENT_BYTES); +#undef METRICS_COUNTER + return KIT_PROFILE_COUNTER_NONE; } static inline void metrics_scope_begin(Compiler* c, const char* name) { - const KitMetrics* m = metrics_sink(c); - if (m && m->scope_begin) m->scope_begin(m->user, name); + KitProfileScope scope = metrics_scope_from_name(name); + if (scope != KIT_PROFILE_SCOPE_NONE) profile_scope_begin(c, scope); } static inline void metrics_scope_end(Compiler* c, const char* name) { - const KitMetrics* m = metrics_sink(c); - if (m && m->scope_end) m->scope_end(m->user, name); + KitProfileScope scope = metrics_scope_from_name(name); + if (scope != KIT_PROFILE_SCOPE_NONE) profile_scope_end(c, scope); } static inline void metrics_count(Compiler* c, const char* name, u64 value) { - const KitMetrics* m = metrics_sink(c); - if (m && m->count) m->count(m->user, name, value); + KitProfileCounter counter = metrics_counter_from_name(name); + if (counter != KIT_PROFILE_COUNTER_NONE) profile_count(c, counter, value); } #endif diff --git a/src/core/profile.c b/src/core/profile.c @@ -0,0 +1,299 @@ +#include "core/profile.h" + +void kit_profiler_reset(KitProfiler* p) { + unsigned char* b; + size_t i; + if (!p) return; + b = (unsigned char*)p; + for (i = 0; i < sizeof(*p); ++i) b[i] = 0; +} + +const char* kit_profile_scope_name(KitProfileScope scope) { + switch (scope) { + case KIT_PROFILE_SCOPE_COMPILE_TU: + return "compile.tu"; + case KIT_PROFILE_SCOPE_COMPILE_FRONTEND: + return "compile.frontend"; + case KIT_PROFILE_SCOPE_COMPILE_OBJ_FINALIZE: + return "compile.obj_finalize"; + case KIT_PROFILE_SCOPE_COMPILE_ASM_LEX_OPEN: + return "compile.asm.lex_open"; + case KIT_PROFILE_SCOPE_COMPILE_ASM_MC_NEW: + return "compile.asm.mc_new"; + case KIT_PROFILE_SCOPE_COMPILE_ASM_PARSE: + return "compile.asm.parse"; + case KIT_PROFILE_SCOPE_COMPILE_ASM_MC_FREE: + return "compile.asm.mc_free"; + case KIT_PROFILE_SCOPE_CG: + return "cg"; + case KIT_PROFILE_SCOPE_NDT: + return "cg.ndt"; + case KIT_PROFILE_SCOPE_NATIVE_TARGET: + return "cg.native_target"; + case KIT_PROFILE_SCOPE_MC_EMIT: + return "mc.emit"; + case KIT_PROFILE_SCOPE_OPT_CFG_BUILD_1: + return "opt.cfg.build_1"; + case KIT_PROFILE_SCOPE_OPT_CFG_JUMP_CLEANUP_CFG: + return "opt.cfg.jump_cleanup_cfg"; + case KIT_PROFILE_SCOPE_OPT_CFG_BUILD_2: + return "opt.cfg.build_2"; + case KIT_PROFILE_SCOPE_OPT_CFG_SIMPLIFY_LOCAL: + return "opt.cfg.simplify_local"; + case KIT_PROFILE_SCOPE_OPT_CFG_VERIFY: + return "opt.cfg.verify"; + case KIT_PROFILE_SCOPE_OPT_MACHINIZE: + return "opt.machinize"; + case KIT_PROFILE_SCOPE_OPT_MACHINIZE_VERIFY: + return "opt.machinize.verify"; + case KIT_PROFILE_SCOPE_OPT_O1_ADDR_XFORM_PREGS: + return "opt.o1.addr_xform_pregs"; + case KIT_PROFILE_SCOPE_OPT_O1_ADDR_XFORM_VERIFY: + return "opt.o1.addr_xform.verify"; + case KIT_PROFILE_SCOPE_OPT_O1_PROMOTE_SCALAR_LOCALS: + return "opt.o1.promote_scalar_locals"; + case KIT_PROFILE_SCOPE_OPT_O1_PROMOTE_SCALAR_VERIFY: + return "opt.o1.promote_scalar.verify"; + case KIT_PROFILE_SCOPE_OPT_O1_ADDR_OF_GLOBAL_CSE: + return "opt.o1.addr_of_global_cse"; + case KIT_PROFILE_SCOPE_OPT_O1_ADDR_OF_GLOBAL_VERIFY: + return "opt.o1.addr_of_global.verify"; + case KIT_PROFILE_SCOPE_OPT_BUILD_LOOP_TREE: + return "opt.build_loop_tree"; + case KIT_PROFILE_SCOPE_OPT_O1_LOWER_LOOP_IMM: + return "opt.o1.lower_loop_imm"; + case KIT_PROFILE_SCOPE_OPT_O1_HOIST_LOOP_CONSTS: + return "opt.o1.hoist_loop_consts"; + case KIT_PROFILE_SCOPE_OPT_LIVE_BLOCKS_PRE_DDE: + return "opt.live_blocks.pre_dde"; + case KIT_PROFILE_SCOPE_OPT_DEAD_DEF_ELIM: + return "opt.dead_def_elim"; + case KIT_PROFILE_SCOPE_OPT_REGALLOC: + return "opt.regalloc"; + case KIT_PROFILE_SCOPE_OPT_REGALLOC_VERIFY: + return "opt.regalloc.verify"; + case KIT_PROFILE_SCOPE_OPT_LIVE_RANGES_REGALLOC: + return "opt.live_ranges.regalloc"; + case KIT_PROFILE_SCOPE_OPT_LOWER_MIR: + return "opt.lower_mir"; + case KIT_PROFILE_SCOPE_OPT_LOWER_MIR_VERIFY: + return "opt.lower_mir.verify"; + case KIT_PROFILE_SCOPE_OPT_COMBINE: + return "opt.combine"; + case KIT_PROFILE_SCOPE_OPT_COMBINE_VERIFY: + return "opt.combine.verify"; + case KIT_PROFILE_SCOPE_OPT_DCE: + return "opt.dce"; + case KIT_PROFILE_SCOPE_OPT_DCE_VERIFY: + return "opt.dce.verify"; + case KIT_PROFILE_SCOPE_OPT_POST_RA_JUMP_CLEANUP_CFG: + return "opt.post_ra.jump_cleanup_cfg"; + case KIT_PROFILE_SCOPE_OPT_POST_RA_BUILD_CFG: + return "opt.post_ra.build_cfg"; + case KIT_PROFILE_SCOPE_OPT_POST_RA_VERIFY: + return "opt.post_ra.verify"; + case KIT_PROFILE_SCOPE_OPT_POST_RA_JUMP_CLEANUP_LAYOUT: + return "opt.post_ra.jump_cleanup_layout"; + case KIT_PROFILE_SCOPE_OPT_EMIT: + return "opt.emit"; + case KIT_PROFILE_SCOPE_OPT_O1_TINY_INLINE: + return "opt.o1.tiny_inline"; + case KIT_PROFILE_SCOPE_OPT_O1_CG_IR_LOWER: + return "opt.o1.cg_ir_lower"; + case KIT_PROFILE_SCOPE_OPT_INLINE_TOTAL: + return "opt.inline.total"; + case KIT_PROFILE_SCOPE_OPT_O1_TOTAL: + return "opt.o1.total"; + case KIT_PROFILE_SCOPE_OPT_INTERP_TOTAL: + return "opt.interp.total"; + case KIT_PROFILE_SCOPE_OPT_NATIVE_EMIT_SETUP: + return "opt.native_emit.setup"; + case KIT_PROFILE_SCOPE_OPT_NATIVE_EMIT_FUNC_BEGIN: + return "opt.native_emit.func_begin"; + case KIT_PROFILE_SCOPE_OPT_NATIVE_EMIT_BODY: + return "opt.native_emit.body"; + case KIT_PROFILE_SCOPE_OPT_NATIVE_EMIT_FUNC_END: + return "opt.native_emit.func_end"; + case KIT_PROFILE_SCOPE_LINK_RESOLVE_TOTAL: + return "link.resolve.total"; + case KIT_PROFILE_SCOPE_LINK_INGEST_ARCHIVES: + return "link.ingest_archives"; + case KIT_PROFILE_SCOPE_LINK_RESOLVE_SYMBOLS: + return "link.resolve_symbols"; + case KIT_PROFILE_SCOPE_LINK_GC: + return "link.gc"; + case KIT_PROFILE_SCOPE_LINK_LAYOUT_SECTIONS: + return "link.layout_sections"; + case KIT_PROFILE_SCOPE_LINK_EMIT_SEGMENT_BYTES: + return "link.emit_segment_bytes"; + case KIT_PROFILE_SCOPE_LINK_LAYOUT_DEBUG: + return "link.layout_debug"; + case KIT_PROFILE_SCOPE_LINK_ASSIGN_VADDRS: + return "link.assign_vaddrs"; + case KIT_PROFILE_SCOPE_LINK_EMIT_BOUNDARIES: + return "link.emit_boundaries"; + case KIT_PROFILE_SCOPE_LINK_RESOLVE_UNDEFS: + return "link.resolve_undefs"; + case KIT_PROFILE_SCOPE_LINK_GC_DROP_DEAD: + return "link.gc_drop_dead"; + case KIT_PROFILE_SCOPE_LINK_LAYOUT_IPLT: + return "link.layout_iplt"; + case KIT_PROFILE_SCOPE_LINK_LAYOUT_JIT_STUBS: + return "link.layout_jit_stubs"; + case KIT_PROFILE_SCOPE_LINK_LAYOUT_GOT: + return "link.layout_got"; + case KIT_PROFILE_SCOPE_LINK_EMIT_RELOCATIONS: + return "link.emit_relocations"; + case KIT_PROFILE_SCOPE_LINK_LAYOUT_DYN: + return "link.layout_dyn"; + case KIT_PROFILE_SCOPE_LINK_RESOLVE_ENTRY: + return "link.resolve_entry"; + case KIT_PROFILE_SCOPE_LINK_CAPTURE_DEBUG: + return "link.capture_debug"; + case KIT_PROFILE_SCOPE_JIT_RESERVE: + return "jit.reserve"; + case KIT_PROFILE_SCOPE_JIT_COPY_SEGMENTS: + return "jit.copy_segments"; + case KIT_PROFILE_SCOPE_JIT_APPLY_RELOCS: + return "jit.apply_relocs"; + case KIT_PROFILE_SCOPE_JIT_PROTECT: + return "jit.protect"; + case KIT_PROFILE_SCOPE_JIT_FLUSH_ICACHE: + return "jit.flush_icache"; + case KIT_PROFILE_SCOPE_JIT_CTORS: + return "jit.ctors"; + case KIT_PROFILE_SCOPE_DRIVER_LOAD_SOURCES: + return "driver.load_sources"; + case KIT_PROFILE_SCOPE_DRIVER_LOAD_OBJECTS: + return "driver.load_objects"; + case KIT_PROFILE_SCOPE_DRIVER_LOAD_ARCHIVES: + return "driver.load_archives"; + case KIT_PROFILE_SCOPE_DRIVER_LINK_SETUP: + return "driver.link_setup"; + default: + return 0; + } +} + +const char* kit_profile_counter_name(KitProfileCounter counter) { + switch (counter) { + case KIT_PROFILE_COUNTER_COMPILE_INPUT_BYTES: + return "compile.input_bytes"; + case KIT_PROFILE_COUNTER_COMPILE_OBJ_SECTIONS: + return "compile.obj_sections"; + case KIT_PROFILE_COUNTER_COMPILE_OBJ_RELOCS: + return "compile.obj_relocs"; + case KIT_PROFILE_COUNTER_CG_SWITCH_TABLE: + return "cg.switch.table"; + case KIT_PROFILE_COUNTER_CG_SWITCH_CHAIN: + return "cg.switch.chain"; + case KIT_PROFILE_COUNTER_OPT_FUNCS: + return "opt.funcs"; + case KIT_PROFILE_COUNTER_OPT_BLOCKS: + return "opt.blocks"; + case KIT_PROFILE_COUNTER_OPT_PREGS: + return "opt.pregs"; + case KIT_PROFILE_COUNTER_OPT_LIVE_WORDS: + return "opt.live_words"; + case KIT_PROFILE_COUNTER_OPT_RANGES: + return "opt.ranges"; + case KIT_PROFILE_COUNTER_OPT_RANGE_POINTS: + return "opt.range_points"; + case KIT_PROFILE_COUNTER_OPT_RANGE_RAW_POINTS: + return "opt.range_raw_points"; + case KIT_PROFILE_COUNTER_OPT_RANGE_MAX_PER_PREG: + return "opt.range_max_per_preg"; + case KIT_PROFILE_COUNTER_OPT_RANGE_MAX_LENGTH: + return "opt.range_max_length"; + case KIT_PROFILE_COUNTER_OPT_RANGE_WHOLE_BLOCK_SPANS: + return "opt.range_whole_block_spans"; + case KIT_PROFILE_COUNTER_OPT_LIVE_BITSET_WORDS_TOUCHED: + return "opt.live.bitset_words_touched"; + case KIT_PROFILE_COUNTER_OPT_LIVE_DATAFLOW_ITERATIONS: + return "opt.live.dataflow_iterations"; + case KIT_PROFILE_COUNTER_OPT_LIVE_DATAFLOW_BLOCK_VISITS: + return "opt.live.dataflow_block_visits"; + case KIT_PROFILE_COUNTER_OPT_RANGE_POINT_VISITS: + return "opt.range.point_visits"; + case KIT_PROFILE_COUNTER_OPT_RANGE_PREG_SCANS: + return "opt.range.preg_scans"; + case KIT_PROFILE_COUNTER_OPT_RANGE_LIVE_WORDS_TOUCHED: + return "opt.range.live_words_touched"; + case KIT_PROFILE_COUNTER_OPT_CONFLICT_BYTES: + return "opt.conflict_bytes"; + case KIT_PROFILE_COUNTER_OPT_COALESCE_MOVES_SEEN: + return "opt.coalesce.moves_seen"; + case KIT_PROFILE_COUNTER_OPT_COALESCE_CANDIDATES: + return "opt.coalesce.candidates"; + case KIT_PROFILE_COUNTER_OPT_COALESCE_CONFLICTS: + return "opt.coalesce.conflicts"; + case KIT_PROFILE_COUNTER_OPT_COALESCE_MERGE_ATTEMPTS: + return "opt.coalesce.merge_attempts"; + case KIT_PROFILE_COUNTER_OPT_COALESCE_MERGES: + return "opt.coalesce.merges"; + case KIT_PROFILE_COUNTER_OPT_INLINE_CANDIDATES: + return "opt.inline.candidates"; + case KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_POLICY: + return "opt.inline.refuse_policy"; + case KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_SCC: + return "opt.inline.refuse_scc"; + case KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_SHAPE: + return "opt.inline.refuse_shape"; + case KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_GROWTH: + return "opt.inline.refuse_growth"; + case KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_REWRITE_SHAPE: + return "opt.inline.refuse_rewrite_shape"; + case KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_REWRITE: + return "opt.inline.refuse_rewrite"; + case KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_SHAPE_VARIADIC: + return "opt.inline.refuse_shape_variadic"; + case KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_SHAPE_ENTRY: + return "opt.inline.refuse_shape_entry"; + case KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_SHAPE_OP: + return "opt.inline.refuse_shape_op"; + case KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_SHAPE_RET_POS: + return "opt.inline.refuse_shape_ret_pos"; + case KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_SHAPE_RET_COUNT: + return "opt.inline.refuse_shape_ret_count"; + case KIT_PROFILE_COUNTER_OPT_INLINE_REFUSE_SHAPE_BUDGET: + return "opt.inline.refuse_shape_budget"; + case KIT_PROFILE_COUNTER_OPT_INLINE_INLINED: + return "opt.inline.inlined"; + case KIT_PROFILE_COUNTER_OPT_TINY_INLINE_CANDIDATES: + return "opt.tiny_inline.candidates"; + case KIT_PROFILE_COUNTER_OPT_TINY_INLINE_REFUSE_POLICY: + return "opt.tiny_inline.refuse_policy"; + case KIT_PROFILE_COUNTER_OPT_TINY_INLINE_REFUSE_SCC: + return "opt.tiny_inline.refuse_scc"; + case KIT_PROFILE_COUNTER_OPT_TINY_INLINE_REFUSE_SHAPE: + return "opt.tiny_inline.refuse_shape"; + case KIT_PROFILE_COUNTER_OPT_TINY_INLINE_REFUSE_BUDGET: + return "opt.tiny_inline.refuse_budget"; + case KIT_PROFILE_COUNTER_OPT_TINY_INLINE_REFUSE_REWRITE_SHAPE: + return "opt.tiny_inline.refuse_rewrite_shape"; + case KIT_PROFILE_COUNTER_OPT_TINY_INLINE_REFUSE_REWRITE: + return "opt.tiny_inline.refuse_rewrite"; + case KIT_PROFILE_COUNTER_OPT_TINY_INLINE_INLINED: + return "opt.tiny_inline.inlined"; + case KIT_PROFILE_COUNTER_LINK_INPUTS: + return "link.inputs"; + case KIT_PROFILE_COUNTER_LINK_SECTIONS: + return "link.sections"; + case KIT_PROFILE_COUNTER_LINK_SEGMENTS: + return "link.segments"; + case KIT_PROFILE_COUNTER_LINK_SYMS: + return "link.syms"; + case KIT_PROFILE_COUNTER_LINK_RELOCS: + return "link.relocs"; + case KIT_PROFILE_COUNTER_JIT_INPUT_SECTION_BYTES: + return "jit.input_section_bytes"; + case KIT_PROFILE_COUNTER_JIT_MASTER_SIZE: + return "jit.master_size"; + case KIT_PROFILE_COUNTER_JIT_NSEGMENTS: + return "jit.nsegments"; + case KIT_PROFILE_COUNTER_JIT_SEGMENT_BYTES: + return "jit.segment_bytes"; + default: + return 0; + } +} diff --git a/src/core/profile.h b/src/core/profile.h @@ -0,0 +1,33 @@ +#ifndef KIT_INTERNAL_PROFILE_H +#define KIT_INTERNAL_PROFILE_H + +#include "core/core.h" + +static inline KitProfiler* profile_sink(Compiler* c) { + return (c && c->ctx) ? c->ctx->profiler : NULL; +} + +static inline void profile_scope_begin(Compiler* c, KitProfileScope scope) { + kit_profiler_scope_begin(profile_sink(c), scope); +} + +static inline void profile_scope_end(Compiler* c, KitProfileScope scope) { + kit_profiler_scope_end(profile_sink(c), scope); +} + +static inline void profile_count(Compiler* c, KitProfileCounter counter, + u64 value) { + kit_profiler_count(profile_sink(c), counter, value); +} + +static inline void profile_define_scope(Compiler* c, KitProfileScope scope, + const char* name) { + kit_profiler_define_scope(profile_sink(c), scope, name); +} + +static inline void profile_define_counter(Compiler* c, KitProfileCounter counter, + const char* name) { + kit_profiler_define_counter(profile_sink(c), counter, name); +} + +#endif diff --git a/test/api/profile_test.c b/test/api/profile_test.c @@ -0,0 +1,81 @@ +/* profile_test - public <kit/core.h> profiler API. */ + +#include <kit/core.h> +#include <stdlib.h> +#include <string.h> + +#include "lib/kit_unit.h" + +static KitUnit g_u; +#define EXPECT(c, ...) CU_EXPECT(&g_u, c, __VA_ARGS__) + +static void check_names_and_ranges(void) { + EXPECT(strcmp(kit_profile_scope_name(KIT_PROFILE_SCOPE_COMPILE_TU), + "compile.tu") == 0, + "builtin scope name"); + EXPECT(strcmp(kit_profile_counter_name(KIT_PROFILE_COUNTER_COMPILE_INPUT_BYTES), + "compile.input_bytes") == 0, + "builtin counter name"); + EXPECT(kit_profile_scope_name(KIT_PROFILE_SCOPE_LANG_FIRST) == NULL, + "language scopes are open"); + EXPECT(kit_profile_counter_name(KIT_PROFILE_COUNTER_EXTERNAL_FIRST) == NULL, + "external counters are open"); +} + +static void check_concrete_profiler(void) { + KitProfiler* p; + KitContext ctx; + const char* scope_name; + const char* counter_name; + memset(&ctx, 0, sizeof ctx); + p = (KitProfiler*)malloc(sizeof(*p)); + EXPECT(p != NULL, "allocate profiler"); + if (!p) return; + + kit_profiler_reset(NULL); + kit_profiler_scope_begin(NULL, KIT_PROFILE_SCOPE_COMPILE_TU); + kit_profiler_scope_end(NULL, KIT_PROFILE_SCOPE_COMPILE_TU); + kit_profiler_count(NULL, KIT_PROFILE_COUNTER_COMPILE_INPUT_BYTES, 7); + + kit_profiler_reset(p); + ctx.profiler = p; + + kit_profile_define_scope(&ctx, KIT_PROFILE_SCOPE_LANG_FIRST, "lang.test"); + kit_profile_define_counter(&ctx, KIT_PROFILE_COUNTER_EXTERNAL_FIRST, + "host.test"); + kit_profile_scope_begin(&ctx, KIT_PROFILE_SCOPE_COMPILE_FRONTEND); + kit_profile_count(&ctx, KIT_PROFILE_COUNTER_COMPILE_INPUT_BYTES, 42); + kit_profile_scope_end(&ctx, KIT_PROFILE_SCOPE_COMPILE_FRONTEND); + + EXPECT(kit_profiler_scope_count(p, KIT_PROFILE_SCOPE_COMPILE_FRONTEND) == 1, + "scope call count"); + EXPECT(kit_profiler_counter_value(p, + KIT_PROFILE_COUNTER_COMPILE_INPUT_BYTES) == + 42, + "counter value"); + EXPECT(p->depth == 0, "scope stack is balanced"); + scope_name = kit_profiler_scope_name(p, KIT_PROFILE_SCOPE_LANG_FIRST); + counter_name = + kit_profiler_counter_name(p, KIT_PROFILE_COUNTER_EXTERNAL_FIRST); + EXPECT(scope_name && strcmp(scope_name, "lang.test") == 0, + "defined language scope name"); + EXPECT(counter_name && strcmp(counter_name, "host.test") == 0, + "defined external counter name"); + + kit_profiler_reset(p); + EXPECT(kit_profiler_scope_count(p, KIT_PROFILE_SCOPE_COMPILE_FRONTEND) == 0, + "reset clears scope counts"); + EXPECT(kit_profiler_counter_value(p, + KIT_PROFILE_COUNTER_COMPILE_INPUT_BYTES) == + 0, + "reset clears counters"); + free(p); +} + +int main(void) { + kit_unit_init(&g_u); + check_names_and_ranges(); + check_concrete_profiler(); + kit_unit_summary(&g_u, "profile_test"); + return kit_unit_status(&g_u); +} diff --git a/test/elf/unit/align_4k.c b/test/elf/unit/align_4k.c @@ -71,7 +71,6 @@ int main(void) { KitContext ctx = {.heap = &g_heap, .file_io = NULL, .diag = &g_diag, - .metrics = NULL, .now = -1}; KitTargetOptions target_opts; memset(&target_opts, 0, sizeof target_opts); diff --git a/test/elf/unit/groupiter.c b/test/elf/unit/groupiter.c @@ -75,7 +75,6 @@ int main(void) { KitContext ctx = {.heap = &g_heap, .file_io = NULL, .diag = &g_diag, - .metrics = NULL, .now = -1}; KitTargetOptions target_opts; memset(&target_opts, 0, sizeof target_opts); diff --git a/test/elf/unit/mutate.c b/test/elf/unit/mutate.c @@ -74,7 +74,6 @@ int main(void) { KitContext ctx = {.heap = &g_heap, .file_io = NULL, .diag = &g_diag, - .metrics = NULL, .now = -1}; KitTargetOptions target_opts; memset(&target_opts, 0, sizeof target_opts);