blob: b1bc3df000c69d42378bbd407deb2c297e91f20f [file] [log] [blame]
Elliott Hughesed398002017-06-21 14:41:24 -07001
2/*--------------------------------------------------------------------*/
3/*--- Support functions for xtree memory reports. m_xtmemory.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
9
10 Copyright (C) 2016-2017 Philippe Waroquiers
11
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation; either version 2 of the
15 License, or (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful, but
18 WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
25 02111-1307, USA.
26
27 The GNU General Public License is contained in the file COPYING.
28*/
29
30#include "pub_core_libcassert.h"
31#include "pub_core_libcbase.h"
32#include "pub_core_libcprint.h"
33#include "pub_core_libcproc.h"
34#include "pub_core_mallocfree.h"
35#include "pub_core_options.h"
36#include "pub_core_xarray.h"
37#include "pub_core_xtree.h"
38#include "pub_core_xtmemory.h" /* self */
39
40static void VG_(XT_Allocs_init)(void* xt_allocs)
41{
42 VG_(memset) (xt_allocs, 0, sizeof(XT_Allocs));
43}
44static void VG_(XT_Allocs_add) (void* to, const void* xt_allocs)
45{
46 XT_Allocs* xto = to;
47 const XT_Allocs* xta = xt_allocs;
48
49 xto->nbytes += xta->nbytes;
50 xto->nblocks += xta->nblocks;
51}
52static void VG_(XT_Allocs_sub) (void* from, const void* xt_allocs)
53{
54 XT_Allocs* xfrom = from;
55 const XT_Allocs* xta = xt_allocs;
56
57 xfrom->nbytes -= xta->nbytes;
58 xfrom->nblocks -= xta->nblocks;
59}
60static const HChar* VG_(XT_Allocs_img) (const void* xt_allocs)
61{
62 static HChar buf[100];
63
64 const XT_Allocs* xta = xt_allocs;
65
66 if (xta->nbytes > 0 || xta->nblocks > 0) {
67 VG_(sprintf) (buf, "%lu %lu",
68 xta->nbytes, xta->nblocks);
69 return buf;
70 } else {
71 return NULL;
72 }
73}
74const HChar* XT_Allocs_events = "curB : currently allocated Bytes" ","
75 "curBk : currently allocated Blocks";
76
77/* Type and functions for full xtree memory profiling. */
78static XTree* full_xt;
79typedef
80 struct _XT_Full {
81 // Current nr of bytes/blocks allocated by this ec
82 SizeT cur_alloc_nbytes;
83 SizeT cur_alloc_nblocks;
84
85 // Total/cumulative nr of bytes/blocks allocated by this ec
86 ULong tot_alloc_nbytes;
87 ULong tot_alloc_nblocks;
88
89 // Total/cumulative nr of bytes/blocks freed by this ec
90 ULong tot_freed_nbytes;
91 ULong tot_freed_nblocks;
92 } XT_Full;
93/* Note: normally, an ec should never be used as both an alloc_ec and
94 a free_ec. This implies that we should never have a XT_Full that has
95 at the same time some alloc and some freed components > 0.
96 We however still will support this possibility, just in case very
97 strange ec are produced and/or given by the tool. */
98
99static void VG_(XT_Full_init)(void* xtfull)
100{
101 VG_(memset) (xtfull, 0, sizeof(XT_Full));
102}
103static void VG_(XT_Full_add) (void* to, const void* xtfull)
104{
105 XT_Full* xto = to;
106 const XT_Full* xtf = xtfull;
107
108 xto->cur_alloc_nbytes += xtf->cur_alloc_nbytes;
109 xto->cur_alloc_nblocks += xtf->cur_alloc_nblocks;
110 xto->tot_alloc_nbytes += xtf->tot_alloc_nbytes;
111 xto->tot_alloc_nblocks += xtf->tot_alloc_nblocks;
112 xto->tot_freed_nbytes += xtf->tot_freed_nbytes;
113 xto->tot_freed_nblocks += xtf->tot_freed_nblocks;
114}
115static void VG_(XT_Full_sub) (void* from, const void* xtfull)
116{
117 XT_Full* xfrom = from;
118 const XT_Full* xtf = xtfull;
119
120 xfrom->cur_alloc_nbytes -= xtf->cur_alloc_nbytes;
121 xfrom->cur_alloc_nblocks -= xtf->cur_alloc_nblocks;
122 xfrom->tot_alloc_nbytes -= xtf->tot_alloc_nbytes;
123 xfrom->tot_alloc_nblocks -= xtf->tot_alloc_nblocks;
124 xfrom->tot_freed_nbytes -= xtf->tot_freed_nbytes;
125 xfrom->tot_freed_nblocks -= xtf->tot_freed_nblocks;
126}
127static const HChar* VG_(XT_Full_img) (const void* xtfull)
128{
129 static HChar buf[300];
130
131 const XT_Full* xtf = xtfull;
132
133 if ( xtf->cur_alloc_nbytes > 0
134 || xtf->cur_alloc_nblocks > 0
135 || xtf->tot_alloc_nbytes > 0
136 || xtf->tot_alloc_nblocks > 0
137 || xtf->tot_freed_nbytes > 0
138 || xtf->tot_freed_nblocks > 0) {
139 VG_(sprintf) (buf,
140 "%lu %lu "
141 "%llu %llu "
142 "%llu %llu",
143 xtf->cur_alloc_nbytes, xtf->cur_alloc_nblocks,
144 xtf->tot_alloc_nbytes, xtf->tot_alloc_nblocks,
145 xtf->tot_freed_nbytes, xtf->tot_freed_nblocks);
146 return buf;
147 } else {
148 return NULL;
149 }
150}
151static const HChar* XT_Full_events =
152 "curB : currently allocated Bytes" ","
153 "curBk : currently allocated Blocks" ","
154 "totB : total allocated Bytes" ","
155 "totBk : total allocated Blocks" ","
156 "totFdB : total Freed Bytes" ","
157 "totFdBk : total Freed Blocks";
158void VG_(XTMemory_Full_init)(XT_filter_IPs_t filter_IPs_fn)
159{
160 full_xt = VG_(XT_create) (VG_(malloc),
161 "m_xtree.full_xt",
162 VG_(free),
163 sizeof(XT_Full),
164 VG_(XT_Full_init),
165 VG_(XT_Full_add),
166 VG_(XT_Full_sub),
167 filter_IPs_fn);
168}
169void VG_(XTMemory_Full_alloc)(SizeT szB,
170 ExeContext* ec_alloc)
171{
172 XT_Full xtf = {szB, 1, szB, 1, 0, 0};
173 VG_(XT_add_to_ec)(full_xt, ec_alloc, &xtf);
174}
175void VG_(XTMemory_Full_free)(SizeT szB,
176 ExeContext* ec_alloc,
177 ExeContext* ec_free)
178{
179 // substract from ec_alloc the freed memory.
180 XT_Full xtf_sub = {szB, 1, 0, 0, 0, 0};
181 VG_(XT_sub_from_ec)(full_xt, ec_alloc, &xtf_sub);
182
183 // add to ec_free the freed memory
184 XT_Full xtf_add = {0, 0, 0, 0, szB, 1};
185 VG_(XT_add_to_ec)(full_xt, ec_free, &xtf_add);
186}
187
188void VG_(XTMemory_Full_resize_in_place)(SizeT oldSzB, SizeT newSzB,
189 ExeContext* ec_alloc)
190{
191 if (oldSzB > newSzB) {
192 XT_Full xtf = {oldSzB - newSzB, 0, oldSzB - newSzB, 0, 0, 0};
193 VG_(XT_sub_from_ec)(full_xt, ec_alloc, &xtf);
194 } else {
195 XT_Full xtf = {newSzB - oldSzB, 0, newSzB - oldSzB, 0, 0, 0};
196 VG_(XT_add_to_ec)(full_xt, ec_alloc, &xtf);
197 }
198}
199
200// Indicates which event nr the report_value function must return.
201static UInt event_report_value_id;
202static ULong XT_Full_report_value(const void* xtfull)
203{
204 const XT_Full* xtf = xtfull;
205 switch (event_report_value_id) {
206 case 0: return (ULong) xtf->cur_alloc_nbytes;
207 case 1: return (ULong) xtf->cur_alloc_nblocks;
208 case 2: return xtf->tot_alloc_nbytes;
209 case 3: return xtf->tot_alloc_nblocks;
210 case 4: return xtf->tot_freed_nbytes;
211 case 5: return xtf->tot_freed_nblocks;
212 default: vg_assert(0);
213 }
214}
215static ULong XT_Allocs_report_value(const void* xt_allocs)
216{
217 const XT_Allocs* xta = xt_allocs;
218 switch (event_report_value_id) {
219 case 0: return (ULong) xta->nbytes;
220 case 1: return (ULong) xta->nblocks;
221 default: vg_assert(0);
222 }
223}
224
225static void produce_report(XTree* xt, const HChar* filename,
226 const HChar* events,
227 const HChar* (*img_value) (const void* value),
228 ULong (*report_value)(const void* value))
229{
230 /* The user can control the kind of report using filename extension. */
231 if (VG_(strstr)(filename, ".ms")) {
232 /* If needed, some harcoded value below could become parameters. */
233 MsFile* fp;
234 Massif_Header header = (Massif_Header) {
235 .snapshot_n = 0,
236 .time = VG_(read_millisecond_timer)(),
237 .sz_B = 0ul,
238 .extra_B = 0ul,
239 .stacks_B = 0ul,
240 .detailed = True,
241 .peak = False,
242 .top_node_desc = NULL,
243 .sig_threshold = 0.00000000000001
244 // Currently, we take a very small float value to not output
245 // the 0 values, but still output all the rest.
246 };
247
248 // Variables to parse events
249 HChar strtok_events[VG_(strlen)(events)+1];
250 HChar* e;
251 HChar* ssaveptr;
252
253 fp = VG_(XT_massif_open)(filename,
254 "xtree.produce_report",
255 NULL,
256 "ms");
257
258 event_report_value_id = 0;
259 VG_(strcpy)(strtok_events, events);
260 for (e = VG_(strtok_r) (strtok_events, ",", &ssaveptr);
261 e != NULL;
262 e = VG_(strtok_r) (NULL, ",", &ssaveptr)) {
263 header.top_node_desc = e;
264 VG_(XT_massif_print)(fp, xt, &header, report_value);
265 header.snapshot_n++;
266 event_report_value_id++;
267 }
268
269 VG_(XT_massif_close)(fp);
270 } else
271 VG_(XT_callgrind_print)(xt,
272 filename,
273 events,
274 img_value);
275}
276
277void VG_(XTMemory_report)
278 (const HChar* filename, Bool fini,
279 void (*next_block)(XT_Allocs* xta, ExeContext** ec_alloc),
280 XT_filter_IPs_t filter_IPs_fn)
281{
282 HChar* expanded_filename;
283
284 if (fini && VG_(clo_xtree_memory) == Vg_XTMemory_None)
285 return;
286
287 expanded_filename
288 = VG_(expand_file_name)("--xtree-memory-file",
289 (filename == NULL) ?
290 (fini ?
291 VG_(clo_xtree_memory_file)
292 : "xtmemory.kcg.%p.%n")
293 : filename);
294
295 /* fini is False => even if user kept --xtree-memory=none, we
296 produce a report when explicitely requested e.g. via a monitor
297 command. */
298 switch (VG_(clo_xtree_memory)) {
299 case Vg_XTMemory_None:
300 case Vg_XTMemory_Allocs: {
301 XTree* xt;
302 XT_Allocs xta;
303 ExeContext* ec_alloc;
304
305 xt = VG_(XT_create) (VG_(malloc),
306 "VG_(XTMemory_report)",
307 VG_(free),
308 sizeof(XT_Allocs),
309 VG_(XT_Allocs_init),
310 VG_(XT_Allocs_add),
311 VG_(XT_Allocs_sub),
312 filter_IPs_fn);
313 (*next_block)(&xta, &ec_alloc);
314 while ( xta.nblocks > 0 ) {
315 VG_(XT_add_to_ec) (xt, ec_alloc, &xta);
316 (*next_block)(&xta, &ec_alloc);
317 }
318
319 produce_report(xt, expanded_filename,
320 XT_Allocs_events, VG_(XT_Allocs_img),
321 XT_Allocs_report_value);
322
323 VG_(XT_delete)(xt);
324 break;
325 }
326 case Vg_XTMemory_Full:
327 produce_report(full_xt, expanded_filename,
328 XT_Full_events, VG_(XT_Full_img),
329 XT_Full_report_value);
330 break;
331 default:
332 vg_assert(0);
333 }
334 if (VG_(clo_verbosity) >= 1 || !fini)
335 VG_(umsg)("xtree memory report: %s\n", expanded_filename);
336
337 VG_(free)(expanded_filename);
338}
339
340/*--------------------------------------------------------------------*/
341/*--- end m_xtree.c ---*/
342/*--------------------------------------------------------------------*/