-
Notifications
You must be signed in to change notification settings - Fork 307
/
CountHeartbeats.lean
62 lines (52 loc) · 2.25 KB
/
CountHeartbeats.lean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
/-
Copyright (c) 2023 Scott Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Scott Morrison
-/
import Lean.Util.Heartbeats
import Lean.Meta.Tactic.TryThis
/-!
Defines a command wrapper that prints the number of heartbeats used in the enclosed command.
For example
```
count_heartbeats in
theorem foo : 42 = 6 * 7 := rfl
```
will produce an info message containing a number around 51.
If this number is above the current `maxHeartbeats`, we also print a `Try this:` suggestion.
-/
open Lean Elab Command Meta
namespace Mathlib.CountHeartbeats
/--
Count the heartbeats used in the enclosed command.
This is most useful for setting sufficient but reasonable limits via `set_option maxHeartbeats`
for long running declarations.
If you do so, please resist the temptation to set the limit as low as possible.
As the `simp` set and other features of the library evolve,
other contributors will find that their (likely unrelated) changes
have pushed the declaration over the limit.
`count_heartbearts in` will automatically suggest a `set_option maxHeartbeats` via "Try this:"
using the least number of the form `2^k * 200000` that suffices.
Note that that internal heartbeat counter accessible via `IO.getNumHeartbeats`
has granularity 1000 times finer that the limits set by `set_option maxHeartbeats`.
As this is intended as a user command, we divide by 1000.
-/
elab "count_heartbeats " "in" ppLine cmd:command : command => do
let start ← IO.getNumHeartbeats
try
elabCommand (← `(command| set_option maxHeartbeats 0 in $cmd))
finally
let finish ← IO.getNumHeartbeats
let elapsed := (finish - start) / 1000
let max := (← Command.liftCoreM getMaxHeartbeats) / 1000
if elapsed < max then
logInfo m!"Used {elapsed} heartbeats, which is less than the current maximum of {max}."
else
let mut max' := max
while max' < elapsed do
max' := 2 * max'
logInfo m!"Used {elapsed} heartbeats, which is greater than the current maximum of {max}."
let m : TSyntax `num := quote max'
Command.liftCoreM <| MetaM.run' do
Lean.Meta.Tactic.TryThis.addSuggestion (← getRef)
(← set_option hygiene false in `(command| set_option maxHeartbeats $m in $cmd))