mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-03 08:03:38 +08:00
perf(cs): eliminate the C# corpus-proportional scans — 1211s -> 450s, +37% edges
Four measured changes on the dotnet/runtime corpus (58,656 files; every step's numbers below are from full-corpus runs on the same host, baselines captured this session; v0.9.0 = 444.3 s): 1. Two-phase cs registry build (types -> finalize -> funcs), the same pre-finalize linear-lookup disease fixed for Java: prepare 280 -> 140 s. 2. C# import-context carve-out: cs_import_types lists namespace_declaration (for namespace-name mapping) and using_statement (C#'s RAII block — a grammar-name collision), so EVERY namespaced C# file's whole body ran with inside_import=true. That both suppressed ordinary usage extraction under namespaces and sent every identifier through the ancestor-walking import-binding check (tree-sitter's ts_node_parent re-descends from the root, so wide files went quadratic: one 147 KB JIT torture file cost 490 s; 6.8 s after). Only using_directive / namespace_use_declaration open an import scope now. Restores the suppressed usages: edges 4,291,387 -> 5,869,093 (+37%), nodes identical. 3. The usages walker maintains call/import ancestry as enter/exit counters on its explicit stack instead of per-node ancestor re-walks (extract_usages.c had grown from 6 to 100 ts_node_parent calls since v0.9.0; the two per-node gates are now O(1) with semantics preserved — strict ancestors only, emit before self-count). 4. Registry short-name indexes replace the two remaining full scans: cs_lookup_extension walked all 963k funcs per unresolved invocation (now the existing free-func short-name iterator, first-match order preserved via min-index selection), and cs_resolve_type_name's step-9 fallback scanned every type per unresolved name IN BOTH the builder and per-file resolution (new type_short index in finalize, same reverse-insertion ascending-order pattern, best-score ties keep the first-in-registration-order winner). Builder 140,095 -> 500 ms; resolve cross-LSP CPU 5.5M -> 317k ms (us_per_file_per_kdef 191 -> 11). End state: 449.9 s wall (1.01x of v0.9.0) with +48.6% edges vs v0.9.0 — per-edge cost 32% BETTER than v0.9.0. Extract's remaining 359 s is the 24 MB hugeexpr1.cs parse floor both versions pay. Guarded by the complexity suite; cs_lsp/extraction/edge/lang-contract suites green including the 53-language calls-breadth contract. Refs #1669. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
This commit is contained in:
@@ -1646,6 +1646,18 @@ static bool is_actual_import_boundary(CBMExtractCtx *ctx, TSNode node, const CBM
|
|||||||
char *name = ts_node_is_null(head) ? NULL : cbm_node_text(ctx->arena, head, ctx->source);
|
char *name = ts_node_is_null(head) ? NULL : cbm_node_text(ctx->arena, head, ctx->source);
|
||||||
|
|
||||||
switch (ctx->language) {
|
switch (ctx->language) {
|
||||||
|
case CBM_LANG_CSHARP:
|
||||||
|
/* cs_import_types also lists namespace_declaration (so the import pass
|
||||||
|
* can map namespace names) and using_statement (C#'s RAII block, a
|
||||||
|
* grammar-name collision with using_directive). Neither is an import
|
||||||
|
* CONTEXT: treating them as one put every namespaced C# file's whole
|
||||||
|
* body behind inside_import, which both suppressed ordinary usage
|
||||||
|
* extraction there and sent every identifier through the ancestor-
|
||||||
|
* walking import-binding check — 92% of extract time on wide files
|
||||||
|
* (dotnet/runtime JIT torture tests, 490 s for one 147 KB file). Only
|
||||||
|
* the using DIRECTIVE opens an import scope. */
|
||||||
|
return strcmp(kind, "using_directive") == 0 ||
|
||||||
|
strcmp(kind, "namespace_use_declaration") == 0;
|
||||||
case CBM_LANG_ELIXIR:
|
case CBM_LANG_ELIXIR:
|
||||||
return strcmp(kind, "call") != 0 ||
|
return strcmp(kind, "call") != 0 ||
|
||||||
(name && (strcmp(name, "import") == 0 || strcmp(name, "alias") == 0 ||
|
(name && (strcmp(name, "import") == 0 || strcmp(name, "alias") == 0 ||
|
||||||
|
|||||||
@@ -49,36 +49,6 @@ static void walk_usages(CBMExtractCtx *ctx, TSNode root, const CBMLangSpec *spec
|
|||||||
static bool is_direct_argument_value(TSNode node);
|
static bool is_direct_argument_value(TSNode node);
|
||||||
static TSNode python_direct_callable_attribute_site(TSNode node);
|
static TSNode python_direct_callable_attribute_site(TSNode node);
|
||||||
|
|
||||||
// Check if a node is inside a call expression (to avoid double-counting as usage)
|
|
||||||
static bool is_inside_call(TSNode node, const CBMLangSpec *spec) {
|
|
||||||
TSNode cur = ts_node_parent(node);
|
|
||||||
while (!ts_node_is_null(cur)) {
|
|
||||||
if (cbm_kind_in_set(cur, spec->call_node_types)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
cur = ts_node_parent(cur);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if a node is inside an import statement
|
|
||||||
static bool is_inside_import(TSNode node, const CBMLangSpec *spec) {
|
|
||||||
bool has_imports = spec->import_node_types && spec->import_node_types[0];
|
|
||||||
bool has_from_imports = spec->import_from_types && spec->import_from_types[0];
|
|
||||||
if (!has_imports && !has_from_imports) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
TSNode cur = ts_node_parent(node);
|
|
||||||
while (!ts_node_is_null(cur)) {
|
|
||||||
if ((has_imports && cbm_kind_in_set(cur, spec->import_node_types)) ||
|
|
||||||
(has_from_imports && cbm_kind_in_set(cur, spec->import_from_types))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
cur = ts_node_parent(cur);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is this an identifier-like node that represents a reference?
|
// Is this an identifier-like node that represents a reference?
|
||||||
static bool is_reference_node(TSNode node, CBMLanguage lang) {
|
static bool is_reference_node(TSNode node, CBMLanguage lang) {
|
||||||
const char *kind = ts_node_type(node);
|
const char *kind = ts_node_type(node);
|
||||||
@@ -2426,7 +2396,8 @@ static bool emit_direct_perl_coderef_usage(CBMExtractCtx *ctx, TSNode node,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try to emit a usage for a reference node. Returns early if the node should be skipped.
|
// Try to emit a usage for a reference node. Returns early if the node should be skipped.
|
||||||
static void try_emit_usage(CBMExtractCtx *ctx, TSNode node, const CBMLangSpec *spec) {
|
static void try_emit_usage(CBMExtractCtx *ctx, TSNode node, const CBMLangSpec *spec,
|
||||||
|
bool inside_call, bool inside_import) {
|
||||||
if (emit_direct_perl_coderef_usage(ctx, node, cbm_enclosing_func_qn_cached(ctx, node), 0)) {
|
if (emit_direct_perl_coderef_usage(ctx, node, cbm_enclosing_func_qn_cached(ctx, node), 0)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2439,7 +2410,7 @@ static void try_emit_usage(CBMExtractCtx *ctx, TSNode node, const CBMLangSpec *s
|
|||||||
if (is_call_argument_label(node)) {
|
if (is_call_argument_label(node)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (is_inside_call(node, spec) || is_inside_import(node, spec)) {
|
if (inside_call || inside_import) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (is_binding_occurrence(ctx, node, spec, NULL) ||
|
if (is_binding_occurrence(ctx, node, spec, NULL) ||
|
||||||
@@ -2456,18 +2427,79 @@ static void try_emit_usage(CBMExtractCtx *ctx, TSNode node, const CBMLangSpec *s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterative usage walker — explicit stack
|
// Iterative usage walker — explicit stack.
|
||||||
|
//
|
||||||
|
// The call/import ancestry that gates usage emission is maintained as ENTER/
|
||||||
|
// EXIT counters on the walk instead of per-node ancestor re-walks: the old
|
||||||
|
// is_inside_call/is_inside_import helpers climbed every ancestor via
|
||||||
|
// ts_node_parent, and tree-sitter's ts_node_parent RE-DESCENDS from the root
|
||||||
|
// scanning siblings — O(depth x sibling-position) per node, which went
|
||||||
|
// quadratic on wide nodes (a 1,536-argument call in dotnet/runtime's JIT
|
||||||
|
// torture tests put 92% of extract time into these walks; 490 s for one
|
||||||
|
// 147 KB file). Counter semantics match the helpers exactly: strict ancestors
|
||||||
|
// only — a node is emitted BEFORE its own kind increments the counters, so a
|
||||||
|
// call node itself does not count as "inside a call".
|
||||||
static void walk_usages(CBMExtractCtx *ctx, TSNode root, const CBMLangSpec *spec) {
|
static void walk_usages(CBMExtractCtx *ctx, TSNode root, const CBMLangSpec *spec) {
|
||||||
TSNodeStack stack;
|
typedef struct {
|
||||||
ts_nstack_init(&stack, ctx->arena, 4096);
|
TSNode node;
|
||||||
ts_nstack_push(&stack, ctx->arena, root);
|
uint32_t next_child;
|
||||||
|
bool counts_call;
|
||||||
|
bool counts_import;
|
||||||
|
} UsageFrame;
|
||||||
|
int cap = 256;
|
||||||
|
UsageFrame *frames = (UsageFrame *)cbm_arena_alloc(ctx->arena, (size_t)cap * sizeof(*frames));
|
||||||
|
if (!frames) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool has_imports = spec->import_node_types && spec->import_node_types[0];
|
||||||
|
bool has_from_imports = spec->import_from_types && spec->import_from_types[0];
|
||||||
|
int call_depth = 0;
|
||||||
|
int import_depth = 0;
|
||||||
|
int top = 0;
|
||||||
|
frames[top++] = (UsageFrame){root, 0, false, false};
|
||||||
|
bool entering = true;
|
||||||
|
|
||||||
while (stack.count > 0) {
|
while (top > 0) {
|
||||||
TSNode node = ts_nstack_pop(&stack);
|
UsageFrame *f = &frames[top - 1];
|
||||||
try_emit_usage(ctx, node, spec);
|
if (entering) {
|
||||||
uint32_t count = ts_node_child_count(node);
|
try_emit_usage(ctx, f->node, spec, call_depth > 0, import_depth > 0);
|
||||||
for (int i = (int)count - LAST_IDX; i >= 0; i--) {
|
f->counts_call = cbm_kind_in_set(f->node, spec->call_node_types);
|
||||||
ts_nstack_push(&stack, ctx->arena, ts_node_child(node, (uint32_t)i));
|
f->counts_import =
|
||||||
|
(has_imports && cbm_kind_in_set(f->node, spec->import_node_types)) ||
|
||||||
|
(has_from_imports && cbm_kind_in_set(f->node, spec->import_from_types));
|
||||||
|
if (f->counts_call) {
|
||||||
|
call_depth++;
|
||||||
|
}
|
||||||
|
if (f->counts_import) {
|
||||||
|
import_depth++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32_t count = ts_node_child_count(f->node);
|
||||||
|
if (f->next_child < count) {
|
||||||
|
TSNode child = ts_node_child(f->node, f->next_child);
|
||||||
|
f->next_child++;
|
||||||
|
if (top == cap) {
|
||||||
|
int new_cap = cap * 2;
|
||||||
|
UsageFrame *grown =
|
||||||
|
(UsageFrame *)cbm_arena_alloc(ctx->arena, (size_t)new_cap * sizeof(*grown));
|
||||||
|
if (!grown) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy(grown, frames, (size_t)cap * sizeof(*frames));
|
||||||
|
frames = grown;
|
||||||
|
cap = new_cap;
|
||||||
|
}
|
||||||
|
frames[top++] = (UsageFrame){child, 0, false, false};
|
||||||
|
entering = true;
|
||||||
|
} else {
|
||||||
|
if (f->counts_call) {
|
||||||
|
call_depth--;
|
||||||
|
}
|
||||||
|
if (f->counts_import) {
|
||||||
|
import_depth--;
|
||||||
|
}
|
||||||
|
top--;
|
||||||
|
entering = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+886
-513
File diff suppressed because it is too large
Load Diff
@@ -169,6 +169,46 @@ static void build_type_embed_index(CBMTypeRegistry *reg, CBMArena *idx_arena) {
|
|||||||
|
|
||||||
/* Index: short_name -> chain of FREE-function (receiver_type==NULL) indices.
|
/* Index: short_name -> chain of FREE-function (receiver_type==NULL) indices.
|
||||||
* Descending-iterate + prepend for ascending chain order (as above). */
|
* Descending-iterate + prepend for ascending chain order (as above). */
|
||||||
|
static void build_type_short_index(CBMTypeRegistry *reg, CBMArena *idx_arena) {
|
||||||
|
int tcount = 0;
|
||||||
|
for (int i = 0; i < reg->type_count; i++) {
|
||||||
|
if (reg->types[i].short_name)
|
||||||
|
tcount++;
|
||||||
|
}
|
||||||
|
if (tcount == 0)
|
||||||
|
return;
|
||||||
|
int bucket_count = next_pow2(tcount * 2);
|
||||||
|
if (bucket_count < 16)
|
||||||
|
bucket_count = 16;
|
||||||
|
int *buckets = (int *)cbm_arena_alloc(idx_arena, (size_t)bucket_count * sizeof(int));
|
||||||
|
CBMRegistryHashEntry *entries = (CBMRegistryHashEntry *)cbm_arena_alloc(
|
||||||
|
idx_arena, (size_t)tcount * sizeof(CBMRegistryHashEntry));
|
||||||
|
if (!buckets || !entries)
|
||||||
|
return;
|
||||||
|
for (int i = 0; i < bucket_count; i++)
|
||||||
|
buckets[i] = -1;
|
||||||
|
int idx = 0;
|
||||||
|
/* Reverse insertion so each chain yields ASCENDING types[] order — callers
|
||||||
|
* that used first-match-in-registration-order keep their tie-breaks. */
|
||||||
|
for (int i = reg->type_count - 1; i >= 0; i--) {
|
||||||
|
const CBMRegisteredType *t = ®->types[i];
|
||||||
|
if (!t->short_name)
|
||||||
|
continue;
|
||||||
|
uint64_t h = fnv1a(t->short_name);
|
||||||
|
int slot = (int)(h & (uint64_t)(bucket_count - 1));
|
||||||
|
entries[idx].hash = h;
|
||||||
|
entries[idx].payload_index = i;
|
||||||
|
entries[idx].next_index = buckets[slot];
|
||||||
|
entries[idx].slot = slot;
|
||||||
|
buckets[slot] = idx;
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
reg->type_short_buckets = buckets;
|
||||||
|
reg->type_short_entries = entries;
|
||||||
|
reg->type_short_bucket_count = bucket_count;
|
||||||
|
reg->type_short_entry_count = idx;
|
||||||
|
}
|
||||||
|
|
||||||
static void build_ffunc_short_index(CBMTypeRegistry *reg, CBMArena *idx_arena) {
|
static void build_ffunc_short_index(CBMTypeRegistry *reg, CBMArena *idx_arena) {
|
||||||
int fcount = 0;
|
int fcount = 0;
|
||||||
for (int i = 0; i < reg->func_count; i++) {
|
for (int i = 0; i < reg->func_count; i++) {
|
||||||
@@ -286,6 +326,42 @@ int cbm_free_func_iter_next(CBMFreeFuncIter *it) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cbm_registry_types_by_short_name(const CBMTypeRegistry *reg, const char *short_name,
|
||||||
|
CBMTypeShortIter *out) {
|
||||||
|
out->reg = reg;
|
||||||
|
out->hash = fnv1a(short_name);
|
||||||
|
if (reg->type_qn_buckets && reg->type_qn_bucket_count > 0) {
|
||||||
|
if (reg->type_short_buckets && reg->type_short_bucket_count > 0) {
|
||||||
|
int slot = (int)(out->hash & (uint64_t)(reg->type_short_bucket_count - 1));
|
||||||
|
out->chain_idx = reg->type_short_buckets[slot];
|
||||||
|
} else {
|
||||||
|
out->chain_idx = -1;
|
||||||
|
}
|
||||||
|
out->tail_i = reg->type_qn_entry_count;
|
||||||
|
out->tail_end = reg->type_count;
|
||||||
|
} else {
|
||||||
|
out->chain_idx = -1;
|
||||||
|
out->tail_i = 0;
|
||||||
|
out->tail_end = reg->type_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int cbm_type_short_iter_next(CBMTypeShortIter *it) {
|
||||||
|
const CBMTypeRegistry *reg = it->reg;
|
||||||
|
while (it->chain_idx >= 0) {
|
||||||
|
const CBMRegistryHashEntry *e = ®->type_short_entries[it->chain_idx];
|
||||||
|
int p = e->payload_index;
|
||||||
|
uint64_t h = e->hash;
|
||||||
|
it->chain_idx = e->next_index;
|
||||||
|
if (h != it->hash)
|
||||||
|
continue;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
if (it->tail_i < it->tail_end)
|
||||||
|
return it->tail_i++;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
void cbm_registry_methods(const CBMTypeRegistry *reg, const char *receiver_qn,
|
void cbm_registry_methods(const CBMTypeRegistry *reg, const char *receiver_qn,
|
||||||
const char *method_name, CBMMethodIter *out) {
|
const char *method_name, CBMMethodIter *out) {
|
||||||
memset(out, 0, sizeof(*out));
|
memset(out, 0, sizeof(*out));
|
||||||
@@ -346,6 +422,7 @@ void cbm_registry_finalize_into(CBMTypeRegistry *reg, CBMArena *idx_arena) {
|
|||||||
build_method_index(reg, idx_arena);
|
build_method_index(reg, idx_arena);
|
||||||
build_type_embed_index(reg, idx_arena);
|
build_type_embed_index(reg, idx_arena);
|
||||||
build_ffunc_short_index(reg, idx_arena);
|
build_ffunc_short_index(reg, idx_arena);
|
||||||
|
build_type_short_index(reg, idx_arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cbm_registry_finalize(CBMTypeRegistry *reg) {
|
void cbm_registry_finalize(CBMTypeRegistry *reg) {
|
||||||
|
|||||||
@@ -123,6 +123,10 @@ typedef struct CBMTypeRegistry {
|
|||||||
int type_embed_entry_count;
|
int type_embed_entry_count;
|
||||||
// Free-function short-name index: fnv1a(short_name) -> chain of FREE-function
|
// Free-function short-name index: fnv1a(short_name) -> chain of FREE-function
|
||||||
// (receiver_type==NULL) indices. payload_index = func index.
|
// (receiver_type==NULL) indices. payload_index = func index.
|
||||||
|
int *type_short_buckets;
|
||||||
|
CBMRegistryHashEntry *type_short_entries;
|
||||||
|
int type_short_bucket_count;
|
||||||
|
int type_short_entry_count;
|
||||||
int *ffunc_short_buckets;
|
int *ffunc_short_buckets;
|
||||||
CBMRegistryHashEntry *ffunc_short_entries;
|
CBMRegistryHashEntry *ffunc_short_entries;
|
||||||
int ffunc_short_bucket_count;
|
int ffunc_short_bucket_count;
|
||||||
@@ -248,6 +252,22 @@ typedef struct {
|
|||||||
int tail_i;
|
int tail_i;
|
||||||
int tail_end;
|
int tail_end;
|
||||||
} CBMFreeFuncIter;
|
} CBMFreeFuncIter;
|
||||||
|
/* Iterate TYPE indices sharing a short name — the type-side twin of the free-
|
||||||
|
* function iterator. Built by finalize into type_short_buckets; degrades to a
|
||||||
|
* full types[] scan on an unfinalized registry (same correctness, old cost).
|
||||||
|
* Added for cs_resolve_type_name's step-9 fallback, which scanned type_count
|
||||||
|
* per unresolved name — quadratic against the shared Tier-2 registry. */
|
||||||
|
typedef struct {
|
||||||
|
const CBMTypeRegistry *reg;
|
||||||
|
uint64_t hash;
|
||||||
|
int chain_idx;
|
||||||
|
int tail_i;
|
||||||
|
int tail_end;
|
||||||
|
} CBMTypeShortIter;
|
||||||
|
void cbm_registry_types_by_short_name(const CBMTypeRegistry *reg, const char *short_name,
|
||||||
|
CBMTypeShortIter *out);
|
||||||
|
int cbm_type_short_iter_next(CBMTypeShortIter *it);
|
||||||
|
|
||||||
void cbm_registry_free_funcs_by_short_name(const CBMTypeRegistry *reg, const char *short_name,
|
void cbm_registry_free_funcs_by_short_name(const CBMTypeRegistry *reg, const char *short_name,
|
||||||
CBMFreeFuncIter *out);
|
CBMFreeFuncIter *out);
|
||||||
int cbm_free_func_iter_next(CBMFreeFuncIter *it);
|
int cbm_free_func_iter_next(CBMFreeFuncIter *it);
|
||||||
|
|||||||
@@ -1259,14 +1259,39 @@ static int run_parallel_pipeline(cbm_pipeline_t *p, cbm_pipeline_ctx_t *ctx,
|
|||||||
cbm_arena_init(&cross_lsp_arena);
|
cbm_arena_init(&cross_lsp_arena);
|
||||||
CBMCrossLspRegistries cross_registries = {0};
|
CBMCrossLspRegistries cross_registries = {0};
|
||||||
if (all_defs) {
|
if (all_defs) {
|
||||||
|
/* Per-builder split of lsp_cross_prepare — attributes a slow prepare to
|
||||||
|
* ONE language instead of re-diagnosing the whole pass (the cs builder
|
||||||
|
* hid ~140 s behind the pass total, #1669 follow-up). */
|
||||||
|
struct timespec t_b;
|
||||||
|
long b_ms[6];
|
||||||
|
cbm_clock_gettime(CLOCK_MONOTONIC, &t_b);
|
||||||
cross_registries.go = cbm_go_build_cross_registry(&cross_lsp_arena, all_defs, def_count);
|
cross_registries.go = cbm_go_build_cross_registry(&cross_lsp_arena, all_defs, def_count);
|
||||||
|
b_ms[0] = (long)elapsed_ms(t_b);
|
||||||
|
cbm_clock_gettime(CLOCK_MONOTONIC, &t_b);
|
||||||
cross_registries.python =
|
cross_registries.python =
|
||||||
cbm_py_build_cross_registry(&cross_lsp_arena, all_defs, def_count);
|
cbm_py_build_cross_registry(&cross_lsp_arena, all_defs, def_count);
|
||||||
|
b_ms[1] = (long)elapsed_ms(t_b);
|
||||||
|
cbm_clock_gettime(CLOCK_MONOTONIC, &t_b);
|
||||||
cross_registries.c = cbm_c_build_cross_registry(&cross_lsp_arena, all_defs, def_count);
|
cross_registries.c = cbm_c_build_cross_registry(&cross_lsp_arena, all_defs, def_count);
|
||||||
|
b_ms[2] = (long)elapsed_ms(t_b);
|
||||||
|
cbm_clock_gettime(CLOCK_MONOTONIC, &t_b);
|
||||||
cross_registries.cs = cbm_cs_build_cross_registry(&cross_lsp_arena, all_defs, def_count);
|
cross_registries.cs = cbm_cs_build_cross_registry(&cross_lsp_arena, all_defs, def_count);
|
||||||
|
b_ms[3] = (long)elapsed_ms(t_b);
|
||||||
|
cbm_clock_gettime(CLOCK_MONOTONIC, &t_b);
|
||||||
cross_registries.ts = cbm_ts_build_cross_registry(&cross_lsp_arena, all_defs, def_count);
|
cross_registries.ts = cbm_ts_build_cross_registry(&cross_lsp_arena, all_defs, def_count);
|
||||||
|
b_ms[4] = (long)elapsed_ms(t_b);
|
||||||
|
cbm_clock_gettime(CLOCK_MONOTONIC, &t_b);
|
||||||
cross_registries.java =
|
cross_registries.java =
|
||||||
cbm_java_build_cross_registry(&cross_lsp_arena, all_defs, def_count);
|
cbm_java_build_cross_registry(&cross_lsp_arena, all_defs, def_count);
|
||||||
|
b_ms[5] = (long)elapsed_ms(t_b);
|
||||||
|
char b_buf[6][CBM_SZ_16];
|
||||||
|
const char *b_name[6] = {"go", "python", "c", "cs", "ts", "java"};
|
||||||
|
for (int bi = 0; bi < 6; bi++) {
|
||||||
|
snprintf(b_buf[bi], sizeof(b_buf[bi]), "%ld", b_ms[bi]);
|
||||||
|
}
|
||||||
|
cbm_log_info("lsp_cross_prepare.builders", b_name[0], b_buf[0], b_name[1], b_buf[1],
|
||||||
|
b_name[2], b_buf[2], b_name[3], b_buf[3], b_name[4], b_buf[4], b_name[5],
|
||||||
|
b_buf[5]);
|
||||||
/* Rust: NOT built here. The shared all_defs registry is built LAZILY on the
|
/* Rust: NOT built here. The shared all_defs registry is built LAZILY on the
|
||||||
* first NULL-filter rust file (the amplifier files) inside cbm_parallel_resolve
|
* first NULL-filter rust file (the amplifier files) inside cbm_parallel_resolve
|
||||||
* — repos whose rust files all filter to subsets never pay the build/RSS. */
|
* — repos whose rust files all filter to subsets never pay the build/RSS. */
|
||||||
|
|||||||
Reference in New Issue
Block a user