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 40 static void VG_(XT_Allocs_init)(void* xt_allocs) 41 { 42 VG_(memset) (xt_allocs, 0, sizeof(XT_Allocs)); 43 } 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 } 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 } 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 99 static void VG_(XT_Full_init)(void* xtfull) 100 { 101 VG_(memset) (xtfull, 0, sizeof(XT_Full)); 102 } 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 } 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 } 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"; 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 } 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 } 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 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; 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 } 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 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 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