2 /*--------------------------------------------------------------------*/
3 /*--- Support functions for xtree memory reports. m_xtmemory.c ---*/
4 /*--------------------------------------------------------------------*/
7 This file is part of Valgrind, a dynamic binary instrumentation
10 Copyright (C) 2016-2017 Philippe Waroquiers
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.
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.
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
27 The GNU General Public License is contained in the file COPYING.
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 */
40 static void VG_(XT_Allocs_init
)(void* xt_allocs
)
42 VG_(memset
) (xt_allocs
, 0, sizeof(XT_Allocs
));
44 static void VG_(XT_Allocs_add
) (void* to
, const void* xt_allocs
)
47 const XT_Allocs
* xta
= xt_allocs
;
49 xto
->nbytes
+= xta
->nbytes
;
50 xto
->nblocks
+= xta
->nblocks
;
52 static void VG_(XT_Allocs_sub
) (void* from
, const void* xt_allocs
)
54 XT_Allocs
* xfrom
= from
;
55 const XT_Allocs
* xta
= xt_allocs
;
57 xfrom
->nbytes
-= xta
->nbytes
;
58 xfrom
->nblocks
-= xta
->nblocks
;
60 static const HChar
* VG_(XT_Allocs_img
) (const void* xt_allocs
)
62 static HChar buf
[100];
64 const XT_Allocs
* xta
= xt_allocs
;
66 if (xta
->nbytes
> 0 || xta
->nblocks
> 0) {
67 VG_(sprintf
) (buf
, "%lu %lu",
68 xta
->nbytes
, xta
->nblocks
);
74 const HChar
* XT_Allocs_events
= "curB : currently allocated Bytes" ","
75 "curBk : currently allocated Blocks";
77 /* Type and functions for full xtree memory profiling. */
78 static XTree
* full_xt
;
81 // Current nr of bytes/blocks allocated by this ec
82 SizeT cur_alloc_nbytes
;
83 SizeT cur_alloc_nblocks
;
85 // Total/cumulative nr of bytes/blocks allocated by this ec
86 ULong tot_alloc_nbytes
;
87 ULong tot_alloc_nblocks
;
89 // Total/cumulative nr of bytes/blocks freed by this ec
90 ULong tot_freed_nbytes
;
91 ULong tot_freed_nblocks
;
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. */
99 static void VG_(XT_Full_init
)(void* xtfull
)
101 VG_(memset
) (xtfull
, 0, sizeof(XT_Full
));
103 static void VG_(XT_Full_add
) (void* to
, const void* xtfull
)
106 const XT_Full
* xtf
= xtfull
;
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
;
115 static void VG_(XT_Full_sub
) (void* from
, const void* xtfull
)
117 XT_Full
* xfrom
= from
;
118 const XT_Full
* xtf
= xtfull
;
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
;
127 static const HChar
* VG_(XT_Full_img
) (const void* xtfull
)
129 static HChar buf
[300];
131 const XT_Full
* xtf
= xtfull
;
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) {
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
);
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";
158 void VG_(XTMemory_Full_init
)(XT_filter_IPs_t filter_IPs_fn
)
160 full_xt
= VG_(XT_create
) (VG_(malloc
),
169 void VG_(XTMemory_Full_alloc
)(SizeT szB
,
170 ExeContext
* ec_alloc
)
172 XT_Full xtf
= {szB
, 1, szB
, 1, 0, 0};
173 VG_(XT_add_to_ec
)(full_xt
, ec_alloc
, &xtf
);
175 void VG_(XTMemory_Full_free
)(SizeT szB
,
176 ExeContext
* ec_alloc
,
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
);
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
);
188 void VG_(XTMemory_Full_resize_in_place
)(SizeT oldSzB
, SizeT newSzB
,
189 ExeContext
* ec_alloc
)
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
);
195 XT_Full xtf
= {newSzB
- oldSzB
, 0, newSzB
- oldSzB
, 0, 0, 0};
196 VG_(XT_add_to_ec
)(full_xt
, ec_alloc
, &xtf
);
200 // Indicates which event nr the report_value function must return.
201 static UInt event_report_value_id
;
202 static ULong
XT_Full_report_value(const void* xtfull
)
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);
215 static ULong
XT_Allocs_report_value(const void* xt_allocs
)
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);
225 static void produce_report(XTree
* xt
, const HChar
* filename
,
227 const HChar
* (*img_value
) (const void* value
),
228 ULong (*report_value
)(const void* value
))
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. */
234 Massif_Header header
= (Massif_Header
) {
236 .time
= VG_(read_millisecond_timer
)(),
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.
248 // Variables to parse events
249 HChar strtok_events
[VG_(strlen
)(events
)+1];
253 fp
= VG_(XT_massif_open
)(filename
,
254 "xtree.produce_report",
258 event_report_value_id
= 0;
259 VG_(strcpy
)(strtok_events
, events
);
260 for (e
= VG_(strtok_r
) (strtok_events
, ",", &ssaveptr
);
262 e
= VG_(strtok_r
) (NULL
, ",", &ssaveptr
)) {
263 header
.top_node_desc
= e
;
264 VG_(XT_massif_print
)(fp
, xt
, &header
, report_value
);
266 event_report_value_id
++;
269 VG_(XT_massif_close
)(fp
);
271 VG_(XT_callgrind_print
)(xt
,
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
)
282 HChar
* expanded_filename
;
284 if (fini
&& VG_(clo_xtree_memory
) == Vg_XTMemory_None
)
288 = VG_(expand_file_name
)("--xtree-memory-file",
291 VG_(clo_xtree_memory_file
)
292 : "xtmemory.kcg.%p.%n")
295 /* fini is False => even if user kept --xtree-memory=none, we
296 produce a report when explicitely requested e.g. via a monitor
298 switch (VG_(clo_xtree_memory
)) {
299 case Vg_XTMemory_None
:
300 case Vg_XTMemory_Allocs
: {
303 ExeContext
* ec_alloc
;
305 xt
= VG_(XT_create
) (VG_(malloc
),
306 "VG_(XTMemory_report)",
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
);
319 produce_report(xt
, expanded_filename
,
320 XT_Allocs_events
, VG_(XT_Allocs_img
),
321 XT_Allocs_report_value
);
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
);
334 if (VG_(clo_verbosity
) >= 1 || !fini
)
335 VG_(umsg
)("xtree memory report: %s\n", expanded_filename
);
337 VG_(free
)(expanded_filename
);
340 /*--------------------------------------------------------------------*/
341 /*--- end m_xtree.c ---*/
342 /*--------------------------------------------------------------------*/