mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-10 09:13:53 +08:00
perf(lsp): shared Java cross-registry + own-file overlay (#1669)
Cross-file LSP for Java rebuilt a type registry for EVERY file from a def
set the module filter reduces by a constant factor, not to a constant
size: the JVM filter branch includes every def sharing the file's
namespace, so per-file work tracks the corpus (measured defs_per_file
1,292 -> 5,031 in lockstep as defs_total went 179k -> 689k). That makes
the pass O(files x corpus_defs) — 87% of a Java index and the bulk of
the v0.9.0 -> v0.10.x slowdown.
Three changes, one architecture (the pattern Go/Python/C/C#/TS already
use):
1. cbm_java_build_cross_registry — the JVM def universe (Java + Kotlin,
for mixed source roots) built ONCE per run, sealed read-only, shared
across resolve workers. Wired into both pipeline.c and
pipeline_incremental.c.
2. Two-phase registration inside that build: all TYPES first, finalize
(hash buckets exist), then FUNCS. Func registration parses signatures,
and type-name qualification via cbm_registry_lookup_type is a LINEAR
scan until finalize — a single mixed pass measured 0.44 ms/def at
689k defs, a ~300 s sequential build that erased the sharing win.
Two-phase: 306 s -> 2.8 s. Stable partition order because overload
ties resolve to the first registered QN match.
3. cbm_run_java_lsp_cross_with_registry resolves each file against the
shared base through an overlay holding exactly THIS FILE's defs
(register_local_func_or_type_from_file). Own-file scope is the load-
bearing choice: patch_one_method refines signatures from the AST and
must write a private copy (its types live in the per-file arena, the
base is sealed), and any wider scope re-imports the quadratic — a
module/namespace-scoped overlay measured ratio 4.00 on the growing-
package corpus, own-file measures 2.00.
Elasticsearch corpus (46,477 files), same host, CBM_PROFILE=1:
v0.10.5 this change v0.9.0
wall 419.9 s 85.6 s (4.9x) 61.5 s
cross-LSP CPU 6,195,780ms 52,513ms (118x) 110,344 ms
us_per_file 207,448 1,770 3,722
us_per_file_per_kdef 300 2 —
nodes 693,100 693,100 —
edges 5,646,235 5,649,949 —
Cross-LSP CPU now beats v0.9.0. Nodes are identical; edges +0.066%,
consistent with the shared base resolving cross-package targets the old
per-file namespace/import filter could not see, plus source-order
independence from the two-phase build.
Guarded by the complexity suite's shared-package gate (RED at ratio 4.00
on the pre-change tree, 2.00 after — see the suite commit).
Refs #1669.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
This commit is contained in:
@@ -1009,6 +1009,15 @@ _Atomic uint64_t g_pxc_build_files = 0;
|
||||
_Atomic uint64_t g_pxc_filter_files = 0;
|
||||
_Atomic uint64_t g_pxc_filter_failed = 0;
|
||||
|
||||
/* Overlay registrations count as per-file registry work too: the complexity
|
||||
* gate (test_complexity.c) sums ALL defs registered per file, whichever path
|
||||
* built them. Without this the shared-registry languages would report zero and
|
||||
* the linearity gate would pass vacuously. */
|
||||
void cbm_pxc_count_perfile_defs(uint64_t defs) {
|
||||
atomic_fetch_add_explicit(&g_pxc_defs_registered, defs, memory_order_relaxed);
|
||||
atomic_fetch_add_explicit(&g_pxc_build_files, 1, memory_order_relaxed);
|
||||
}
|
||||
|
||||
void cbm_pxc_filter_stats(uint64_t *defs_registered, uint64_t *build_files, uint64_t *filter_files,
|
||||
uint64_t *filter_failed) {
|
||||
if (defs_registered)
|
||||
@@ -1070,6 +1079,14 @@ void cbm_pxc_dispatch_file(CBMLanguage lang, CBMFileResult *result, const char *
|
||||
&result->resolved_calls);
|
||||
used_prebuilt = true;
|
||||
break;
|
||||
case CBM_LANG_JAVA:
|
||||
/* Own-module defs go into a per-file overlay; imports and stdlib
|
||||
* resolve through the shared base (#1669). */
|
||||
cbm_run_java_lsp_cross_with_registry(
|
||||
&result->arena, result, source, source_len, def_module, prebuilt, imp_keys,
|
||||
imp_vals, imp_count, result->cached_tree, &result->resolved_calls);
|
||||
used_prebuilt = true;
|
||||
break;
|
||||
case CBM_LANG_JAVASCRIPT:
|
||||
case CBM_LANG_TYPESCRIPT:
|
||||
case CBM_LANG_TSX: {
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "lsp/c_lsp.h" /* cbm_c_build_cross_registry / cbm_run_c_lsp_cross_with_registry */
|
||||
#include "lsp/cs_lsp.h" /* cbm_cs_build_cross_registry / cbm_run_cs_lsp_cross_with_registry */
|
||||
#include "lsp/ts_lsp.h" /* cbm_ts_build_cross_registry / cbm_run_ts_lsp_cross_with_registry */
|
||||
#include "lsp/java_lsp.h" /* cbm_java_build_cross_registry / cbm_run_java_lsp_cross_with_registry */
|
||||
#include "lsp/rust_lsp.h" /* cbm_rust_build_cross_registry / cbm_run_rust_lsp_cross_with_registry */
|
||||
#include "pipeline/pipeline_internal.h"
|
||||
#include <stdbool.h>
|
||||
@@ -125,6 +126,7 @@ typedef struct {
|
||||
CBMTypeRegistry *ts; /* CBM_LANG_JAVASCRIPT, TYPESCRIPT, TSX */
|
||||
CBMTypeRegistry *php; /* CBM_LANG_PHP */
|
||||
CBMTypeRegistry *cs; /* CBM_LANG_CSHARP */
|
||||
CBMTypeRegistry *java; /* CBM_LANG_JAVA (JVM def universe incl. Kotlin defs) */
|
||||
/* CBM_LANG_RUST: intentionally absent — the shared rust registry is built
|
||||
* LAZILY inside cbm_parallel_resolve (first NULL-filter rust file), not eagerly. */
|
||||
} CBMCrossLspRegistries;
|
||||
@@ -133,6 +135,9 @@ typedef struct {
|
||||
* if none was built (or language has no cross-LSP entrypoint). */
|
||||
/* Per-file registry-build cost (#1669): how many defs the per-file cross-LSP
|
||||
* path actually registered, and how often the module filter failed. */
|
||||
/* Count defs an overlay registered for one file (complexity-gate telemetry). */
|
||||
void cbm_pxc_count_perfile_defs(uint64_t defs);
|
||||
|
||||
void cbm_pxc_filter_stats(uint64_t *defs_registered, uint64_t *build_files, uint64_t *filter_files,
|
||||
uint64_t *filter_failed);
|
||||
|
||||
@@ -157,6 +162,8 @@ static inline CBMTypeRegistry *cbm_pxc_registry_for_lang(const CBMCrossLspRegist
|
||||
return r->php;
|
||||
case CBM_LANG_CSHARP:
|
||||
return r->cs;
|
||||
case CBM_LANG_JAVA:
|
||||
return r->java;
|
||||
default:
|
||||
return NULL; /* incl. CBM_LANG_RUST — its shared registry is built lazily */
|
||||
}
|
||||
|
||||
@@ -1254,7 +1254,7 @@ static int run_parallel_pipeline(cbm_pipeline_t *p, cbm_pipeline_ctx_t *ctx,
|
||||
* Built ONCE here; shared READ-ONLY across all files of that language
|
||||
* during resolve. Per-file work is then: parse + AST walk + O(1) lookups
|
||||
* — no registry build, no Phase 1b mutations. Languages added so far:
|
||||
* Go, Python. Others (C/C++, TS/JS, PHP, C#) fall back to per-file. */
|
||||
* Go, Python, C/C++, C#, TS/JS, Java. Others (Kotlin, PHP) fall back to per-file. */
|
||||
CBMArena cross_lsp_arena;
|
||||
cbm_arena_init(&cross_lsp_arena);
|
||||
CBMCrossLspRegistries cross_registries = {0};
|
||||
@@ -1265,6 +1265,8 @@ static int run_parallel_pipeline(cbm_pipeline_t *p, cbm_pipeline_ctx_t *ctx,
|
||||
cross_registries.c = cbm_c_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);
|
||||
cross_registries.ts = cbm_ts_build_cross_registry(&cross_lsp_arena, all_defs, def_count);
|
||||
cross_registries.java =
|
||||
cbm_java_build_cross_registry(&cross_lsp_arena, all_defs, def_count);
|
||||
/* 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
|
||||
* — repos whose rust files all filter to subsets never pay the build/RSS. */
|
||||
|
||||
@@ -1334,6 +1334,8 @@ static int run_extract_resolve(cbm_pipeline_ctx_t *ctx, cbm_file_info_t *changed
|
||||
cross_registries.c = cbm_c_build_cross_registry(xa, all_defs, all_def_count);
|
||||
cross_registries.cs = cbm_cs_build_cross_registry(xa, all_defs, all_def_count);
|
||||
cross_registries.ts = cbm_ts_build_cross_registry(xa, all_defs, all_def_count);
|
||||
cross_registries.java =
|
||||
cbm_java_build_cross_registry(xa, all_defs, all_def_count);
|
||||
registries_arg = &cross_registries;
|
||||
}
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user