Home | History | Annotate | Download | only in coregrind
      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