Commit | Line | Data |
---|---|---|
7f918cf1 CE |
1 | (* Copyright (C) 2003-2006, 2008 Henry Cejtin, Matthew Fluet, Suresh |
2 | * Jagannathan, and Stephen Weeks. | |
3 | * | |
4 | * MLton is released under a BSD-style license. | |
5 | * See the file MLton-LICENSE for details. | |
6 | *) | |
7 | ||
8 | structure MLtonProfile: MLTON_PROFILE = | |
9 | struct | |
10 | ||
11 | structure P = Primitive.MLton.Profile | |
12 | ||
13 | val gcState = Primitive.MLton.GCState.gcState | |
14 | ||
15 | val isOn = P.isOn | |
16 | ||
17 | structure Data = | |
18 | struct | |
19 | datatype t = T of {isCurrent: bool ref, | |
20 | isFreed: bool ref, | |
21 | raw: P.Data.t} | |
22 | ||
23 | val all: t list ref = ref [] | |
24 | ||
25 | local | |
26 | fun make f (T r) = f r | |
27 | in | |
28 | val isFreed = make #isFreed | |
29 | val raw = make #raw | |
30 | end | |
31 | ||
32 | fun equals (d, d') = | |
33 | isFreed d = isFreed d' | |
34 | ||
35 | fun free (d as T {isCurrent, isFreed, raw, ...}) = | |
36 | if not isOn | |
37 | then () | |
38 | else | |
39 | if !isFreed | |
40 | then raise Fail "free of freed profile data" | |
41 | else if !isCurrent | |
42 | then raise Fail "free of current profile data" | |
43 | else | |
44 | (all := List.foldl (fn (d', ac) => | |
45 | if equals (d, d') | |
46 | then ac | |
47 | else d' :: ac) [] (!all) | |
48 | ; P.Data.free (gcState, raw) | |
49 | ; isFreed := true) | |
50 | ||
51 | fun make (raw: P.Data.t): t = | |
52 | T {isCurrent = ref false, | |
53 | isFreed = ref false, | |
54 | raw = raw} | |
55 | ||
56 | fun malloc (): t = | |
57 | let | |
58 | val array = | |
59 | if isOn | |
60 | then P.Data.malloc gcState | |
61 | else P.Data.dummy | |
62 | val d = make array | |
63 | val _ = all := d :: !all | |
64 | in | |
65 | d | |
66 | end | |
67 | ||
68 | fun write (T {isFreed, raw, ...}, file) = | |
69 | if not isOn then | |
70 | () | |
71 | else if !isFreed then | |
72 | raise Fail "write of freed profile data" | |
73 | else | |
74 | P.Data.write (gcState, raw, | |
75 | Primitive.NullString8.fromString | |
76 | (String.nullTerm file)) | |
77 | end | |
78 | ||
79 | val r: Data.t ref = ref (Data.make P.Data.dummy) | |
80 | ||
81 | fun current () = !r | |
82 | ||
83 | fun setCurrent (d as Data.T {isCurrent, isFreed, raw, ...}) = | |
84 | if not isOn | |
85 | then () | |
86 | else | |
87 | if !isFreed | |
88 | then raise Fail "setCurrent of freed profile data" | |
89 | else | |
90 | let | |
91 | val Data.T {isCurrent = ic, ...} = current () | |
92 | val _ = ic := false | |
93 | val _ = isCurrent := true | |
94 | val _ = r := d | |
95 | val _ = P.setCurrent (gcState, raw) | |
96 | in | |
97 | () | |
98 | end | |
99 | ||
100 | fun withData (d: Data.t, f: unit -> 'a): 'a = | |
101 | let | |
102 | val old = current () | |
103 | val _ = setCurrent d | |
104 | in | |
105 | DynamicWind.wind (f, fn () => setCurrent old) | |
106 | end | |
107 | ||
108 | fun init () = setCurrent (Data.make (P.getCurrent gcState)) | |
109 | ||
110 | val _ = | |
111 | if not isOn | |
112 | then () | |
113 | else | |
114 | let | |
115 | val _ = | |
116 | Cleaner.addNew | |
117 | (Cleaner.atExit, fn () => | |
118 | (P.done gcState | |
119 | ; Data.write (current (), "mlmon.out") | |
120 | ; List.app (fn d => P.Data.free (gcState, Data.raw d)) | |
121 | (!Data.all))) | |
122 | val _ = | |
123 | Cleaner.addNew | |
124 | (Cleaner.atLoadWorld, fn () => | |
125 | ((* In a new world, all of the old profiling data is invalid. *) | |
126 | Data.all := [] | |
127 | ; init ())) | |
128 | in | |
129 | init () | |
130 | end | |
131 | ||
132 | end |