Skip to content

Commit 28e98dd

Browse files
consolidate timing helpers
1 parent dbeea4d commit 28e98dd

File tree

5 files changed

+64
-76
lines changed

5 files changed

+64
-76
lines changed

lib/unison-prelude/package.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ default-extensions:
5454
- LambdaCase
5555
- MultiParamTypeClasses
5656
- NamedFieldPuns
57+
- NumericUnderscores
5758
- OverloadedLabels
5859
- OverloadedStrings
5960
- PatternSynonyms
Lines changed: 39 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,52 @@
11
module Unison.Util.Timing
22
( time,
3-
unsafeTime,
3+
startTiming,
4+
stopTiming,
45
)
56
where
67

7-
import Data.Time.Clock (picosecondsToDiffTime)
8-
import Data.Time.Clock.System (getSystemTime, systemToTAITime)
9-
import Data.Time.Clock.TAI (diffAbsoluteTime)
8+
import Data.Word (Word64)
9+
import GHC.Clock (getMonotonicTimeNSec)
1010
import System.CPUTime (getCPUTime)
11-
import System.IO.Unsafe (unsafePerformIO)
11+
import Text.Printf (printf)
1212
import Unison.Debug qualified as Debug
1313
import UnliftIO (MonadIO, liftIO)
1414

1515
time :: (MonadIO m) => String -> m a -> m a
16-
time label ma =
16+
time label action =
1717
if Debug.shouldDebug Debug.Timing
1818
then do
19-
systemStart <- liftIO getSystemTime
20-
cpuPicoStart <- liftIO getCPUTime
21-
liftIO $ putStrLn $ "Timing " ++ label ++ "..."
22-
a <- ma
23-
cpuPicoEnd <- liftIO getCPUTime
24-
systemEnd <- liftIO getSystemTime
25-
let systemDiff = diffAbsoluteTime (systemToTAITime systemEnd) (systemToTAITime systemStart)
26-
let cpuDiff = picosecondsToDiffTime (cpuPicoEnd - cpuPicoStart)
27-
liftIO $ putStrLn $ "Finished " ++ label ++ " in " ++ show cpuDiff ++ " (cpu), " ++ show systemDiff ++ " (system)"
28-
pure a
29-
else ma
19+
startTime <- liftIO startTiming
20+
result <- action
21+
liftIO (stopTiming label startTime)
22+
pure result
23+
else action
3024

31-
-- Mitchell says: this function doesn't look like it would work at all; let's just delete it
32-
unsafeTime :: (Monad m) => String -> m a -> m a
33-
unsafeTime label ma =
34-
if Debug.shouldDebug Debug.Timing
35-
then do
36-
let !systemStart = unsafePerformIO getSystemTime
37-
!cpuPicoStart = unsafePerformIO getCPUTime
38-
!_ = unsafePerformIO $ putStrLn $ "Timing " ++ label ++ "..."
39-
a <- ma
40-
let !cpuPicoEnd = unsafePerformIO getCPUTime
41-
!systemEnd = unsafePerformIO getSystemTime
42-
let systemDiff = diffAbsoluteTime (systemToTAITime systemEnd) (systemToTAITime systemStart)
43-
let cpuDiff = picosecondsToDiffTime (cpuPicoEnd - cpuPicoStart)
44-
let !_ = unsafePerformIO $ putStrLn $ "Finished " ++ label ++ " in " ++ show cpuDiff ++ " (cpu), " ++ show systemDiff ++ " (system)"
45-
pure a
46-
else ma
25+
startTiming :: IO (Word64, Integer)
26+
startTiming = (,) <$> getMonotonicTimeNSec <*> getCPUTime
27+
28+
stopTiming :: String -> (Word64, Integer) -> IO ()
29+
stopTiming label (systemTimeStart, cpuTimeStart) = do
30+
(systemTimeEnd, cpuTimeEnd) <- startTiming
31+
let systemDiff = realToFrac @Word64 @Double (systemTimeEnd - systemTimeStart) / 1_000
32+
let cpuDiff = realToFrac @Integer @Double (cpuTimeEnd - cpuTimeStart) / 1_000
33+
printf "%s: %s (cpu), %s (system)\n" label (renderNanos cpuDiff) (renderNanos systemDiff)
34+
where
35+
-- Render nanoseconds, trying to fit into 4 characters.
36+
renderNanos :: Double -> String
37+
renderNanos ns
38+
| ns < 0.5 = "0 ns"
39+
| ns < 995 = printf "%.0f ns" ns
40+
| ns < 9_950 = printf "%.2f µs" us
41+
| ns < 99_500 = printf "%.1f µs" us
42+
| ns < 995_000 = printf "%.0f µs" us
43+
| ns < 9_950_000 = printf "%.2f ms" ms
44+
| ns < 99_500_000 = printf "%.1f ms" ms
45+
| ns < 995_000_000 = printf "%.0f ms" ms
46+
| ns < 9_950_000_000 = printf "%.2f s" s
47+
| ns < 99_500_000_000 = printf "%.1f s" s
48+
| otherwise = printf "%.0f s" s
49+
where
50+
us = ns / 1_000
51+
ms = ns / 1_000_000
52+
s = ns / 1_000_000_000

lib/unison-prelude/unison-prelude.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ library
5050
LambdaCase
5151
MultiParamTypeClasses
5252
NamedFieldPuns
53+
NumericUnderscores
5354
OverloadedLabels
5455
OverloadedStrings
5556
PatternSynonyms

lib/unison-sqlite/src/Unison/Sqlite/Transaction.hs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ module Unison.Sqlite.Transaction
4040

4141
-- * Rows modified
4242
rowsModified,
43+
44+
-- * Debug-timing actions
45+
time,
4346
)
4447
where
4548

@@ -52,13 +55,15 @@ import Data.Unique (Unique, newUnique)
5255
import Database.SQLite.Simple qualified as Sqlite
5356
import Database.SQLite.Simple.FromField qualified as Sqlite
5457
import System.Random qualified as Random
58+
import Unison.Debug qualified as Debug
5559
import Unison.Prelude
5660
import Unison.Sqlite.Connection (Connection (..))
5761
import Unison.Sqlite.Connection qualified as Connection
5862
import Unison.Sqlite.Exception (SqliteExceptionReason, SqliteQueryException, pattern SqliteBusyException)
5963
import Unison.Sqlite.Sql (Sql)
6064
import Unison.Util.Cache (Cache)
6165
import Unison.Util.Cache qualified as Cache
66+
import Unison.Util.Timing qualified as Timing
6267
import UnliftIO.Exception (bracketOnError_, catchAny, trySyncOrAsync, uninterruptibleMask)
6368
import Unsafe.Coerce (unsafeCoerce)
6469

@@ -236,8 +241,8 @@ unsafeGetConnection =
236241

237242
-- | Unwrap the transaction newtype, throwing away the sending of BEGIN/COMMIT + automatic retry.
238243
unsafeUnTransaction :: Transaction a -> Connection -> IO a
239-
unsafeUnTransaction (Transaction action) =
240-
action
244+
unsafeUnTransaction =
245+
coerce
241246

242247
-- Without results
243248

@@ -355,3 +360,16 @@ rowsModified =
355360

356361
transactionRetryDelay :: Int
357362
transactionRetryDelay = 100_000
363+
364+
-- Debug timing
365+
366+
-- | Time a transaction.
367+
time :: String -> Transaction a -> Transaction a
368+
time label action =
369+
if Debug.shouldDebug Debug.Timing
370+
then Transaction \conn -> do
371+
startTime <- Timing.startTiming
372+
result <- unsafeUnTransaction action conn
373+
Timing.stopTiming label startTime
374+
pure result
375+
else action

unison-cli/src/Unison/Cli/Monad.hs

Lines changed: 3 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,8 @@ import Control.Monad.State.Strict qualified as State
6363
import Data.List.NonEmpty qualified as List (NonEmpty)
6464
import Data.List.NonEmpty qualified as List.NonEmpty
6565
import Data.List.NonEmpty qualified as NonEmpty
66-
import Data.Time.Clock (DiffTime, diffTimeToPicoseconds)
67-
import Data.Time.Clock.System (getSystemTime, systemToTAITime)
68-
import Data.Time.Clock.TAI (diffAbsoluteTime)
6966
import Data.Unique (Unique, newUnique)
70-
import System.CPUTime (getCPUTime)
7167
import System.Console.Regions qualified as Console.Regions
72-
import Text.Printf (printf)
7368
import U.Codebase.Sqlite.DbId (ProjectBranchId, ProjectId)
7469
import U.Codebase.Sqlite.Queries qualified as Q
7570
import Unison.Auth.CredentialManager (CredentialManager)
@@ -96,6 +91,7 @@ import Unison.Term (Term)
9691
import Unison.Type (Type)
9792
import Unison.UnisonFile qualified as UF
9893
import Unison.Util.Pretty qualified as Pretty
94+
import Unison.Util.Timing qualified as Timing
9995
import Unsafe.Coerce (unsafeCoerce)
10096

10197
-- | The main command-line app monad.
@@ -340,45 +336,11 @@ time :: String -> Cli a -> Cli a
340336
time label action =
341337
if Debug.shouldDebug Debug.Timing
342338
then Cli \env k s -> do
343-
systemStart <- getSystemTime
344-
cpuPicoStart <- getCPUTime
339+
startTime <- Timing.startTiming
345340
a <- unCli action env (\a loopState -> pure (Success a, loopState)) s
346-
cpuPicoEnd <- getCPUTime
347-
systemEnd <- getSystemTime
348-
let systemDiff =
349-
diffTimeToNanos
350-
(diffAbsoluteTime (systemToTAITime systemEnd) (systemToTAITime systemStart))
351-
let cpuDiff = picosToNanos (cpuPicoEnd - cpuPicoStart)
352-
printf "%s: %s (cpu), %s (system)\n" label (renderNanos cpuDiff) (renderNanos systemDiff)
341+
Timing.stopTiming label startTime
353342
feed k a
354343
else action
355-
where
356-
diffTimeToNanos :: DiffTime -> Double
357-
diffTimeToNanos =
358-
picosToNanos . diffTimeToPicoseconds
359-
360-
picosToNanos :: Integer -> Double
361-
picosToNanos =
362-
(/ 1_000) . realToFrac
363-
364-
-- Render nanoseconds, trying to fit into 4 characters.
365-
renderNanos :: Double -> String
366-
renderNanos ns
367-
| ns < 0.5 = "0 ns"
368-
| ns < 995 = printf "%.0f ns" ns
369-
| ns < 9_950 = printf "%.2f µs" us
370-
| ns < 99_500 = printf "%.1f µs" us
371-
| ns < 995_000 = printf "%.0f µs" us
372-
| ns < 9_950_000 = printf "%.2f ms" ms
373-
| ns < 99_500_000 = printf "%.1f ms" ms
374-
| ns < 995_000_000 = printf "%.0f ms" ms
375-
| ns < 9_950_000_000 = printf "%.2f s" s
376-
| ns < 99_500_000_000 = printf "%.1f s" s
377-
| otherwise = printf "%.0f s" s
378-
where
379-
us = ns / 1_000
380-
ms = ns / 1_000_000
381-
s = ns / 1_000_000_000
382344

383345
getProjectPathIds :: Cli PP.ProjectPathIds
384346
getProjectPathIds = do

0 commit comments

Comments
 (0)