[Agda] Performance issues with --sharing

Peter Selinger selinger at mathstat.dal.ca
Thu Sep 24 18:57:41 CEST 2015


Dear all,

last month, in the thread "type check performance", Wolfram Kahl
suggested that I try the experimental --sharing feature in the
development branch.

The issue at hand was Agda's extremely inefficient evaluation
strategy, which is normal order and not lazy: it recomputes the same
value a potentially unlimited number of times.

I have tested --sharing on various examples, and the results are not
encouraging: I have not been able to find any code examples where
--sharing will actually speed up performance. On the contrary, it
usually slows things down by a factor of 2 or more.

I've created a self-contained example below. In order to compare
different Agda versions without depending on different versions of the
standard library, I have made the example to be completely independent
of the library.

Here are the results:

Using Agda 2.4.2.3:

test 15: ca. 1 second
test 16: ca. 2 seconds
test 17: ca. 4 seconds
test 18: ca. 8 seconds

Using the development version without --sharing (master revision df481626e):

test 15: ca. 1 second
test 16: ca. 2 seconds
test 17: ca. 4 seconds
test 18: ca. 8 seconds

Using the development version with --sharing (master revision df481626e):

test 15: ca. 2 second
test 16: ca. 4 seconds
test 17: ca. 9 seconds
test 18: ca. 19 seconds

As you can see, --sharing does not do anything to fix the exponential
runtime (neither in this example nor in several others that I have
tried). Instead, it slows things down by a constant factor.
(The exponential runtime here is caused by folding a function that
uses the accumulator twice).

I think a proper lazy evaluation strategy will eventually be a
must-have feature, and unfortunately, --sharing does not seem to be
it. Right now I am rewriting many of my programs using forced
strictness and CPS translations, and this makes them efficient, but
unreadable (and non-trivial to prove theorems about).

As mentioned in a previous thread: I am aware that the code becomes
more efficient when I compile it to Haskell. But since all of my code
is used inside proofs, it is really the type checking cost that is
affected. 

-- Peter

----------------------------------------------------------------------
-- Begin Agda Code
----------------------------------------------------------------------

-- Natural numbers
data Nat : Set where
  zero : Nat
  succ : Nat -> Nat

_+_ : Nat -> Nat -> Nat
zero + m = m
succ n + m = succ (n + m)

_-_ : Nat -> Nat -> Nat
zero - m = zero
n - zero = n
succ n - succ m = n - m

{-# BUILTIN NATURAL Nat #-}
{-# BUILTIN NATPLUS _+_ #-}
{-# BUILTIN NATMINUS _-_ #-}

-- Lists
data List (X : Set) : Set where
  nil : List X
  _::_ : X -> List X -> List X

replicate : ∀ {X} -> Nat -> X -> List X
replicate zero x = nil
replicate (succ n) x = x :: replicate n x

foldl : ∀ {A B} -> (A -> B -> A) -> A -> List B -> A
foldl f a nil = a
foldl f a (x :: xs) = foldl f (f a x) xs

-- Test
test : Nat -> Nat
test n = foldl (\a x -> succ ((a + x) - a)) 0 (replicate n 1)


More information about the Agda mailing list