Skip to content

Commit 888871e

Browse files
Merge pull request #103 from chrisdone/cd/2025-10-10-add-stats
Add --compiler-stats option
2 parents 7d295ee + 84e2684 commit 888871e

3 files changed

Lines changed: 43 additions & 16 deletions

File tree

hell.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ executable hell
2626
, bytestring
2727
, constraints
2828
, containers
29+
, criterion-measurement
2930
, directory
3031
, ghc-prim
3132
, haskell-src-exts

package.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ dependencies:
1212
- text
1313
- bytestring
1414
- async
15+
- criterion-measurement
1516
- mtl
1617
- directory
1718
- syb

src/Hell.hs

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
{-# LANGUAGE BangPatterns #-}
12
{-# LANGUAGE AllowAmbiguousTypes #-}
23
{-# LANGUAGE BlockArguments #-}
34
{-# LANGUAGE CPP #-}
@@ -41,13 +42,15 @@
4142

4243
module Main (main) where
4344

45+
#if __GLASGOW_HASKELL__ >= 906
46+
import Control.Monad
47+
#endif
48+
4449
-- All modules tend to be imported qualified by their last component,
4550
-- e.g. 'Data.Graph' becomes 'Graph', and are then exposed to the Hell
4651
-- guest language as such.
4752

48-
#if __GLASGOW_HASKELL__ >= 906
49-
import Control.Monad
50-
#endif
53+
import Criterion.Measurement
5154
import Control.Applicative (Alternative (..), optional)
5255
import qualified Control.Concurrent as Concurrent
5356
import Control.Exception (evaluate)
@@ -125,12 +128,15 @@ import qualified UnliftIO.Async as Async
125128
-- | Commands available.
126129
data Command
127130
= Run FilePath
128-
| Check FilePath
131+
| Check FilePath StatsEnabled
129132
| Version
130133

134+
data StatsEnabled = NoStats | PrintStats
135+
131136
-- | Main entry point.
132137
main :: IO ()
133138
main = do
139+
initializeTime
134140
args <- getArgs
135141
case args of
136142
(x : ys)
@@ -150,7 +156,8 @@ commandParser :: Options.Parser Command
150156
commandParser =
151157
Options.asum
152158
[ Run <$> Options.strArgument (Options.metavar "FILE" <> Options.help "Run the given .hell file"),
153-
Check <$> Options.strOption (Options.long "check" <> Options.metavar "FILE" <> Options.help "Typecheck the given .hell file"),
159+
Check <$> Options.strOption (Options.long "check" <> Options.metavar "FILE" <> Options.help "Typecheck the given .hell file") <*>
160+
Options.flag NoStats PrintStats (Options.long "compiler-stats" <> Options.internal),
154161
Version <$ Options.flag () () (Options.long "version" <> Options.help "Print the version")
155162
]
156163

@@ -162,37 +169,48 @@ hellVersion = "2025-06-09"
162169
dispatch :: Command -> IO ()
163170
dispatch Version = Text.putStrLn hellVersion
164171
dispatch (Run filePath) = do
165-
action <- compileFile filePath
172+
action <- compileFile NoStats filePath
166173
eval () action
167-
dispatch (Check filePath) = do
168-
compileFile filePath >>= void . evaluate
174+
dispatch (Check filePath stats) = do
175+
compileFile stats filePath >>= void . evaluate
169176

170177
--------------------------------------------------------------------------------
171178
-- Compiler
172179

173180
-- | Parses the file with HSE, desugars it, infers it, checks it,
174181
-- returns it. Or throws an error.
175-
compileFile :: FilePath -> IO (Term () (IO ()))
176-
compileFile filePath = do
177-
result <- parseFile filePath
182+
compileFile :: StatsEnabled -> FilePath -> IO (Term () (IO ()))
183+
compileFile stats filePath = do
184+
t0 <- getTime
185+
!result <- parseFile filePath
186+
t1 <- getTime
187+
emitStat stats "parse" (t1-t0)
178188
case result of
179189
Left e -> error $ e
180190
Right File {terms, types}
181191
| anyCycles terms -> error "Cyclic bindings are not supported!"
182192
| anyCycles types -> error "Cyclic types are not supported!"
183-
| otherwise ->
193+
| otherwise -> do
194+
t2 <- getTime
195+
emitStat stats "cycle_detect" (t2-t1)
184196
case desugarAll types terms of
185197
Left err -> error $ prettyString err
186-
Right dterms ->
198+
Right !dterms -> do
199+
t3 <- getTime
200+
emitStat stats "desugar" (t3-t2)
187201
case lookup "main" dterms of
188202
Nothing -> error "No main declaration!"
189203
Just main' ->
190204
case inferExp mempty main' of
191205
Left err -> error $ prettyString err
192-
Right uterm ->
206+
Right uterm -> do
207+
t4 <- getTime
208+
emitStat stats "infer" (t4-t3)
193209
case check uterm Nil of
194210
Left err -> error $ prettyString err
195-
Right (Typed t ex) ->
211+
Right (Typed t ex) -> do
212+
t5 <- getTime
213+
emitStat stats "check" (t5-t4)
196214
case Type.eqTypeRep (typeRepKind t) (typeRep @Type) of
197215
Nothing -> error $ "Kind error, that's nowhere near an IO ()!"
198216
Just Type.HRefl ->
@@ -201,6 +219,11 @@ compileFile filePath = do
201219
pure ex
202220
Nothing -> error $ "Type isn't IO (), but: " ++ show t
203221

222+
emitStat :: StatsEnabled -> Text -> Double -> IO ()
223+
emitStat NoStats _ _ = pure ()
224+
emitStat PrintStats label s =
225+
t_putStrLn $ "stat: " <> label <> " = " <> Text.pack (secs s)
226+
204227
--------------------------------------------------------------------------------
205228
-- Get declarations from the module
206229

@@ -830,7 +853,9 @@ instances =
830853
instance1 @Monoid @Vector,
831854
instance2 @Monoid @Options.Mod,
832855
instance1 @Monoid @[],
833-
instance2 @Semigroup @Options.Mod
856+
instance2 @Semigroup @Options.Mod,
857+
instance0 @Semigroup @Text,
858+
instance1 @Semigroup @Vector
834859
]
835860

836861
--------------------------------------------------------------------------------

0 commit comments

Comments
 (0)