Zulip Chat Archive

Stream: new members

Topic: profiling execution


tzlil (Dec 13 2025 at 12:47):

i have this code

unsafe def main : IO Unit := do
  let n := 5
  let b := @Board.Initial n
  let rec grundy (b : Board n) (ref : IO.Ref (Std.HashMap (Board n) )) : IO  := do
    let hm  ref.get
    match hm[b]? with
    | some r => return r -- already computed this one
    | none => do
      let m  @(legalMoves b).traverse _ _ _ _ sorry _ (grundy · ref)
      let t := @Nat.find (fun n => n  m) _ sorry
      ref.modify (Std.HashMap.alter · b (fun _ => some t))
      return t

  let ref  IO.mkRef (@Std.HashMap.emptyWithCapacity (Board n)  _ _ (2 ^ (n*n)))

  let _  grundy b ref
  let hm  ref.get
  let _  @(legalMoves b).traverse _ _ _ _ sorry _ fun b => do
    IO.println s!"{repr b} has measure {Move.Measure b} and grundy value {hm[b]!}"

which really should not take too long, but it takes almost 100 seconds to run just for 5x5, the mex should only be computed ~33 million times, how do i profile this and figure out whats taking the most time? my best guess is legalMoves which is implemented using Fintype.elems, but maybe im just using iorefs in a bad way or hashmap not linearly or some other way im not aware of, i could only find flags for profiling the elaboration and typechecking and not the runtime of the binary itself

pandaman (Dec 13 2025 at 15:18):

Regular C profilers work well with Lean executables.
I use samply to profile Lean programs for example.


Last updated: Dec 20 2025 at 21:32 UTC