Skip to content

Commit 0f45d8d

Browse files
committed
Parallelize ExCk return-type lookups in prewarm, hoist beam setup out of loop
Previously prewarmStructFieldsFromText made sequential ReturnTypeStruct calls (2s timeout each) in a loop, also calling getBeamProcess+Ready for every iteration. On files with many var=Mod.func() patterns, these sequential calls could hold the BEAM process for extended periods while a completion-triggered ReturnTypeStruct call waited behind them. Changes: - Fire all ExCk ReturnTypeStruct calls in parallel goroutines so they complete as fast as the BEAM can process them, minimizing the window where the prewarm contends with completion requests. - Hoist getBeamProcess + Ready out of the loop — same BEAM process for all calls, no need to look it up and check readiness per call. - All ExCk calls share a single 2s context timeout instead of each getting its own, preventing runaway goroutines.
1 parent feb344e commit 0f45d8d

1 file changed

Lines changed: 38 additions & 31 deletions

File tree

internal/lsp/server.go

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,7 +1515,7 @@ func (s *Server) prewarmStructFieldsFromText(_ string, filePath, text string) {
15151515
tf := NewTokenizedFile(text)
15161516

15171517
seen := make(map[string]bool)
1518-
warmed := 0
1518+
var warmed int
15191519

15201520
// Pre-warm from struct literal references (%Module{}).
15211521
refs := tf.StructModuleRefs()
@@ -1535,39 +1535,46 @@ func (s *Server) prewarmStructFieldsFromText(_ string, filePath, text string) {
15351535
// Pre-warm from function call return types via ExCk.
15361536
// Scan the entire file for var = Module.func(...) patterns.
15371537
calls := tf.AllVariableFunctionCalls()
1538-
for _, call := range calls {
1539-
aliases := tf.ExtractAliasesInScope(call.Line)
1540-
s.mergeAliasesFromUseTokenized(tf, aliases)
1541-
resolvedModule := tf.ResolveModuleExpr(call.Module, call.Line)
1542-
fullCallModule := s.resolveModuleWithNesting(resolvedModule, aliases, filePath, call.Line)
1543-
if fullCallModule == "" {
1544-
continue
1545-
}
1546-
1538+
if len(calls) > 0 {
15471539
buildRoot := s.structFieldBuildRoot(filePath)
1548-
if buildRoot == "" {
1549-
continue
1550-
}
1551-
1552-
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
1553-
bp := s.getBeamProcess(ctx, buildRoot)
1554-
if bp == nil {
1555-
cancel()
1556-
continue
1557-
}
1558-
if err := bp.Ready(ctx); err != nil {
1540+
if buildRoot != "" {
1541+
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
1542+
bp := s.getBeamProcess(ctx, buildRoot)
1543+
if bp != nil && bp.Ready(ctx) == nil {
1544+
type excResult struct {
1545+
structModule string
1546+
}
1547+
results := make([]excResult, len(calls))
1548+
var wg sync.WaitGroup
1549+
for i, call := range calls {
1550+
aliases := tf.ExtractAliasesInScope(call.Line)
1551+
s.mergeAliasesFromUseTokenized(tf, aliases)
1552+
resolvedModule := tf.ResolveModuleExpr(call.Module, call.Line)
1553+
fullCallModule := s.resolveModuleWithNesting(resolvedModule, aliases, filePath, call.Line)
1554+
if fullCallModule == "" {
1555+
continue
1556+
}
1557+
wg.Add(1)
1558+
go func(idx int, mod, fn string, arity int) {
1559+
defer wg.Done()
1560+
structModule, err := bp.ReturnTypeStruct(ctx, mod, fn, arity)
1561+
if err == nil && structModule != "" {
1562+
results[idx] = excResult{structModule: structModule}
1563+
}
1564+
}(i, fullCallModule, call.Function, call.Arity)
1565+
}
1566+
wg.Wait()
1567+
for _, res := range results {
1568+
if res.structModule == "" || seen[res.structModule] {
1569+
continue
1570+
}
1571+
seen[res.structModule] = true
1572+
s.prewarmStructFields(filePath, res.structModule)
1573+
warmed++
1574+
}
1575+
}
15591576
cancel()
1560-
continue
1561-
}
1562-
1563-
structModule, err := bp.ReturnTypeStruct(ctx, fullCallModule, call.Function, call.Arity)
1564-
cancel()
1565-
if err != nil || structModule == "" || seen[structModule] {
1566-
continue
15671577
}
1568-
seen[structModule] = true
1569-
s.prewarmStructFields(filePath, structModule)
1570-
warmed++
15711578
}
15721579

15731580
if s.debug && warmed > 0 {

0 commit comments

Comments
 (0)