Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Runaway Memory Usage #4

Open
kavon opened this issue Sep 17, 2018 · 0 comments
Open

Runaway Memory Usage #4

kavon opened this issue Sep 17, 2018 · 0 comments
Labels
bug trunk related to the trunk branch

Comments

@kavon
Copy link
Member

kavon commented Sep 17, 2018

The following benchmark program (seq-mazefun) executes pretty quickly in MLton, but after compiling with Manticore it has runaway memory usage. Of course this causes GC thrashing so the program doesn't seem to terminate before hitting the swapfile.

There must be some bug causing some data to stay live according to the GC longer than it should.

(* from the Larceny benchmark suite

;;; MAZEFUN -- Constructs a maze in a purely functional way,
;;; written by Marc Feeley.
;;; ported to SML by Kavon Farvardin

*)

datatype maze_elm
  = Pt of int * int
  | Empty

structure Benchmark = struct

  val hd = List.hd
  val tl = List.tl
  val concat = List.concat
  val length = List.length
  val null = List.null
  val foldr = List.foldr

  fun tup1 (x, _) = x
  fun tup2 (_, x) = x

  (* operations on maze elms *)
  fun fst e = (case e
    of Pt (x, _) => x
     | _ => raise Fail "not a point"
     (* end case *))

  fun snd e = (case e
    of Pt (_, x) => x
     | _ => raise Fail "not a point"
     (* end case *))

  fun mazeElmEqual p = (case p
    of (Pt (x, y), Pt (a, b)) => x = a andalso y = b
     | (Empty, Empty) => true
     | _ => false
     (* end case *))

  fun mazeElmToString p = (case p
    of Pt _ => " _"
     | Empty => " *"
    (* end case *))

  fun printStringMat mat =
    app (fn lst => (app print lst; print "\n")) mat
(***********)

  (* the args to f are flipped,
     i.e. acc is on the left in Scheme *)
  fun foldl f id xs = let
    fun lp (xs, acc) = (case xs
      of nil => acc
       | x :: xs => lp(xs, f (acc, x))
      (* end case *))
    in
      lp (xs, id)
    end

  fun for lo hi f = let
      fun lp lo =
        if lo < hi
          then f lo :: lp (lo + 1)
          else nil
    in
      lp lo
    end

  fun listRead lst i =
    if i = 0
      then hd lst
      else listRead (tl lst) (i-1)

  fun listWrite lst i new =
    if i = 0
      then new :: tl lst
      else hd lst :: listWrite (tl lst) (i-1) new

  fun listRemovePos lst i =
    if i = 0
      then tl lst
      else hd lst :: listRemovePos (tl lst) (i-1)

  fun member x = List.exists (fn y => mazeElmEqual (x, y))

  fun hasDuplicates lst = (case lst
    of nil => false
     | x :: xs => member x xs orelse hasDuplicates xs
    (* end case *))

  fun makeMatrix n m init =
    for 0 n (fn i =>
      for 0 m (fn j =>
        init i j
      )
    )

  fun matrixRead mat i j = listRead (listRead mat i) j

  fun matrixWrite mat i j new =
    listWrite mat i (listWrite (listRead mat i) j new)

  fun matrixSize mat = (length mat, length (hd mat))

  fun matrixMap f mat = map (fn lst => map f lst) mat

  fun nextRandom cur =
    ((cur * 3581) + 12751) mod 131072

  fun shuffle lst = let
    fun shuf lst rand =
      if null lst
        then nil
        else let
          val newRand = nextRandom rand
          val i = newRand mod (length lst)
        in
          listRead lst i
            :: shuf (listRemovePos lst i) newRand
        end
  in
    shuf lst 0 (* <- the seed *)
  end

  fun odd n = n mod 2 = 1
  fun even n = n mod 2 = 0

  fun caveToMaze cave = matrixMap mazeElmToString cave

  fun pierce pos cave = matrixWrite cave (fst pos) (snd pos) pos

  fun neighboringCavities pos cave = let
      val size = matrixSize cave
      val n = tup1 size
      val m = tup2 size
      val i = fst pos
      val j = snd pos

      fun notEmpty (i, j) = (case matrixRead cave i j
        of Empty => false
         | _ => true
         (* end case *))
    in
      concat [
        if i > 0 andalso notEmpty (i-1, j)
          then [Pt (i-1, j)]
          else nil,
        if i < n-1 andalso notEmpty (i+1, j)
          then [Pt (i+1, j)]
          else nil,
        if j > 0 andalso notEmpty (i, j-1)
          then [Pt (i, j-1)]
          else nil,
        if j < m-1 andalso notEmpty (i, j+1)
          then [Pt (i, j+1)]
          else nil
      ]
    end

  and changeCavity cave pos newID = let
      fun change cave pos newID oldID = let
        val i = fst pos
        val j = snd pos
        val cavityID = matrixRead cave i j
      in
        if mazeElmEqual (cavityID, oldID)
          then foldl (fn (c, nc) =>
                        change c nc newID oldID)
                     (matrixWrite cave i j newID)
                     (neighboringCavities pos cave)
          else cave
      end
    in
      change cave pos newID (matrixRead cave (fst pos) (snd pos))
    end

  and tryToPierce pos cave = let
    val ncs = neighboringCavities pos cave
  in
    if hasDuplicates
        (map (fn nc => matrixRead cave (fst nc) (snd nc)) ncs)
      then cave
      else pierce
              pos
              (foldl (fn (c, nc) => changeCavity c nc pos)
                     cave
                     ncs)
  end

  and pierceRandomly possibleHoles cave = (case possibleHoles
    of nil => cave
     | hole :: rest => pierceRandomly rest (tryToPierce hole cave)
    (* end case *))

  fun makeMaze n m = if not (odd n andalso odd m)
    then raise Fail "n and m must be odd"
    else let
      fun init i j = if even i andalso even j
                      then Pt (i, j)
                      else Empty

      val cave = makeMatrix n m init

      val possibleHoles = concat (
            for 0 n (fn i => concat (
              for 0 m (fn j =>
                if even i andalso even j
                  then nil
                  else [Pt (i, j)]
              ))
            ))

    in
      caveToMaze (pierceRandomly (shuffle possibleHoles) cave)
    end


  fun go (n, m) =
    printStringMat (makeMaze n m)

end


structure Main =
  struct

    val iterations = 1

    val n = 11
    val m = 11

    fun main _ = let

      fun doit () = Benchmark.go (n, m)

      fun lp 0 = ()
      	| lp n = (doit(); lp (n-1))

      fun start () = lp iterations

  	in
      	start ()
  	end

end

val _ = Main.main (CommandLine.name (), CommandLine.arguments ())
@kavon kavon added bug trunk related to the trunk branch labels Sep 17, 2018
kavon added a commit that referenced this issue Sep 20, 2018
kavon added a commit that referenced this issue Sep 22, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug trunk related to the trunk branch
Projects
None yet
Development

No branches or pull requests

1 participant