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, see <http://www.gnu.org/licenses/>.
25 The GNU General Public License is contained in the file COPYING.
28 #include "pub_core_libcassert.h"
29 #include "pub_core_libcbase.h"
30 #include "pub_core_libcprint.h"
31 #include "pub_core_libcproc.h"
32 #include "pub_core_mallocfree.h"
33 #include "pub_core_options.h"
34 #include "pub_core_xarray.h"
35 #include "pub_core_xtree.h"
36 #include "pub_core_xtmemory.h" /* self */
38 static void VG_(XT_Allocs_init
)(void* xt_allocs
)
40 VG_(memset
) (xt_allocs
, 0, sizeof(XT_Allocs
));
42 static void VG_(XT_Allocs_add
) (void* to
, const void* xt_allocs
)
45 const XT_Allocs
* xta
= xt_allocs
;
47 xto
->nbytes
+= xta
->nbytes
;
48 xto
->nblocks
+= xta
->nblocks
;
50 static void VG_(XT_Allocs_sub
) (void* from
, const void* xt_allocs
)
52 XT_Allocs
* xfrom
= from
;
53 const XT_Allocs
* xta
= xt_allocs
;
55 xfrom
->nbytes
-= xta
->nbytes
;
56 xfrom
->nblocks
-= xta
->nblocks
;
58 static const HChar
* VG_(XT_Allocs_img
) (const void* xt_allocs
)
60 static HChar buf
[100];
62 const XT_Allocs
* xta
= xt_allocs
;
64 if (xta
->nbytes
> 0 || xta
->nblocks
> 0) {
65 VG_(sprintf
) (buf
, "%lu %lu",
66 xta
->nbytes
, xta
->nblocks
);
72 const HChar
* XT_Allocs_events
= "curB : currently allocated Bytes" ","
73 "curBk : currently allocated Blocks";
75 /* Type and functions for full xtree memory profiling. */
76 static XTree
* full_xt
;
79 // Current nr of bytes/blocks allocated by this ec
80 SizeT cur_alloc_nbytes
;
81 SizeT cur_alloc_nblocks
;
83 // Total/cumulative nr of bytes/blocks allocated by this ec
84 ULong tot_alloc_nbytes
;
85 ULong tot_alloc_nblocks
;
87 // Total/cumulative nr of bytes/blocks freed by this ec
88 ULong tot_freed_nbytes
;
89 ULong tot_freed_nblocks
;
91 /* Note: normally, an ec should never be used as both an alloc_ec and
92 a free_ec. This implies that we should never have a XT_Full that has
93 at the same time some alloc and some freed components > 0.
94 We however still will support this possibility, just in case very
95 strange ec are produced and/or given by the tool. */
97 static void VG_(XT_Full_init
)(void* xtfull
)
99 VG_(memset
) (xtfull
, 0, sizeof(XT_Full
));
101 static void VG_(XT_Full_add
) (void* to
, const void* xtfull
)
104 const XT_Full
* xtf
= xtfull
;
106 xto
->cur_alloc_nbytes
+= xtf
->cur_alloc_nbytes
;
107 xto
->cur_alloc_nblocks
+= xtf
->cur_alloc_nblocks
;
108 xto
->tot_alloc_nbytes
+= xtf
->tot_alloc_nbytes
;
109 xto
->tot_alloc_nblocks
+= xtf
->tot_alloc_nblocks
;
110 xto
->tot_freed_nbytes
+= xtf
->tot_freed_nbytes
;
111 xto
->tot_freed_nblocks
+= xtf
->tot_freed_nblocks
;
113 static void VG_(XT_Full_sub
) (void* from
, const void* xtfull
)
115 XT_Full
* xfrom
= from
;
116 const XT_Full
* xtf
= xtfull
;
118 xfrom
->cur_alloc_nbytes
-= xtf
->cur_alloc_nbytes
;
119 xfrom
->cur_alloc_nblocks
-= xtf
->cur_alloc_nblocks
;
120 xfrom
->tot_alloc_nbytes
-= xtf
->tot_alloc_nbytes
;
121 xfrom
->tot_alloc_nblocks
-= xtf
->tot_alloc_nblocks
;
122 xfrom
->tot_freed_nbytes
-= xtf
->tot_freed_nbytes
;
123 xfrom
->tot_freed_nblocks
-= xtf
->tot_freed_nblocks
;
125 static const HChar
* VG_(XT_Full_img
) (const void* xtfull
)
127 static HChar buf
[300];
129 const XT_Full
* xtf
= xtfull
;
131 if ( xtf
->cur_alloc_nbytes
> 0
132 || xtf
->cur_alloc_nblocks
> 0
133 || xtf
->tot_alloc_nbytes
> 0
134 || xtf
->tot_alloc_nblocks
> 0
135 || xtf
->tot_freed_nbytes
> 0
136 || xtf
->tot_freed_nblocks
> 0) {
141 xtf
->cur_alloc_nbytes
, xtf
->cur_alloc_nblocks
,
142 xtf
->tot_alloc_nbytes
, xtf
->tot_alloc_nblocks
,
143 xtf
->tot_freed_nbytes
, xtf
->tot_freed_nblocks
);
149 static const HChar
* XT_Full_events
=
150 "curB : currently allocated Bytes" ","
151 "curBk : currently allocated Blocks" ","
152 "totB : total allocated Bytes" ","
153 "totBk : total allocated Blocks" ","
154 "totFdB : total Freed Bytes" ","
155 "totFdBk : total Freed Blocks";
156 void VG_(XTMemory_Full_init
)(XT_filter_IPs_t filter_IPs_fn
)
158 full_xt
= VG_(XT_create
) (VG_(malloc
),
167 void VG_(XTMemory_Full_alloc
)(SizeT szB
,
168 ExeContext
* ec_alloc
)
170 XT_Full xtf
= {szB
, 1, szB
, 1, 0, 0};
171 VG_(XT_add_to_ec
)(full_xt
, ec_alloc
, &xtf
);
173 void VG_(XTMemory_Full_free
)(SizeT szB
,
174 ExeContext
* ec_alloc
,
177 // substract from ec_alloc the freed memory.
178 XT_Full xtf_sub
= {szB
, 1, 0, 0, 0, 0};
179 VG_(XT_sub_from_ec
)(full_xt
, ec_alloc
, &xtf_sub
);
181 // add to ec_free the freed memory
182 XT_Full xtf_add
= {0, 0, 0, 0, szB
, 1};
183 VG_(XT_add_to_ec
)(full_xt
, ec_free
, &xtf_add
);
186 void VG_(XTMemory_Full_resize_in_place
)(SizeT oldSzB
, SizeT newSzB
,
187 ExeContext
* ec_alloc
)
189 if (oldSzB
> newSzB
) {
190 XT_Full xtf
= {oldSzB
- newSzB
, 0, oldSzB
- newSzB
, 0, 0, 0};
191 VG_(XT_sub_from_ec
)(full_xt
, ec_alloc
, &xtf
);
193 XT_Full xtf
= {newSzB
- oldSzB
, 0, newSzB
- oldSzB
, 0, 0, 0};
194 VG_(XT_add_to_ec
)(full_xt
, ec_alloc
, &xtf
);
198 // Indicates which event nr the report_value function must return.
199 static UInt event_report_value_id
;
200 static ULong
XT_Full_report_value(const void* xtfull
)
202 const XT_Full
* xtf
= xtfull
;
203 switch (event_report_value_id
) {
204 case 0: return (ULong
) xtf
->cur_alloc_nbytes
;
205 case 1: return (ULong
) xtf
->cur_alloc_nblocks
;
206 case 2: return xtf
->tot_alloc_nbytes
;
207 case 3: return xtf
->tot_alloc_nblocks
;
208 case 4: return xtf
->tot_freed_nbytes
;
209 case 5: return xtf
->tot_freed_nblocks
;
210 default: vg_assert(0);
213 static ULong
XT_Allocs_report_value(const void* xt_allocs
)
215 const XT_Allocs
* xta
= xt_allocs
;
216 switch (event_report_value_id
) {
217 case 0: return (ULong
) xta
->nbytes
;
218 case 1: return (ULong
) xta
->nblocks
;
219 default: vg_assert(0);
223 static void produce_report(XTree
* xt
, const HChar
* filename
,
225 const HChar
* (*img_value
) (const void* value
),
226 ULong (*report_value
)(const void* value
))
228 /* The user can control the kind of report using filename extension. */
229 if (VG_(strstr
)(filename
, ".ms")) {
230 /* If needed, some harcoded value below could become parameters. */
232 Massif_Header header
= (Massif_Header
) {
234 .time
= VG_(read_millisecond_timer
)(),
240 .top_node_desc
= NULL
,
241 .sig_threshold
= 0.00000000000001
242 // Currently, we take a very small float value to not output
243 // the 0 values, but still output all the rest.
246 // Variables to parse events
247 HChar strtok_events
[VG_(strlen
)(events
)+1];
251 fp
= VG_(XT_massif_open
)(filename
,
252 "xtree.produce_report",
256 event_report_value_id
= 0;
257 VG_(strcpy
)(strtok_events
, events
);
258 for (e
= VG_(strtok_r
) (strtok_events
, ",", &ssaveptr
);
260 e
= VG_(strtok_r
) (NULL
, ",", &ssaveptr
)) {
261 header
.top_node_desc
= e
;
262 VG_(XT_massif_print
)(fp
, xt
, &header
, report_value
);
264 event_report_value_id
++;
267 VG_(XT_massif_close
)(fp
);
269 VG_(XT_callgrind_print
)(xt
,
275 void VG_(XTMemory_report
)
276 (const HChar
* filename
, Bool fini
,
277 void (*next_block
)(XT_Allocs
* xta
, ExeContext
** ec_alloc
),
278 XT_filter_IPs_t filter_IPs_fn
)
280 HChar
* expanded_filename
;
282 if (fini
&& VG_(clo_xtree_memory
) == Vg_XTMemory_None
)
286 = VG_(expand_file_name
)("--xtree-memory-file",
289 VG_(clo_xtree_memory_file
)
290 : "xtmemory.kcg.%p.%n")
293 /* fini is False => even if user kept --xtree-memory=none, we
294 produce a report when explicitely requested e.g. via a monitor
296 switch (VG_(clo_xtree_memory
)) {
297 case Vg_XTMemory_None
:
298 case Vg_XTMemory_Allocs
: {
301 ExeContext
* ec_alloc
;
303 xt
= VG_(XT_create
) (VG_(malloc
),
304 "VG_(XTMemory_report)",
311 (*next_block
)(&xta
, &ec_alloc
);
312 while ( xta
.nblocks
> 0 ) {
313 VG_(XT_add_to_ec
) (xt
, ec_alloc
, &xta
);
314 (*next_block
)(&xta
, &ec_alloc
);
317 produce_report(xt
, expanded_filename
,
318 XT_Allocs_events
, VG_(XT_Allocs_img
),
319 XT_Allocs_report_value
);
324 case Vg_XTMemory_Full
:
325 produce_report(full_xt
, expanded_filename
,
326 XT_Full_events
, VG_(XT_Full_img
),
327 XT_Full_report_value
);
332 if (VG_(clo_verbosity
) >= 1 || !fini
)
333 VG_(umsg
)("xtree memory report: %s\n", expanded_filename
);
335 VG_(free
)(expanded_filename
);
338 /*--------------------------------------------------------------------*/
339 /*--- end m_xtree.c ---*/
340 /*--------------------------------------------------------------------*/