Commit | Line | Data |
---|---|---|
7f918cf1 CE |
1 | MLtonProfile |
2 | ============ | |
3 | ||
4 | [source,sml] | |
5 | ---- | |
6 | signature MLTON_PROFILE = | |
7 | sig | |
8 | structure Data: | |
9 | sig | |
10 | type t | |
11 | ||
12 | val equals: t * t -> bool | |
13 | val free: t -> unit | |
14 | val malloc: unit -> t | |
15 | val write: t * string -> unit | |
16 | end | |
17 | ||
18 | val isOn: bool | |
19 | val withData: Data.t * (unit -> 'a) -> 'a | |
20 | end | |
21 | ---- | |
22 | ||
23 | `MLton.Profile` provides <:Profiling:> control from within the | |
24 | program, allowing you to profile individual portions of your | |
25 | program. With `MLton.Profile`, you can create many units of profiling | |
26 | data (essentially, mappings from functions to counts) during a run of | |
27 | a program, switch between them while the program is running, and | |
28 | output multiple `mlmon.out` files. | |
29 | ||
30 | * `isOn` | |
31 | + | |
32 | a compile-time constant that is false only when compiling `-profile no`. | |
33 | ||
34 | * `type Data.t` | |
35 | + | |
36 | the type of a unit of profiling data. In order to most efficiently | |
37 | execute non-profiled programs, when compiling `-profile no` (the | |
38 | default), `Data.t` is equivalent to `unit ref`. | |
39 | ||
40 | * `Data.equals (x, y)` | |
41 | + | |
42 | returns true if the `x` and `y` are the same unit of profiling data. | |
43 | ||
44 | * `Data.free x` | |
45 | + | |
46 | frees the memory associated with the unit of profiling data `x`. It | |
47 | is an error to free the current unit of profiling data or to free a | |
48 | previously freed unit of profiling data. When compiling | |
49 | `-profile no`, `Data.free x` is a no-op. | |
50 | ||
51 | * `Data.malloc ()` | |
52 | + | |
53 | returns a new unit of profiling data. Each unit of profiling data is | |
54 | allocated from the process address space (but is _not_ in the MLton | |
55 | heap) and consumes memory proportional to the number of source | |
56 | functions. When compiling `-profile no`, `Data.malloc ()` is | |
57 | equivalent to allocating a new `unit ref`. | |
58 | ||
59 | * `write (x, f)` | |
60 | + | |
61 | writes the accumulated ticks in the unit of profiling data `x` to file | |
62 | `f`. It is an error to write a previously freed unit of profiling | |
63 | data. When compiling `-profile no`, `write (x, f)` is a no-op. A | |
64 | profiled program will always write the current unit of profiling data | |
65 | at program exit to a file named `mlmon.out`. | |
66 | ||
67 | * `withData (d, f)` | |
68 | + | |
69 | runs `f` with `d` as the unit of profiling data, and returns the | |
70 | result of `f` after restoring the current unit of profiling data. | |
71 | When compiling `-profile no`, `withData (d, f)` is equivalent to | |
72 | `f ()`. | |
73 | ||
74 | ||
75 | == Example == | |
76 | ||
77 | Here is an example, taken from the `examples/profiling` directory, | |
78 | showing how to profile the executions of the `fib` and `tak` functions | |
79 | separately. Suppose that `fib-tak.sml` contains the following. | |
80 | [source,sml] | |
81 | ---- | |
82 | structure Profile = MLton.Profile | |
83 | ||
84 | val fibData = Profile.Data.malloc () | |
85 | val takData = Profile.Data.malloc () | |
86 | ||
87 | fun wrap (f, d) x = | |
88 | Profile.withData (d, fn () => f x) | |
89 | ||
90 | val rec fib = | |
91 | fn 0 => 0 | |
92 | | 1 => 1 | |
93 | | n => fib (n - 1) + fib (n - 2) | |
94 | val fib = wrap (fib, fibData) | |
95 | ||
96 | fun tak (x,y,z) = | |
97 | if not (y < x) | |
98 | then z | |
99 | else tak (tak (x - 1, y, z), | |
100 | tak (y - 1, z, x), | |
101 | tak (z - 1, x, y)) | |
102 | val tak = wrap (tak, takData) | |
103 | ||
104 | val rec f = | |
105 | fn 0 => () | |
106 | | n => (fib 38; f (n-1)) | |
107 | val _ = f 2 | |
108 | ||
109 | val rec g = | |
110 | fn 0 => () | |
111 | | n => (tak (18,12,6); g (n-1)) | |
112 | val _ = g 500 | |
113 | ||
114 | fun done (data, file) = | |
115 | (Profile.Data.write (data, file) | |
116 | ; Profile.Data.free data) | |
117 | ||
118 | val _ = done (fibData, "mlmon.fib.out") | |
119 | val _ = done (takData, "mlmon.tak.out") | |
120 | ---- | |
121 | ||
122 | Compile and run the program. | |
123 | ---- | |
124 | % mlton -profile time fib-tak.sml | |
125 | % ./fib-tak | |
126 | ---- | |
127 | ||
128 | Separately display the profiling data for `fib` | |
129 | ---- | |
130 | % mlprof fib-tak mlmon.fib.out | |
131 | 5.77 seconds of CPU time (0.00 seconds GC) | |
132 | function cur | |
133 | --------- ----- | |
134 | fib 96.9% | |
135 | <unknown> 3.1% | |
136 | ---- | |
137 | and for `tak` | |
138 | ---- | |
139 | % mlprof fib-tak mlmon.tak.out | |
140 | 0.68 seconds of CPU time (0.00 seconds GC) | |
141 | function cur | |
142 | -------- ------ | |
143 | tak 100.0% | |
144 | ---- | |
145 | ||
146 | Combine the data for `fib` and `tak` by calling `mlprof` | |
147 | with multiple `mlmon.out` files. | |
148 | ---- | |
149 | % mlprof fib-tak mlmon.fib.out mlmon.tak.out mlmon.out | |
150 | 6.45 seconds of CPU time (0.00 seconds GC) | |
151 | function cur | |
152 | --------- ----- | |
153 | fib 86.7% | |
154 | tak 10.5% | |
155 | <unknown> 2.8% | |
156 | ---- |