commit 5e69b646150a00a9b2db85dc89f5fdc5eacd1f3e
parent 62709d0deefba724be60743649962c604f808d87
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Sun, 14 Jun 2026 11:28:40 -0700
Add concrete profiler API
Diffstat:
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);