summaryrefslogtreecommitdiff
path: root/test/bench.hs
blob: e610e84973148d318218da66f9a3a28904da3085 (plain)
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
{-# LANGUAGE CPP                      #-}
{-# LANGUAGE ForeignFunctionInterface #-}
import qualified Data.Attoparsec.Text       as Atto
import qualified Data.ByteString.Char8      as S
import qualified Data.ByteString.Lazy.Char8 as L
import Data.List as List
import Data.Either
import Data.ByteString.Unsafe
import Data.Text
import Data.Text.Encoding
import Data.Word
import Foreign.Ptr
import System.IO.Unsafe
import qualified Data.Vector as V
import Control.Monad.State ( State, execState, gets, modify )
import qualified Data.IntMap as IntMap

import Codec.Wavefront.Lexer ( lexer )
import Codec.Wavefront.Object ( WavefrontOBJ, ctxtToWavefrontOBJ, objLocations )
import Codec.Wavefront.Token ( tokenize )

import qualified Graphics.WaveFront.Parse as Parse
import qualified Graphics.WaveFront.Parse.Common as Parse

import Wavefront.Lex
import qualified Data.Wavefront as C
import Wavefront as C

import Criterion.Main
#ifdef WEIGH
import Weigh -- WARNING: weigh is incompatible with profiling. It reports much more allocations with profiling turned on.
#endif

foreign import ccall "&cube_obj" cube_ptr :: Ptr Word8
cube_obj_len :: Int
cube_obj_len = 840

cube_obj :: L.ByteString
cube_obj = L.fromChunks . pure . unsafePerformIO $ do
    unsafePackCStringFinalizer cube_ptr cube_obj_len (return ())
{-# NOINLINE cube_obj #-}

cube_objT :: Text
cube_objT = decodeUtf8 $ L.toStrict cube_obj
{-# NOINLINE cube_objT #-}

countVerticesSabadie :: Text -> Int
countVerticesSabadie ts = V.length vs
 where
    obj = sabadie ts
    vs = either (const V.empty) objLocations obj

countVerticesSundqvist :: Text -> Int
countVerticesSundqvist ts = List.length vs
 where
    obj = sundqvist ts
    vs = either (const []) (List.filter isOBJVertex) obj
    isOBJVertex (Parse.OBJVertex {}) = True
    isOBJVertex _                    = False

countVerticesCrayne :: L.ByteString -> Int
countVerticesCrayne bs = execState (parseOBJ builder (ObjConfig IntMap.empty) bs) 0
 where
    builder = nullBuilder
        { vertex = \_ -> modify succ
        }

countVerticesCrayneFull :: L.ByteString -> Int
countVerticesCrayneFull ts = V.length vs
 where
    obj = C.parse ts
    vs = C.objLocations obj


sabadie :: Text -> Either String WavefrontOBJ
sabadie = fmap (ctxtToWavefrontOBJ . lexer) . tokenize

sundqvist :: Text -> Either String (Parse.OBJ Double Text Integer [])
sundqvist = Atto.parseOnly (Parse.wholeFile Parse.obj)

main :: IO ()
main = do
    print $ countVerticesSabadie cube_objT
    print $ countVerticesSundqvist cube_objT
    print $ countVerticesCrayne cube_obj
    putStrLn $ "---- Benchmarking"
    defaultMain [
          bgroup "count vertices"
                [ bench "crayne" $ whnf countVerticesCrayne cube_obj
                , bench "crayneFull" $ whnf countVerticesCrayneFull cube_obj
                , bench "sabadie"   $ whnf countVerticesSabadie   cube_objT
                , bench "sundqvist" $ whnf countVerticesSundqvist cube_objT
                ]
          ]
#ifdef WEIGH
    Weigh.mainWith $ do
        func "crayne" countVerticesCrayne cube_obj
        func "crayneFull" countVerticesCrayneFull cube_obj
        func "sabadie" countVerticesSabadie cube_objT
        func "sundqvist" countVerticesSundqvist cube_objT
#endif
    return ()