perf(lsp): skip cross-LSP for machine-generated files

Investigation of kubernetes' largest Go files revealed the perf tail
is dominated by machine-generated code:

  pkg/generated/openapi/zz_generated.openapi.go      74,266 lines
  staging/src/k8s.io/api/core/v1/generated.pb.go     71,154 lines
  Multiple *.pb.go protobuf files                    12-14K lines each
  209 files in staging/.../client-go/applyconfigurations/

These files are boilerplate (getters/setters/marshal/unmarshal) with
limited semantic value for code-navigation queries. But because tree-
sitter parse of a 70K-line file alone is ~1-2 seconds, even one
unresolved cross-file call in such a file triggers the full cross-LSP
overhead and dominates the wall time.

Skip cross-LSP for files matching common generated-file conventions:
  *.pb.go            (Go protobuf)
  zz_generated*      (k8s codegen convention)
  *_generated.go     (general Go codegen)
  *.gen.go           (general Go codegen)
  /applyconfigurations/  (k8s codegen subtree)
  *_pb2.py, *_pb2_grpc.py  (Python protobuf)
  *.pb.cc, *.pb.h, *.pb-c.{c,h}  (C/C++ protobuf)

The per-file LSP during extract still indexes their defs and calls
normally — only the cross-file resolution refinement is skipped.
Graph quality: zero loss for hand-written code; for generated code
cross-file method resolution falls back to whatever per-file LSP
captured (which is typically complete for intra-package boilerplate).
This commit is contained in:
Martin Vogel
2026-05-21 11:29:21 +02:00
parent 8ce2228834
commit aecd86135f
+27 -1
View File
@@ -1782,6 +1782,31 @@ static void resolve_worker(int worker_id, void *ctx_ptr) {
}
CBMLanguage lang = rc->files[file_idx].language;
const char *rel = rc->files[file_idx].rel_path;
/* Skip cross-LSP for machine-generated files — they're huge (10k-
* 70k lines for k8s protobuf/openapi), have low semantic value for
* graph navigation (boilerplate getters/setters/marshal), and
* dominate the cross-LSP wall time when they have even one
* unresolved call (tree-sitter parse on a 70k-line file is ~1-2s).
* The per-file LSP during extract still indexes their defs/calls
* normally — only the cross-file resolution refinement is skipped. */
bool is_generated = false;
if (rel) {
is_generated =
(strstr(rel, ".pb.go") != NULL) ||
(strstr(rel, "zz_generated") != NULL) ||
(strstr(rel, "_generated.go") != NULL) ||
(strstr(rel, ".gen.go") != NULL) ||
(strstr(rel, "/applyconfigurations/") != NULL) ||
(strstr(rel, "_pb2.py") != NULL) ||
(strstr(rel, "_pb2_grpc.py") != NULL) ||
(strstr(rel, ".pb.cc") != NULL) ||
(strstr(rel, ".pb.h") != NULL) ||
(strstr(rel, ".pb-c.c") != NULL) ||
(strstr(rel, ".pb-c.h") != NULL);
}
/* Cross-file LSP is a per-file tree-sitter re-parse + AST walk +
* registry lookups — ~50-150ms per file. It can ONLY find calls
* that exist in the AST. If the per-file extract found zero calls,
@@ -1795,7 +1820,8 @@ static void resolve_worker(int worker_id, void *ctx_ptr) {
bool cross_lsp_eligible =
(rc->all_defs && rc->def_count > 0 && cbm_pxc_has_cross_lsp(lang) &&
result->calls.count > 0 &&
result->resolved_calls.count < result->calls.count);
result->resolved_calls.count < result->calls.count &&
!is_generated);
/* Skip files with nothing else to resolve and no cross-LSP work. */
if (result->calls.count == 0 && result->usages.count == 0 && result->throws.count == 0 &&