Merge: curl: basic Unix domain socket support
[nit.git] / lib / performance_analysis.nit
1 # This file is part of NIT (http://www.nitlanguage.org).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Services to gather information on the performance of events by categories
16 #
17 # Provides `PerfMap` to manage all the categories and
18 # `PerfEntry` for per-category statistics.
19 #
20 # ~~~
21 # for i in 100.times do
22 # var clock = new Clock
23 #
24 # # Do some "work" here
25 # nanosleep(0, 1000000)
26 #
27 # # Register the perf
28 # sys.perfs["sleep 1ms"].add clock.lapse
29 #
30 # # Do some other "work" here
31 # nanosleep(0, 5000000)
32 #
33 # # Register the perf
34 # sys.perfs["sleep 5ms"].add clock.lapse
35 # end
36 #
37 # assert sys.perfs["sleep 1ms"].count == 100
38 # assert sys.perfs["sleep 1ms"].avg.is_approx(0.001, 0.001)
39 # assert sys.perfs["sleep 5ms"].avg.is_approx(0.005, 0.005)
40 # ~~~
41 module performance_analysis
42
43 import realtime
44
45 redef class Sys
46 # Main `PerfMap` available by default
47 var perfs = new PerfMap
48 end
49
50 # Collection of statistics on many events
51 class PerfMap
52 super HashMap[String, PerfEntry]
53
54 redef fun provide_default_value(key)
55 do
56 if not key isa String then return super
57
58 var ts = new PerfEntry(key)
59 self[key] = ts
60 return ts
61 end
62
63 # Number of digits to the right of the decimal points in reports created by `to_s`
64 #
65 # Defaults to 4.
66 var precision = 4 is writable
67
68 redef fun to_s
69 do
70 var prec = precision
71
72 var table = new Map[String, Array[String]]
73 for event, stats in self do
74 table[event] = [event,
75 stats.min.to_precision(prec),
76 stats.max.to_precision(prec),
77 stats.avg.to_precision(prec),
78 stats.sum.to_precision(prec),
79 stats.count.to_s]
80 end
81
82 var widths = [0] * 6
83 for event, row in table do
84 for i in row.length.times do
85 widths[i] = widths[i].max(row[i].length)
86 end
87 end
88
89 var s = "# {"Event".justify(widths[0], 0.0)} {"min".justify(widths[1], 0.5)} {"max".justify(widths[2], 0.5)} {"avg".justify(widths[3], 0.5)} {"sum".justify(widths[4], 0.5)} {"count".justify(widths[5], 0.5)}\n"
90
91 var sorted_events = table.keys.to_a
92 alpha_comparator.sort sorted_events
93 for event in sorted_events do
94 var row = table[event]
95 s += "*"
96 for c in row.length.times do
97 var cell = row[c]
98 s += " "
99 if c == 0 then
100 s += cell.justify(widths[c], 0.0, '.')
101 else s += cell.justify(widths[c], 1.0)
102 end
103 s += "\n"
104 end
105 return s
106 end
107 end
108
109 # Statistics on wall clock execution time of a category of events by `name`
110 class PerfEntry
111
112 # Name of the category
113 var name: String
114
115 # Shortest execution time of registered events
116 var min = 0.0
117
118 # Longest execution time of registered events
119 var max = 0.0
120
121 # Average execution time of registered events
122 var avg = 0.0
123
124 # Number of registered events
125 var count = 0
126
127 # Total execution time of this event
128 var sum = 0.0
129
130 # Register a new event execution time in seconds
131 fun add(time: Float)
132 do
133 if time.to_f < min.to_f or count == 0 then min = time
134 if time.to_f > max.to_f then max = time
135
136 sum += time
137 count += 1
138 avg = sum / count.to_f
139 end
140
141 redef fun to_s do return "min {min}, max {max}, avg {avg}, sum {sum}, count {count}"
142 end