FreeBSD: add file descriptor tracking for _umtx_op
[valgrind.git] / coregrind / m_xtmemory.c
blobef68ae9d75b585144135fd93754a9a09da3f22ba
2 /*--------------------------------------------------------------------*/
3 /*--- Support functions for xtree memory reports. m_xtmemory.c ---*/
4 /*--------------------------------------------------------------------*/
6 /*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
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)
44 XT_Allocs* xto = to;
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);
67 return buf;
68 } else {
69 return NULL;
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;
77 typedef
78 struct _XT_Full {
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;
90 } XT_Full;
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)
103 XT_Full* xto = to;
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) {
137 VG_(sprintf) (buf,
138 "%lu %lu "
139 "%llu %llu "
140 "%llu %llu",
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);
144 return buf;
145 } else {
146 return NULL;
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),
159 "m_xtree.full_xt",
160 VG_(free),
161 sizeof(XT_Full),
162 VG_(XT_Full_init),
163 VG_(XT_Full_add),
164 VG_(XT_Full_sub),
165 filter_IPs_fn);
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,
175 ExeContext* ec_free)
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);
192 } else {
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,
224 const HChar* events,
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. */
231 MsFile* fp;
232 Massif_Header header = (Massif_Header) {
233 .snapshot_n = 0,
234 .time = VG_(read_millisecond_timer)(),
235 .sz_B = 0ul,
236 .extra_B = 0ul,
237 .stacks_B = 0ul,
238 .detailed = True,
239 .peak = False,
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];
248 HChar* e;
249 HChar* ssaveptr;
251 fp = VG_(XT_massif_open)(filename,
252 "xtree.produce_report",
253 NULL,
254 "ms");
256 event_report_value_id = 0;
257 VG_(strcpy)(strtok_events, events);
258 for (e = VG_(strtok_r) (strtok_events, ",", &ssaveptr);
259 e != NULL;
260 e = VG_(strtok_r) (NULL, ",", &ssaveptr)) {
261 header.top_node_desc = e;
262 VG_(XT_massif_print)(fp, xt, &header, report_value);
263 header.snapshot_n++;
264 event_report_value_id++;
267 VG_(XT_massif_close)(fp);
268 } else
269 VG_(XT_callgrind_print)(xt,
270 filename,
271 events,
272 img_value);
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)
283 return;
285 expanded_filename
286 = VG_(expand_file_name)("--xtree-memory-file",
287 (filename == NULL) ?
288 (fini ?
289 VG_(clo_xtree_memory_file)
290 : "xtmemory.kcg.%p.%n")
291 : filename);
293 /* fini is False => even if user kept --xtree-memory=none, we
294 produce a report when explicitely requested e.g. via a monitor
295 command. */
296 switch (VG_(clo_xtree_memory)) {
297 case Vg_XTMemory_None:
298 case Vg_XTMemory_Allocs: {
299 XTree* xt;
300 XT_Allocs xta;
301 ExeContext* ec_alloc;
303 xt = VG_(XT_create) (VG_(malloc),
304 "VG_(XTMemory_report)",
305 VG_(free),
306 sizeof(XT_Allocs),
307 VG_(XT_Allocs_init),
308 VG_(XT_Allocs_add),
309 VG_(XT_Allocs_sub),
310 filter_IPs_fn);
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);
321 VG_(XT_delete)(xt);
322 break;
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);
328 break;
329 default:
330 vg_assert(0);
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 /*--------------------------------------------------------------------*/