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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
module Debug.Profile
( ProcessInfo(..), getProcessInfos, showMemInfo, printMemInfo
, garbageCollectorOff, garbageCollectorOn, garbageCollect
, profileTime, profileTimeNF, profileSpace, profileSpaceNF
, getTimings, getElapsedTimeNF, getTimingsNF
)
where
import Data.List (intercalate)
data ProcessInfo = RunTime | ElapsedTime | Memory | Code
| Stack | Heap | Choices | GarbageCollections
deriving (Eq,Show)
getProcessInfos :: IO [(ProcessInfo,Int)]
getProcessInfos external
garbageCollectorOff :: IO ()
garbageCollectorOff external
garbageCollectorOn :: IO ()
garbageCollectorOn external
garbageCollect :: IO ()
garbageCollect external
showMemInfo :: [(ProcessInfo,Int)] -> String
showMemInfo infos = intercalate ", " $
formatItem Memory "Memory: " ++
formatItem Code "Code: " ++
formatItem Stack "Stack: " ++
formatItem Choices"Choices: " ++
formatItem Heap "Heap: "
where
formatItem i s = maybe [] (\v -> [s ++ showBytes v]) (lookup i infos)
showBytes b = if b<10000 then show b
else show (b `div` 1000) ++ " kb"
printMemInfo :: IO ()
printMemInfo = getProcessInfos >>= putStrLn . showMemInfo
profileTime :: IO a -> IO a
profileTime action = do
(result,rt,et,gc) <- getTimings action
putStrLn $ "Run time: " ++ show rt ++ " msec."
putStrLn $ "Elapsed time: " ++ show et ++ " msec."
putStrLn $ "Garbage collections: " ++ show gc
return result
getTimings :: IO a -> IO (a,Int,Int,Int)
getTimings action = do
garbageCollect
pi1 <- getProcessInfos
result <- action
pi2 <- getProcessInfos
return (result,
infoDiff pi1 pi2 RunTime,
infoDiff pi1 pi2 ElapsedTime,
infoDiff pi1 pi2 GarbageCollections)
getTimingsNF :: a -> IO (Int,Int,Int)
getTimingsNF exp = do
(_,rt,et,gc) <- getTimings (seq (id $!! exp) (return ()))
return (rt,et,gc)
getElapsedTimeNF :: IO a -> IO (a,Int)
getElapsedTimeNF action = do
garbageCollect
pi1 <- getProcessInfos
value <- action >>= (return $!!)
pi2 <- getProcessInfos
return (value, infoDiff pi1 pi2 ElapsedTime)
profileTimeNF :: a -> IO ()
profileTimeNF exp = profileTime (seq (id $!! exp) (return ()))
profileSpace :: IO a -> IO a
profileSpace action = do
garbageCollect
garbageCollectorOff
pi1 <- getProcessInfos
result <- action
pi2 <- getProcessInfos
garbageCollectorOn
putStrLn $ "Run time: "
++ (showInfoDiff pi1 pi2 RunTime) ++ " msec."
putStrLn $ "Elapsed time: "
++ (showInfoDiff pi1 pi2 ElapsedTime) ++ " msec."
putStrLn $ "Garbage collections: "
++ (showInfoDiff pi1 pi2 GarbageCollections)
putStrLn $ "Heap usage: "
++ (showInfoDiff pi1 pi2 Heap) ++ " bytes"
putStrLn $ "Stack usage: "
++ (showInfoDiff pi1 pi2 Stack) ++ " bytes"
return result
profileSpaceNF :: a -> IO ()
profileSpaceNF exp = profileSpace (seq (id $!! exp) (return ()))
showInfoDiff :: [(ProcessInfo, Int)] -> [(ProcessInfo, Int)] -> ProcessInfo
-> String
showInfoDiff infos1 infos2 item =
show (maybe 0 id (lookup item infos2) - maybe 0 id (lookup item infos1))
infoDiff :: [(ProcessInfo, Int)] -> [(ProcessInfo, Int)] -> ProcessInfo -> Int
infoDiff infos1 infos2 item =
maybe 0 id (lookup item infos2) - maybe 0 id (lookup item infos1)
|