packages feed

hasktorch-0.0.1.0: tests/MemorySpec.hs

{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DataKinds #-}
module MemorySpec (spec) where

import Test.Hspec
import Control.Exception (bracket)
import Control.Monad (forM_)
import Numeric.Dimensions

import Torch.Double.Dynamic as Dynamic

import System.Mem ()

-- |Confirm that memory is deallocated (works)
main :: IO ()
main = hspec spec

spec :: Spec
spec = do
  it "scenario: memoryTestMinimal" memoryTestMinimal

headIdx :: Dims '[0, 0, 0, 0]
headIdx = dims

headIdx' :: SomeDims
headIdx' = SomeDims (dims :: Dims '[0, 0, 0, 0])

iterator :: SomeDims -> Int -> IO ()
iterator = iteratorBracket

-- |Leaks memory
iteratorAssign :: SomeDims -> Int -> IO ()
iteratorAssign d niter = do
  putStrLn $ show (memSizeGB d) ++ " GB per allocation x " ++ show niter
  forM_ [1..niter] $ \iter -> do
    putStr ("Iteration : " ++ show iter ++ " / ")
    let x = (Dynamic.new' d :: DoubleDynamic) `getDim` headIdx
    putStrLn $ "Printing dummy value: " ++ show x
  putStrLn "Done"

-- |Releases memory on OSX (but not consistently on linux)
iteratorMonadic :: SomeDims -> Int -> IO ()
iteratorMonadic d niter = do
  putStrLn $ show (memSizeGB d) ++ " GB per allocation x " ++ show niter
  forM_ [1..niter] $ \iter -> do
    putStr ("Iteration : " ++ show iter ++ " / ")
    let x = (Dynamic.new' d :: DoubleDynamic) `getDim` headIdx
    putStrLn $ "Printing dummy value: " ++ show x
  putStrLn "Done"

-- |Releases memory
iteratorBracket :: SomeDims -> Int -> IO ()
iteratorBracket d niter = do
  putStrLn $ show (memSizeGB d) ++ " GB per allocation x " ++ show niter
  forM_ [1..niter] $ \iter ->
    bracket (pure iter)
    (\iter -> do
       putStr ("Iteration : " ++ show iter ++ " / ")
       let x = (Dynamic.new' d :: DoubleDynamic) `getDim` headIdx
       putStrLn $ "Printing dummy value: " ++ show x
    )
    (const (pure ()))
  putStrLn "Done"

manualAlloc1 :: IO ()
manualAlloc1 = do
  putStrLn   "Allocating"
  let !(t :: DoubleDynamic) = new (dims :: Dims '[200, 200, 200, 200])
  let x = getDim t headIdx
  putStrLn $ "Printing dummy value: " ++ show x

manualAlloc2 :: Double -> IO (DoubleDynamic)
manualAlloc2 v = do
  putStrLn "Allocating"
  let !(t :: DoubleDynamic) = constant (dims :: Dims '[200, 200, 100, 100]) v
  let x = getDim t headIdx
  putStrLn $ "Printing dummy value: " ++ show x
  pure t

pr :: DoubleDynamic -> IO ()
pr t = do
  let v = getDim t headIdx
  putStrLn $ "Printing dummy value: " ++ show v

-- |getDim' size per allocation
memSizeGB :: SomeDims -> Double
memSizeGB (SomeDims d) = (fromIntegral (totalDim d) * 8) / 1000000000.0

memoryTestLarge :: IO ()
memoryTestLarge = iterator (SomeDims (dims :: Dims '[200, 200, 200, 200])) 1000000 -- 12.8 GB x 1M = 12M GB

memoryTestSmall :: IO ()
memoryTestSmall = iterator (SomeDims (dims :: Dims '[100, 100, 100, 7])) 300 -- 50 MB x 300 = 15 GB

memoryTestFast :: IO ()
memoryTestFast = iterator (SomeDims (dims :: Dims '[50, 50, 50, 5])) 10000 -- 5 MB x 1000 = 5 GB

memoryTestMinimal :: IO ()
memoryTestMinimal = iterator (SomeDims (dims :: Dims '[50, 50, 50, 5])) 100 -- 5 MB x 100 = 500 MB