• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
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 
VG_(XT_Allocs_init)40 static void VG_(XT_Allocs_init)(void* xt_allocs)
41 {
42    VG_(memset) (xt_allocs, 0, sizeof(XT_Allocs));
43 }
VG_(XT_Allocs_add)44 static 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 }
VG_(XT_Allocs_sub)52 static 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 }
VG_(XT_Allocs_img)60 static 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 }
74 const HChar* XT_Allocs_events = "curB : currently allocated Bytes"   ","
75                                 "curBk : currently allocated Blocks";
76 
77 /* Type and functions for full xtree memory profiling. */
78 static XTree* full_xt;
79 typedef
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 
VG_(XT_Full_init)99 static void VG_(XT_Full_init)(void* xtfull)
100 {
101    VG_(memset) (xtfull, 0, sizeof(XT_Full));
102 }
VG_(XT_Full_add)103 static 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 }
VG_(XT_Full_sub)115 static 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 }
VG_(XT_Full_img)127 static 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 }
151 static 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";
VG_(XTMemory_Full_init)158 void 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 }
VG_(XTMemory_Full_alloc)169 void 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 }
VG_(XTMemory_Full_free)175 void 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 
VG_(XTMemory_Full_resize_in_place)188 void 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.
201 static UInt event_report_value_id;
XT_Full_report_value(const void * xtfull)202 static 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 }
XT_Allocs_report_value(const void * xt_allocs)215 static 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 
produce_report(XTree * xt,const HChar * filename,const HChar * events,const HChar * (* img_value)(const void * value),ULong (* report_value)(const void * value))225 static 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 
VG_(XTMemory_report)277 void 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 /*--------------------------------------------------------------------*/
343