This PR roughly halves the time needed to load the .ilean files by optimizing the JSON parser and the conversion from JSON to Lean data structures. The code is optimized roughly as follows: - String operations are inlined more aggressively - Parsers are changed to use new `String.Iterator` functions `curr'` and `next'` that receive a proof and hence do not need to perform an additional check - The `RefIdent` of .ilean files now uses a `String` instead of a `Name` to avoid the expensive parse step from `String` to `Name` (despite the fact that we only very rarely actually need a `Name` in downstream code) - Instead of `List`s and `Subarray`s, the JSON to Lean conversion now directly passes around arrays and array indices to avoid redundant boxing - Parsec's `peek?` sometimes generates redundant `Option` wrappers because the generation of basic blocks interferes with the ctor-match optimization, so it is changed to use an `isEof` check where possible - Early returns and inline-do-blocks cause the code generator to generate new functions, which then interfere with optimizations, so they are now avoided - Mutual defs are used instead of unspecialized passing of higher-order functions to generate faster code - The object parser is made tail-recursive This PR also fixes a stack overflow in `Lean.Json.compress` that would occur with long lists and adds a benchmark for the .ilean roundtrip (compressed pretty-printing -> parsing).
54 lines
1.7 KiB
Text
54 lines
1.7 KiB
Text
import Lean.Data.Lsp
|
|
|
|
def genModuleRefs (n : Nat) : IO Lean.Lsp.ModuleRefs := do
|
|
let someLoc : Lean.Lsp.RefInfo.Location := {
|
|
range := ⟨⟨333, 444⟩, ⟨444, 555⟩⟩
|
|
parentDecl? := some {
|
|
name := "A.Reasonably.Long.ParentDecl.Name.barfoo",
|
|
range := ⟨⟨1111, 2222⟩, ⟨3333, 4444⟩⟩
|
|
selectionRange := ⟨⟨5555, 6666⟩, ⟨7777, 8888⟩⟩
|
|
}
|
|
}
|
|
|
|
let mut someUsages : Array Lean.Lsp.RefInfo.Location := #[]
|
|
for _ in [0, 200] do
|
|
someUsages := someUsages.push someLoc
|
|
|
|
let someInfo : Lean.Lsp.RefInfo := {
|
|
definition? := someLoc
|
|
usages := someUsages
|
|
}
|
|
|
|
let mut refs : Lean.Lsp.ModuleRefs := .empty
|
|
for i in [0:n] do
|
|
let someIdent := Lean.Lsp.RefIdent.const s!"A.Reasonably.Long.Module.Name{i}" s!"A.Reasonably.Long.Declaration.Name.foobar{i}"
|
|
refs := refs.insert someIdent someInfo
|
|
|
|
return refs
|
|
|
|
@[noinline]
|
|
def compress (refs : Lean.Lsp.ModuleRefs) : IO String := do
|
|
return Lean.Json.compress (Lean.ToJson.toJson refs)
|
|
|
|
@[noinline]
|
|
def parse (s : String) : IO (Except String Lean.Json) := do
|
|
return Lean.Json.parse s
|
|
|
|
def main (args : List String) : IO Unit := do
|
|
let n := (args.get! 0).toNat!
|
|
let refs ← genModuleRefs n
|
|
let compressStartTime ← IO.monoMsNow
|
|
let s ← compress refs
|
|
let compressEndTime ← IO.monoMsNow
|
|
let compressTime : Float := (compressEndTime - compressStartTime).toFloat / 1000.0
|
|
IO.println s!"compress: {compressTime}"
|
|
let parseStartTime ← IO.monoMsNow
|
|
let r ← parse s
|
|
let parseEndTime ← IO.monoMsNow
|
|
let parseTime : Float := (parseEndTime - parseStartTime).toFloat / 1000.0
|
|
match r with
|
|
| .ok _ =>
|
|
IO.println s!"parse: {parseTime}"
|
|
| .error _ =>
|
|
IO.println s!"parse: {parseTime}"
|
|
IO.println "error"
|