[Agda] Performance issues and code structure.
Dan Doel
dan.doel at gmail.com
Mon Sep 28 10:38:44 CEST 2009
On Sunday 27 September 2009 8:22:59 am Nils Anders Danielsson wrote:
> On 2009-09-27 05:49, Dan Doel wrote:
> > Loading it up using the command line 'agda' command reveals that it's
> > causing a (haskell) stack overflow.
>
> I run Agda using the following command-line which increases the maximum
> stack size (40M), and introduces a maximum heap size (2G) to avoid
> swapping:
>
> agda +RTS -M2G -K40M -RTS
>
> In Emacs I have set haskell-ghci-program-args to '("+RTS" "-M2G" "-K40M"
> "-RTS").
>
> > Is it the equational reasoning that's so expensive?
>
> Probably not, but maybe it exacerbates the problem. You could try
> replacing all the inferable code with underscores.
>
> The Agda typechecker normalises code before checking equality. If the
> normalised terms are large, then equality checking can be slow. Note
> that records are η-expanded, and that sharing is /not/ preserved by
> Agda's current call-by-name evaluator. Furthermore I believe that
> lambda-lifting is performed before type-checking, which means that a
> module (record) header's telescope is prepended to every definition
> inside the module, thus causing even more equality checking to be
> performed.
Well, in the course of fooling with various things, I managed to make this
code much more efficient. I'm still not entirely sure why this happens,
though. I'll describe it briefly here:
My notion of a product in a category is a record:
record _Product (C : Category) (A B : Cat.Obj C) : Set where
...
field
A×B : Obj
... morphisms and laws
Then, the fact that a category has all binary products is represented by
another record:
record _Has-Products (C : Category) : Set where
...
field
has-product : ∀{A B} → (C Product) A B
infixr 65 _×_
_×_ : Obj → Obj → Obj
A × B = _Product.A×B {C} (has-product {A} {B})
private
module Local {A B : Obj} where
open _Product {C} (has-product {A} {B}) public
...
This is the version that performs acceptably with all the proofs. The version
that was using all my memory and then overflowing the stack omitted those two
{C}s when opening _Product.
The way I discovered this was quite roundabout. Everything looks fine without
the {C}s normally. However, for an unrelated matter, I wanted to see what
having a proof-irrelevant equality would be like. When I enacted that,
_Product turned yellow in those two situations, and I had to fill in {C}. This
in turn allowed the proofs to successfully check. But adding the {C} even
without --proof-irrelevance results in the significantly improved memory/stack
usage.
I suppose the fact that the proofs in question use all of the operations from
the _Product module many times explains why they had such an impact. Still,
it's a bit of a surprise that filling that implicit argument in causes such a
vast difference in performance. I guess without specifying it, the module may
get opened still parameterized by C, and the category record may be getting
eta expanded and re-evaluated dozens of times, since it needs to be passed to
almost every individual term in the proof? I'm a bit confused as to why I get
complaints with Prop equality (and proof irrelevance; I haven't bothered with
a lot of experimentation about which situations exactly cause it to turn
yellow), but not with Set equality, though.
Anyhow, thanks for your help.
-- Dan
More information about the Agda
mailing list