contrib/memplot: to visualize output of --trace-memory
[nit.git] / contrib / memplot / memplot.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 # Program to transform `memory.log` files produced by `nitc --trace-memory` into a csv file
16 module memplot
17
18 import counter
19 import template
20
21 # An aggregated time-slice
22 class Aggreg
23 # The start time of the slice
24 var time: Float
25
26 # Number of allocations
27 var acpt = new Counter[String]
28
29 # Number of allocated bytes
30 var asiz = new Counter[String]
31
32 # Number of deallocations
33 var dcpt = new Counter[String]
34
35 # Number of deallocated bytes
36 var dsiz = new Counter[String]
37
38 # Total number of allocations since the beginning
39 var cpttot = new Counter[String]
40
41 # Total number of allocated bytes since the beginning
42 var siztot = new Counter[String]
43
44 # Map of all the various counters.
45 var fields = new Map[String, Counter[String]]
46
47 init do
48 fields["acpt"] = acpt
49 fields["asiz"] = asiz
50 fields["dcpt"] = dcpt
51 fields["dsiz"] = dsiz
52 fields["cpttot"] = cpttot
53 fields["siztot"] = siztot
54 end
55 end
56
57 # Main class that does the job
58 class MemProg
59 # The `memory.log` file.
60 var filepath: String
61
62 # The delay of an aggregation
63 var time_slice: Float
64
65 # Total number of events
66 var events = 0
67
68 # List a all time aggregations
69 var aggregs = new Array[Aggreg]
70
71 # Total number of allocations
72 var cpttot = new Counter[String]
73
74 # Total number of allocated bytes
75 var siztot = new Counter[String]
76
77 # Parse the log file `filepath` and fill `aggregs`.
78 fun parse do
79 # Current lines (not yet put in an aggreg)
80 var lines = new Counter[String]
81
82 var time = 0.0
83 var dt = 100.0
84 dt = 100.0
85 for l in "memory.log".to_path.each_line do
86 if l[0] == '#' then
87 var t = l.substring_from(2).to_f
88
89 while t > time + dt do
90 aggreg(lines, time)
91 time += dt
92 end
93 #if time > 1000.0 then break
94 continue
95 end
96 events += 1
97 lines.inc(l)
98 end
99 aggreg(lines, time)
100 end
101
102 # Create and register a new aggregation
103 fun aggreg(lines: Counter[String], t1: Float) do
104 var aggreg = new Aggreg(t1)
105 aggregs.add aggreg
106 print "events:{events} aggregs:{aggregs.length} {t1}ms"
107
108 # Process each distinct line
109 for l, v in lines do
110 var a = l.split('\t')
111 if a.length != 3 then
112 print "Error {a.length}. {l}"
113 continue
114 end
115 var c = a[0]
116 var s = a[1].to_i
117 var e = a[2]
118 if c == "+" then
119 aggreg.acpt[e] += v
120 aggreg.asiz[e] += v * s
121 else if c == "-" then
122 aggreg.dcpt[e] += v
123 aggreg.dsiz[e] += v * s
124 else abort
125 end
126 lines.clear
127
128 # Sum all information
129 for e, v in aggreg.acpt do cpttot[e] += v
130 for e, v in aggreg.asiz do siztot[e] += v
131 for e, v in aggreg.dcpt do cpttot[e] -= v
132 for e, v in aggreg.dsiz do siztot[e] -= v
133
134 # Copy current total
135 aggreg.cpttot.add_all cpttot
136 aggreg.siztot.add_all siztot
137
138 cpttot.print_elements(2)
139 end
140
141 # Generate a *long* CVS file, to use with statistical tools
142 fun tolong: Writable
143 do
144 var res = new Template
145
146 # Write the header
147 res.add "time, class"
148 for f, c in aggregs.first.fields do
149 res.add ", "
150 res.add f
151 end
152 res.add "\n"
153
154 # Collect the largest tags, add add an `other` tag.
155 var elts = siztot.sort.reversed.sub(0,10).reversed
156 elts.add "other"
157
158 for a in aggregs do
159 var t = a.time.to_s
160
161 # For each field compute the value of `other`
162 for f, c in a.fields do
163 var o = c.sum
164 for e in elts do
165 if e == "other" then continue
166 o -= c[e]
167 end
168 c["other"] = o
169 end
170
171 # For each tag (incl. other) produce a line
172 for e in elts do
173 res.add t
174 res.add ", "
175 res.add e
176
177 for f, v in a.fields do
178 res.add ", "
179 res.add v[e].to_s
180 end
181 res.add "\n"
182 end
183 end
184 return res
185 end
186 end
187
188 var m = new MemProg("memory.log", 100.0)
189 m.parse
190
191 m.cpttot.print_summary
192 m.siztot.print_summary
193
194 m.tolong.write_to_file "memory.csv"
195
196 if "memplot.r".file_exists then
197 system("r memplot.r")
198 end