1734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//--------------------------------------------------------------------*/
2734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//--- Massif: a heap profiling tool.                     ms_main.c ---*/
3734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//--------------------------------------------------------------------*/
4c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
5c9f3692175ba544ecef6f905f5dcd755c3b153benethercote/*
6996901a830e8e7c3fd8be8f0c675c71f2b108957nethercote   This file is part of Massif, a Valgrind tool for profiling memory
7c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   usage of programs.
8c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
90f157ddb404bcde7815a1c5bf2d7e41c114f3d73sewardj   Copyright (C) 2003-2013 Nicholas Nethercote
102bc10126a94b421a490b2759dc50ab67ec4ee116njn      njn@valgrind.org
11c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
12c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   This program is free software; you can redistribute it and/or
13c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   modify it under the terms of the GNU General Public License as
14c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   published by the Free Software Foundation; either version 2 of the
15c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   License, or (at your option) any later version.
16c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
17c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   This program is distributed in the hope that it will be useful, but
18c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   WITHOUT ANY WARRANTY; without even the implied warranty of
19c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   General Public License for more details.
21c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
22c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   You should have received a copy of the GNU General Public License
23c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   along with this program; if not, write to the Free Software
24c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
25c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   02111-1307, USA.
26c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
27c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   The GNU General Public License is contained in the file COPYING.
28c9f3692175ba544ecef6f905f5dcd755c3b153benethercote*/
29c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
30734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//---------------------------------------------------------------------------
31734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// XXX:
32734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//---------------------------------------------------------------------------
33734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// Todo -- nice, but less critical:
34ab23b615fc56c1bf47fb04d62188932291c3a871njn// - do a graph-drawing test
35734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// - make file format more generic.  Obstacles:
36734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   - unit prefixes are not generic
37734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   - preset column widths for stats are not generic
38734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   - preset column headers are not generic
39734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   - "Massif arguments:" line is not generic
40868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe// - do snapshots on some specific client requests
41734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//     - "show me the extra allocations since the last snapshot"
42734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//     - "start/stop logging" (eg. quickly skip boring bits)
43734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// - Add ability to draw multiple graphs, eg. heap-only, stack-only, total.
44734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   Give each graph a title.  (try to do it generically!)
45734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// - make --show-below-main=no work
46a15b6661220b7ae6d4e417030eb5bd348f08ea20njn// - Options like --alloc-fn='operator new(unsigned, std::nothrow_t const&)'
471a2741aad64315cd5da0cc877f474d53af16b5a3njn//   don't work in a .valgrindrc file or in $VALGRIND_OPTS.
481a2741aad64315cd5da0cc877f474d53af16b5a3njn//   m_commandline.c:add_args_from_string() needs to respect single quotes.
493b677e56014e94554456bb24853849cec228d617njn// - With --stack=yes, want to add a stack trace for detailed snapshots so
503b677e56014e94554456bb24853849cec228d617njn//   it's clear where/why the peak is occurring. (Mattieu Castet)  Also,
513b677e56014e94554456bb24853849cec228d617njn//   possibly useful even with --stack=no? (Andi Yin)
52734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//
53734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// Performance:
54734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// - To run the benchmarks:
55734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//
56734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//     perl perf/vg_perf --tools=massif --reps=3 perf/{heap,tinycc} massif
57734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//     time valgrind --tool=massif --depth=100 konqueror
58734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//
59734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   The other benchmarks don't do much allocation, and so give similar speeds
60734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   to Nulgrind.
61734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//
62734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   Timing results on 'nevermore' (njn's machine) as of r7013:
63734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//
64734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//     heap      0.53s  ma:12.4s (23.5x, -----)
65734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//     tinycc    0.46s  ma: 4.9s (10.7x, -----)
66734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//     many-xpts 0.08s  ma: 2.0s (25.0x, -----)
67734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//     konqueror 29.6s real  0:21.0s user
68734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//
69ab23b615fc56c1bf47fb04d62188932291c3a871njn//   [Introduction of --time-unit=i as the default slowed things down by
70ab23b615fc56c1bf47fb04d62188932291c3a871njn//   roughly 0--20%.]
71ab23b615fc56c1bf47fb04d62188932291c3a871njn//
72734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// - get_XCon accounts for about 9% of konqueror startup time.  Try
73734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   keeping XPt children sorted by 'ip' and use binary search in get_XCon.
74734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   Requires factoring out binary search code from various places into a
75734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   VG_(bsearch) function.
76734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//
77734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// Todo -- low priority:
78734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// - In each XPt, record both bytes and the number of allocations, and
79734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   possibly the global number of allocations.
800f85e029aec63c86bfe51360acee949b71e08600njn// - (Andy Lin) Give a stack trace on detailed snapshots?
81734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// - (Artur Wisz) add a feature to Massif to ignore any heap blocks larger
82734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   than a certain size!  Because: "linux's malloc allows to set a
83734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   MMAP_THRESHOLD value, so we set it to 4096 - all blocks above that will
84734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   be handled directly by the kernel, and are guaranteed to be returned to
85734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   the system when freed. So we needed to profile only blocks below this
86734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   limit."
87734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//
88734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// File format working notes:
89734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
90734b805cb3af82ddd7d3ba22a0e22aba29b78305njn#if 0
91734b805cb3af82ddd7d3ba22a0e22aba29b78305njndesc: --heap-admin=foo
92734b805cb3af82ddd7d3ba22a0e22aba29b78305njncmd: date
93734b805cb3af82ddd7d3ba22a0e22aba29b78305njntime_unit: ms
94734b805cb3af82ddd7d3ba22a0e22aba29b78305njn#-----------
95734b805cb3af82ddd7d3ba22a0e22aba29b78305njnsnapshot=0
96734b805cb3af82ddd7d3ba22a0e22aba29b78305njn#-----------
97734b805cb3af82ddd7d3ba22a0e22aba29b78305njntime=0
98734b805cb3af82ddd7d3ba22a0e22aba29b78305njnmem_heap_B=0
99734b805cb3af82ddd7d3ba22a0e22aba29b78305njnmem_heap_admin_B=0
100734b805cb3af82ddd7d3ba22a0e22aba29b78305njnmem_stacks_B=0
101734b805cb3af82ddd7d3ba22a0e22aba29b78305njnheap_tree=empty
102734b805cb3af82ddd7d3ba22a0e22aba29b78305njn#-----------
103734b805cb3af82ddd7d3ba22a0e22aba29b78305njnsnapshot=1
104734b805cb3af82ddd7d3ba22a0e22aba29b78305njn#-----------
105734b805cb3af82ddd7d3ba22a0e22aba29b78305njntime=353
106734b805cb3af82ddd7d3ba22a0e22aba29b78305njnmem_heap_B=5
107734b805cb3af82ddd7d3ba22a0e22aba29b78305njnmem_heap_admin_B=0
108734b805cb3af82ddd7d3ba22a0e22aba29b78305njnmem_stacks_B=0
109734b805cb3af82ddd7d3ba22a0e22aba29b78305njnheap_tree=detailed
110734b805cb3af82ddd7d3ba22a0e22aba29b78305njnn1: 5 (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
111734b805cb3af82ddd7d3ba22a0e22aba29b78305njn n1: 5 0x27F6E0: _nl_normalize_codeset (in /lib/libc-2.3.5.so)
112734b805cb3af82ddd7d3ba22a0e22aba29b78305njn  n1: 5 0x279DE6: _nl_load_locale_from_archive (in /lib/libc-2.3.5.so)
113734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   n1: 5 0x278E97: _nl_find_locale (in /lib/libc-2.3.5.so)
114734b805cb3af82ddd7d3ba22a0e22aba29b78305njn    n1: 5 0x278871: setlocale (in /lib/libc-2.3.5.so)
115734b805cb3af82ddd7d3ba22a0e22aba29b78305njn     n1: 5 0x8049821: (within /bin/date)
116734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      n0: 5 0x26ED5E: (below main) (in /lib/libc-2.3.5.so)
117734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
118734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
119734b805cb3af82ddd7d3ba22a0e22aba29b78305njnn_events: n  time(ms)  total(B)    useful-heap(B)  admin-heap(B)  stacks(B)
120734b805cb3af82ddd7d3ba22a0e22aba29b78305njnt_events: B
121734b805cb3af82ddd7d3ba22a0e22aba29b78305njnn 0 0 0 0 0
122734b805cb3af82ddd7d3ba22a0e22aba29b78305njnn 0 0 0 0 0
123734b805cb3af82ddd7d3ba22a0e22aba29b78305njnt1: 5 <string...>
124734b805cb3af82ddd7d3ba22a0e22aba29b78305njn t1: 6 <string...>
125734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
126734b805cb3af82ddd7d3ba22a0e22aba29b78305njnIdeas:
127734b805cb3af82ddd7d3ba22a0e22aba29b78305njn- each snapshot specifies an x-axis value and one or more y-axis values.
128734b805cb3af82ddd7d3ba22a0e22aba29b78305njn- can display the y-axis values separately if you like
129734b805cb3af82ddd7d3ba22a0e22aba29b78305njn- can completely separate connection between snapshots and trees.
130734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
131734b805cb3af82ddd7d3ba22a0e22aba29b78305njnChallenges:
132734b805cb3af82ddd7d3ba22a0e22aba29b78305njn- how to specify and scale/abbreviate units on axes?
133734b805cb3af82ddd7d3ba22a0e22aba29b78305njn- how to combine multiple values into the y-axis?
134734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
135734b805cb3af82ddd7d3ba22a0e22aba29b78305njn--------------------------------------------------------------------------------Command:            date
136734b805cb3af82ddd7d3ba22a0e22aba29b78305njnMassif arguments:   --heap-admin=foo
137734b805cb3af82ddd7d3ba22a0e22aba29b78305njnms_print arguments: massif.out
138734b805cb3af82ddd7d3ba22a0e22aba29b78305njn--------------------------------------------------------------------------------
139734b805cb3af82ddd7d3ba22a0e22aba29b78305njn    KB
140734b805cb3af82ddd7d3ba22a0e22aba29b78305njn6.472^                                                       :#
141734b805cb3af82ddd7d3ba22a0e22aba29b78305njn     |                                                       :#  ::  .    .
142734b805cb3af82ddd7d3ba22a0e22aba29b78305njn     ...
143734b805cb3af82ddd7d3ba22a0e22aba29b78305njn     |                                     ::@  :@    :@ :@:::#  ::  :    ::::
144734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   0 +-----------------------------------@---@---@-----@--@---#-------------->ms     0                                                                     713
145734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
146734b805cb3af82ddd7d3ba22a0e22aba29b78305njnNumber of snapshots: 50
147734b805cb3af82ddd7d3ba22a0e22aba29b78305njn Detailed snapshots: [2, 11, 13, 19, 25, 32 (peak)]
148734b805cb3af82ddd7d3ba22a0e22aba29b78305njn--------------------------------------------------------------------------------  n       time(ms)         total(B)   useful-heap(B) admin-heap(B)    stacks(B)
149734b805cb3af82ddd7d3ba22a0e22aba29b78305njn--------------------------------------------------------------------------------  0              0                0                0             0            0
150734b805cb3af82ddd7d3ba22a0e22aba29b78305njn  1            345                5                5             0            0
151734b805cb3af82ddd7d3ba22a0e22aba29b78305njn  2            353                5                5             0            0
152734b805cb3af82ddd7d3ba22a0e22aba29b78305njn100.00% (5B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
153734b805cb3af82ddd7d3ba22a0e22aba29b78305njn->100.00% (5B) 0x27F6E0: _nl_normalize_codeset (in /lib/libc-2.3.5.so)
154734b805cb3af82ddd7d3ba22a0e22aba29b78305njn#endif
155734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
156734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//---------------------------------------------------------------------------
157c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
158c7561b931e249acf3768ead77638545b0ccaa8f1njn#include "pub_tool_basics.h"
1594cfea4f9480393ed6799db463b2e0fb8865a1a2fsewardj#include "pub_tool_vki.h"
16045f4e7c91119c7d01a59f5e827c67841632c9314sewardj#include "pub_tool_aspacemgr.h"
161ea27e4627518665dd6c81213c0ba1f7ff0218e1anjn#include "pub_tool_debuginfo.h"
16281c00df9ac724e898179dd90e52b2e15deb11fd8njn#include "pub_tool_hashtable.h"
16397405b2d134b52880d6dbec3eb2929e2002c2542njn#include "pub_tool_libcbase.h"
164132bfccd21960e462352175f8553a5bdce8a210cnjn#include "pub_tool_libcassert.h"
165eb8896b58301a0a7a34281384d705072994369f0njn#include "pub_tool_libcfile.h"
16636a20fa5f779a0a6fb7b4a90dcaa6376481f1faanjn#include "pub_tool_libcprint.h"
167f39e9a36dca9642668a66c6b054f81c88650bcb9njn#include "pub_tool_libcproc.h"
168b506bd863e6cab5aea7cc4bea2ac3bc19a781b56njn#include "pub_tool_machine.h"
169717cde5bda18d17792d1994c61b6a27408b4b4a7njn#include "pub_tool_mallocfree.h"
1702024234c590f408994b373abfb00bc2cd2a90c48njn#include "pub_tool_options.h"
171717cde5bda18d17792d1994c61b6a27408b4b4a7njn#include "pub_tool_replacemalloc.h"
172d01fef7de693582a6ce32bdbef7c9040ad6b356bnjn#include "pub_tool_stacktrace.h"
173e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn#include "pub_tool_threadstate.h"
17443b9a8abb139b86a24457fa3c19b9cb60ca17c3anjn#include "pub_tool_tooliface.h"
17514c7cc5a5fbe9526329f058116f921988efe679esewardj#include "pub_tool_xarray.h"
17645f4e7c91119c7d01a59f5e827c67841632c9314sewardj#include "pub_tool_clientstate.h"
1773b290486cd4cd601b20e04340e593c9ed9717e5fsewardj#include "pub_tool_gdbserver.h"
178c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1791a046d5a3c34f924b648cc22c01f0a8e02ca221eflorian#include "pub_tool_clreq.h"           // For {MALLOC,FREE}LIKE_BLOCK
180c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
181734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------*/
182734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//--- Overview of operation                                ---*/
183734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------*/
184c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
185734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// The size of the stacks and heap is tracked.  The heap is tracked in a lot
186734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// of detail, enough to tell how many bytes each line of code is responsible
187734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// for, more or less.  The main data structure is a tree representing the
188734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// call tree beneath all the allocation functions like malloc().
189e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn// (Alternatively, if --pages-as-heap=yes is specified, memory is tracked at
190e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn// the page level, and each page is treated much like a heap block.  We use
191e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn// "heap" throughout below to cover this case because the concepts are all the
192e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn// same.)
193c9f3692175ba544ecef6f905f5dcd755c3b153benethercote//
194734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// "Snapshots" are recordings of the memory usage.  There are two basic
195734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// kinds:
196734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// - Normal:  these record the current time, total memory size, total heap
197734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   size, heap admin size and stack size.
198734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// - Detailed: these record those things in a normal snapshot, plus a very
199734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   detailed XTree (see below) indicating how the heap is structured.
200c9f3692175ba544ecef6f905f5dcd755c3b153benethercote//
201734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// Snapshots are taken every so often.  There are two storage classes of
202734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// snapshots:
203734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// - Temporary:  Massif does a temporary snapshot every so often.  The idea
204734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   is to always have a certain number of temporary snapshots around.  So
205734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   we take them frequently to begin with, but decreasingly often as the
206734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   program continues to run.  Also, we remove some old ones after a while.
207734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   Overall it's a kind of exponential decay thing.  Most of these are
208734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   normal snapshots, a small fraction are detailed snapshots.
209734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// - Permanent:  Massif takes a permanent (detailed) snapshot in some
210734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   circumstances.  They are:
211734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   - Peak snapshot:  When the memory usage peak is reached, it takes a
212734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//     snapshot.  It keeps this, unless the peak is subsequently exceeded,
213734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//     in which case it will overwrite the peak snapshot.
214734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   - User-requested snapshots:  These are done in response to client
215734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//     requests.  They are always kept.
216734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
217734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// Used for printing things when clo_verbosity > 1.
218734b805cb3af82ddd7d3ba22a0e22aba29b78305njn#define VERB(verb, format, args...) \
219734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (VG_(clo_verbosity) > verb) { \
2205ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj      VG_(dmsg)("Massif: " format, ##args); \
221c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   }
222c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
223734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
224734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//--- Statistics                                           ---//
225734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
226c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
227c9f3692175ba544ecef6f905f5dcd755c3b153benethercote// Konqueror startup, to give an idea of the numbers involved with a biggish
228c9f3692175ba544ecef6f905f5dcd755c3b153benethercote// program, with default depth:
229c9f3692175ba544ecef6f905f5dcd755c3b153benethercote//
230c9f3692175ba544ecef6f905f5dcd755c3b153benethercote//  depth=3                   depth=40
231c9f3692175ba544ecef6f905f5dcd755c3b153benethercote//  - 310,000 allocations
232c9f3692175ba544ecef6f905f5dcd755c3b153benethercote//  - 300,000 frees
233c9f3692175ba544ecef6f905f5dcd755c3b153benethercote//  -  15,000 XPts            800,000 XPts
234c9f3692175ba544ecef6f905f5dcd755c3b153benethercote//  -   1,800 top-XPts
235c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
236f6b0076ba64f5c22f9e09be70c351a9d4b095883njnstatic UInt n_heap_allocs           = 0;
237f6b0076ba64f5c22f9e09be70c351a9d4b095883njnstatic UInt n_heap_reallocs         = 0;
238f6b0076ba64f5c22f9e09be70c351a9d4b095883njnstatic UInt n_heap_frees            = 0;
239f6b0076ba64f5c22f9e09be70c351a9d4b095883njnstatic UInt n_ignored_heap_allocs   = 0;
240f6b0076ba64f5c22f9e09be70c351a9d4b095883njnstatic UInt n_ignored_heap_frees    = 0;
241f6b0076ba64f5c22f9e09be70c351a9d4b095883njnstatic UInt n_ignored_heap_reallocs = 0;
242f6b0076ba64f5c22f9e09be70c351a9d4b095883njnstatic UInt n_stack_allocs          = 0;
243f6b0076ba64f5c22f9e09be70c351a9d4b095883njnstatic UInt n_stack_frees           = 0;
244f6b0076ba64f5c22f9e09be70c351a9d4b095883njnstatic UInt n_xpts                  = 0;
245f6b0076ba64f5c22f9e09be70c351a9d4b095883njnstatic UInt n_xpt_init_expansions   = 0;
246f6b0076ba64f5c22f9e09be70c351a9d4b095883njnstatic UInt n_xpt_later_expansions  = 0;
247f6b0076ba64f5c22f9e09be70c351a9d4b095883njnstatic UInt n_sxpt_allocs           = 0;
248f6b0076ba64f5c22f9e09be70c351a9d4b095883njnstatic UInt n_sxpt_frees            = 0;
249f6b0076ba64f5c22f9e09be70c351a9d4b095883njnstatic UInt n_skipped_snapshots     = 0;
250f6b0076ba64f5c22f9e09be70c351a9d4b095883njnstatic UInt n_real_snapshots        = 0;
251f6b0076ba64f5c22f9e09be70c351a9d4b095883njnstatic UInt n_detailed_snapshots    = 0;
252f6b0076ba64f5c22f9e09be70c351a9d4b095883njnstatic UInt n_peak_snapshots        = 0;
253f6b0076ba64f5c22f9e09be70c351a9d4b095883njnstatic UInt n_cullings              = 0;
254f6b0076ba64f5c22f9e09be70c351a9d4b095883njnstatic UInt n_XCon_redos            = 0;
255734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
256734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
257734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//--- Globals                                              ---//
258734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
259734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
2601a2741aad64315cd5da0cc877f474d53af16b5a3njn// Number of guest instructions executed so far.  Only used with
2611a2741aad64315cd5da0cc877f474d53af16b5a3njn// --time-unit=i.
2621a2741aad64315cd5da0cc877f474d53af16b5a3njnstatic Long guest_instrs_executed = 0;
2631a2741aad64315cd5da0cc877f474d53af16b5a3njn
26432397c0c26fd49181e87a409ad986b9e1b5b0dfdnjnstatic SizeT heap_szB       = 0; // Live heap size
26532397c0c26fd49181e87a409ad986b9e1b5b0dfdnjnstatic SizeT heap_extra_szB = 0; // Live heap extra size -- slop + admin bytes
26632397c0c26fd49181e87a409ad986b9e1b5b0dfdnjnstatic SizeT stacks_szB     = 0; // Live stacks size
267734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
268734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// This is the total size from the current peak snapshot, or 0 if no peak
269734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// snapshot has been taken yet.
270734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic SizeT peak_snapshot_total_szB = 0;
271734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
272734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// Incremented every time memory is allocated/deallocated, by the
273734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// allocated/deallocated amount;  includes heap, heap-admin and stack
274734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// memory.  An alternative to milliseconds as a unit of program "time".
275734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic ULong total_allocs_deallocs_szB = 0;
276c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
277e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn// When running with --heap=yes --pages-as-heap=no, we don't start taking
278e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn// snapshots until the first basic block is executed, rather than doing it in
279e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn// ms_post_clo_init (which is the obvious spot), for two reasons.
280734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// - It lets us ignore stack events prior to that, because they're not
281734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   really proper ones and just would screw things up.
282734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// - Because there's still some core initialisation to do, and so there
283734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   would be an artificial time gap between the first and second snapshots.
284734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//
285e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn// When running with --heap=yes --pages-as-heap=yes, snapshots start much
286e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn// earlier due to new_mem_startup so this isn't relevant.
287e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn//
288734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic Bool have_started_executing_code = False;
289c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
290734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
291734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//--- Alloc fns                                            ---//
292734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
293c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
294734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic XArray* alloc_fns;
295f6b0076ba64f5c22f9e09be70c351a9d4b095883njnstatic XArray* ignore_fns;
296c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
297734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic void init_alloc_fns(void)
298734b805cb3af82ddd7d3ba22a0e22aba29b78305njn{
299734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Create the list, and add the default elements.
3009c606bd8634cd6b67bb41fa645b5c639668cfa2dsewardj   alloc_fns = VG_(newXA)(VG_(malloc), "ms.main.iaf.1",
30119f91bbaedb4caef8a60ce94b0f507193cc0bc10florian                                       VG_(free), sizeof(HChar*));
3026bd9dc18c043927c1196caba20a327238a179c42florian   #define DO(x)  { const HChar* s = x; VG_(addToXA)(alloc_fns, &s); }
303734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
30413118f8b1ae7c0161df02d527cd802287e731a62njn   // Ordered roughly according to (presumed) frequency.
305734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Nb: The C++ "operator new*" ones are overloadable.  We include them
306734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // always anyway, because even if they're overloaded, it would be a
307734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // prodigiously stupid overloading that caused them to not allocate
308734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // memory.
309343a504d2c37a4dabd0241fd0e46d79a677f52a0njn   //
310343a504d2c37a4dabd0241fd0e46d79a677f52a0njn   // XXX: because we don't look at the first stack entry (unless it's a
311343a504d2c37a4dabd0241fd0e46d79a677f52a0njn   // custom allocation) there's not much point to having all these alloc
312343a504d2c37a4dabd0241fd0e46d79a677f52a0njn   // functions here -- they should never appear anywhere (I think?) other
313343a504d2c37a4dabd0241fd0e46d79a677f52a0njn   // than the top stack entry.  The only exceptions are those that in
314343a504d2c37a4dabd0241fd0e46d79a677f52a0njn   // vg_replace_malloc.c are partly or fully implemented in terms of another
315343a504d2c37a4dabd0241fd0e46d79a677f52a0njn   // alloc function: realloc (which uses malloc);  valloc,
316343a504d2c37a4dabd0241fd0e46d79a677f52a0njn   // malloc_zone_valloc, posix_memalign and memalign_common (which use
317343a504d2c37a4dabd0241fd0e46d79a677f52a0njn   // memalign).
318343a504d2c37a4dabd0241fd0e46d79a677f52a0njn   //
319734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   DO("malloc"                                              );
320734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   DO("__builtin_new"                                       );
321734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   DO("operator new(unsigned)"                              );
322734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   DO("operator new(unsigned long)"                         );
323734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   DO("__builtin_vec_new"                                   );
324734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   DO("operator new[](unsigned)"                            );
325734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   DO("operator new[](unsigned long)"                       );
326734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   DO("calloc"                                              );
327734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   DO("realloc"                                             );
328734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   DO("memalign"                                            );
32913118f8b1ae7c0161df02d527cd802287e731a62njn   DO("posix_memalign"                                      );
33013118f8b1ae7c0161df02d527cd802287e731a62njn   DO("valloc"                                              );
331734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   DO("operator new(unsigned, std::nothrow_t const&)"       );
332734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   DO("operator new[](unsigned, std::nothrow_t const&)"     );
333734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   DO("operator new(unsigned long, std::nothrow_t const&)"  );
334734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   DO("operator new[](unsigned long, std::nothrow_t const&)");
3356e9de463ef677f093e9f24f126e1b11c28cf59fdsewardj#if defined(VGO_darwin)
33613118f8b1ae7c0161df02d527cd802287e731a62njn   DO("malloc_zone_malloc"                                  );
33713118f8b1ae7c0161df02d527cd802287e731a62njn   DO("malloc_zone_calloc"                                  );
33813118f8b1ae7c0161df02d527cd802287e731a62njn   DO("malloc_zone_realloc"                                 );
33913118f8b1ae7c0161df02d527cd802287e731a62njn   DO("malloc_zone_memalign"                                );
34013118f8b1ae7c0161df02d527cd802287e731a62njn   DO("malloc_zone_valloc"                                  );
34113118f8b1ae7c0161df02d527cd802287e731a62njn#endif
342734b805cb3af82ddd7d3ba22a0e22aba29b78305njn}
343c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
344f6b0076ba64f5c22f9e09be70c351a9d4b095883njnstatic void init_ignore_fns(void)
345734b805cb3af82ddd7d3ba22a0e22aba29b78305njn{
346f6b0076ba64f5c22f9e09be70c351a9d4b095883njn   // Create the (empty) list.
347f6b0076ba64f5c22f9e09be70c351a9d4b095883njn   ignore_fns = VG_(newXA)(VG_(malloc), "ms.main.iif.1",
34819f91bbaedb4caef8a60ce94b0f507193cc0bc10florian                                        VG_(free), sizeof(HChar*));
349f6b0076ba64f5c22f9e09be70c351a9d4b095883njn}
350f6b0076ba64f5c22f9e09be70c351a9d4b095883njn
351f6b0076ba64f5c22f9e09be70c351a9d4b095883njn// Determines if the named function is a member of the XArray.
35246cc04521acf2827eb33310fadc119bf2dc039e4florianstatic Bool is_member_fn(const XArray* fns, const HChar* fnname)
353f6b0076ba64f5c22f9e09be70c351a9d4b095883njn{
35419f91bbaedb4caef8a60ce94b0f507193cc0bc10florian   HChar** fn_ptr;
355734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   Int i;
356734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
357734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Nb: It's a linear search through the list, because we're comparing
358734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // strings rather than pointers to strings.
359734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Nb: This gets called a lot.  It was an OSet, but they're quite slow to
360734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // iterate through so it wasn't a good choice.
361f6b0076ba64f5c22f9e09be70c351a9d4b095883njn   for (i = 0; i < VG_(sizeXA)(fns); i++) {
362f6b0076ba64f5c22f9e09be70c351a9d4b095883njn      fn_ptr = VG_(indexXA)(fns, i);
363f6b0076ba64f5c22f9e09be70c351a9d4b095883njn      if (VG_STREQ(fnname, *fn_ptr))
364734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         return True;
365734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
366734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   return False;
367734b805cb3af82ddd7d3ba22a0e22aba29b78305njn}
368c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
369c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
370734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
371734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//--- Command line args                                    ---//
372734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
373c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
374734b805cb3af82ddd7d3ba22a0e22aba29b78305njn#define MAX_DEPTH       200
375c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
3761a2741aad64315cd5da0cc877f474d53af16b5a3njntypedef enum { TimeI, TimeMS, TimeB } TimeUnit;
377c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
378e58e8a7a82f81c9237e7cae9a1b70a31dec67d36florianstatic const HChar* TimeUnit_to_string(TimeUnit time_unit)
379734b805cb3af82ddd7d3ba22a0e22aba29b78305njn{
380734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   switch (time_unit) {
3811a2741aad64315cd5da0cc877f474d53af16b5a3njn   case TimeI:  return "i";
382734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   case TimeMS: return "ms";
383734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   case TimeB:  return "B";
384734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   default:     tl_assert2(0, "TimeUnit_to_string: unrecognised TimeUnit");
385c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   }
386734b805cb3af82ddd7d3ba22a0e22aba29b78305njn}
387c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
388e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjnstatic Bool   clo_heap            = True;
389429afb4dd4ef1fc17845f82132772b7a18c98e5bnjn   // clo_heap_admin is deliberately a word-sized type.  At one point it was
390429afb4dd4ef1fc17845f82132772b7a18c98e5bnjn   // a UInt, but this caused problems on 64-bit machines when it was
391429afb4dd4ef1fc17845f82132772b7a18c98e5bnjn   // multiplied by a small negative number and then promoted to a
392429afb4dd4ef1fc17845f82132772b7a18c98e5bnjn   // word-sized type -- it ended up with a value of 4.2 billion.  Sigh.
393efc13c21199dbb35ad07a5e00d538aa884863c01njnstatic SSizeT clo_heap_admin      = 8;
394e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjnstatic Bool   clo_pages_as_heap   = False;
39562721e90cec685b202424719f7237620e2c5780dnjnstatic Bool   clo_stacks          = False;
39683df0b67a14425c484d8dda42b53f3ff0b598894njnstatic Int    clo_depth           = 30;
39762721e90cec685b202424719f7237620e2c5780dnjnstatic double clo_threshold       = 1.0;  // percentage
39862721e90cec685b202424719f7237620e2c5780dnjnstatic double clo_peak_inaccuracy = 1.0;  // percentage
39983df0b67a14425c484d8dda42b53f3ff0b598894njnstatic Int    clo_time_unit       = TimeI;
40083df0b67a14425c484d8dda42b53f3ff0b598894njnstatic Int    clo_detailed_freq   = 10;
40183df0b67a14425c484d8dda42b53f3ff0b598894njnstatic Int    clo_max_snapshots   = 100;
40219f91bbaedb4caef8a60ce94b0f507193cc0bc10florianstatic const HChar* clo_massif_out_file = "massif.out.%p";
403734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
404734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic XArray* args_for_massif;
405c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
40619f91bbaedb4caef8a60ce94b0f507193cc0bc10florianstatic Bool ms_process_cmd_line_option(const HChar* arg)
407c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
40819f91bbaedb4caef8a60ce94b0f507193cc0bc10florian   const HChar* tmp_str;
40983df0b67a14425c484d8dda42b53f3ff0b598894njn
410734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Remember the arg for later use.
411734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   VG_(addToXA)(args_for_massif, &arg);
412734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
413e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn        if VG_BOOL_CLO(arg, "--heap",           clo_heap)   {}
414e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   else if VG_BINT_CLO(arg, "--heap-admin",     clo_heap_admin, 0, 1024) {}
415734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
416e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   else if VG_BOOL_CLO(arg, "--stacks",         clo_stacks) {}
417734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
418e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   else if VG_BOOL_CLO(arg, "--pages-as-heap",  clo_pages_as_heap) {}
419734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
420e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   else if VG_BINT_CLO(arg, "--depth",          clo_depth, 1, MAX_DEPTH) {}
421c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
422e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   else if VG_STR_CLO(arg, "--alloc-fn",        tmp_str) {
42383df0b67a14425c484d8dda42b53f3ff0b598894njn      VG_(addToXA)(alloc_fns, &tmp_str);
424c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   }
425e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   else if VG_STR_CLO(arg, "--ignore-fn",       tmp_str) {
426f6b0076ba64f5c22f9e09be70c351a9d4b095883njn      VG_(addToXA)(ignore_fns, &tmp_str);
427f6b0076ba64f5c22f9e09be70c351a9d4b095883njn   }
428e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
429b1cc5d666cc8f8065419e4a8c819ed0b8256a764njn   else if VG_DBL_CLO(arg, "--threshold",  clo_threshold) {
430b1cc5d666cc8f8065419e4a8c819ed0b8256a764njn      if (clo_threshold < 0 || clo_threshold > 100) {
431b1cc5d666cc8f8065419e4a8c819ed0b8256a764njn         VG_(fmsg_bad_option)(arg,
432b1cc5d666cc8f8065419e4a8c819ed0b8256a764njn            "--threshold must be between 0.0 and 100.0\n");
433b1cc5d666cc8f8065419e4a8c819ed0b8256a764njn      }
434b1cc5d666cc8f8065419e4a8c819ed0b8256a764njn   }
435e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
436e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   else if VG_DBL_CLO(arg, "--peak-inaccuracy", clo_peak_inaccuracy) {}
437e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
438e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   else if VG_XACT_CLO(arg, "--time-unit=i",    clo_time_unit, TimeI)  {}
439e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   else if VG_XACT_CLO(arg, "--time-unit=ms",   clo_time_unit, TimeMS) {}
440e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   else if VG_XACT_CLO(arg, "--time-unit=B",    clo_time_unit, TimeB)  {}
441e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
442e006e6f3046b3a53137489f89d6045cf709f6786njn   else if VG_BINT_CLO(arg, "--detailed-freq",  clo_detailed_freq, 1, 1000000) {}
443e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
444e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   else if VG_BINT_CLO(arg, "--max-snapshots",  clo_max_snapshots, 10, 1000) {}
445e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
44683df0b67a14425c484d8dda42b53f3ff0b598894njn   else if VG_STR_CLO(arg, "--massif-out-file", clo_massif_out_file) {}
447f4c665fc4cbfb05ed0b31364270b00334cbd1f18njn
448c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   else
449c9f3692175ba544ecef6f905f5dcd755c3b153benethercote      return VG_(replacement_malloc_process_cmd_line_option)(arg);
45027fec9071fd5365fa4a517fb77b844b6f8712268nethercote
451c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   return True;
452c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
453c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
45451d827bcd88ce045a383ea1ca81768757df2d1fanjnstatic void ms_print_usage(void)
455c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
456734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   VG_(printf)(
457c9f3692175ba544ecef6f905f5dcd755c3b153benethercote"    --heap=no|yes             profile heap blocks [yes]\n"
458a15b6661220b7ae6d4e417030eb5bd348f08ea20njn"    --heap-admin=<size>       average admin bytes per heap block;\n"
459734b805cb3af82ddd7d3ba22a0e22aba29b78305njn"                               ignored if --heap=no [8]\n"
460734b805cb3af82ddd7d3ba22a0e22aba29b78305njn"    --stacks=no|yes           profile stack(s) [no]\n"
461e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn"    --pages-as-heap=no|yes    profile memory at the page level [no]\n"
462734b805cb3af82ddd7d3ba22a0e22aba29b78305njn"    --depth=<number>          depth of contexts [30]\n"
463f6b0076ba64f5c22f9e09be70c351a9d4b095883njn"    --alloc-fn=<name>         specify <name> as an alloc function [empty]\n"
464f6b0076ba64f5c22f9e09be70c351a9d4b095883njn"    --ignore-fn=<name>        ignore heap allocations within <name> [empty]\n"
46562721e90cec685b202424719f7237620e2c5780dnjn"    --threshold=<m.n>         significance threshold, as a percentage [1.0]\n"
46662721e90cec685b202424719f7237620e2c5780dnjn"    --peak-inaccuracy=<m.n>   maximum peak inaccuracy, as a percentage [1.0]\n"
4671a2741aad64315cd5da0cc877f474d53af16b5a3njn"    --time-unit=i|ms|B        time unit: instructions executed, milliseconds\n"
4681a2741aad64315cd5da0cc877f474d53af16b5a3njn"                              or heap bytes alloc'd/dealloc'd [i]\n"
469734b805cb3af82ddd7d3ba22a0e22aba29b78305njn"    --detailed-freq=<N>       every Nth snapshot should be detailed [10]\n"
470734b805cb3af82ddd7d3ba22a0e22aba29b78305njn"    --max-snapshots=<N>       maximum number of snapshots recorded [100]\n"
471374a36dbfb6d08ed8d77c31a88e198a861ffadf0njn"    --massif-out-file=<file>  output file name [massif.out.%%p]\n"
472c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   );
473c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
474c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
47551d827bcd88ce045a383ea1ca81768757df2d1fanjnstatic void ms_print_debug_usage(void)
476c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
47797db761d2a94fc7a349aee9359ef85828d9618b6njn   VG_(printf)(
47897db761d2a94fc7a349aee9359ef85828d9618b6njn"    (none)\n"
47997db761d2a94fc7a349aee9359ef85828d9618b6njn   );
480c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
481c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
482734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
483734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
484734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//--- XPts, XTrees and XCons                               ---//
485734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
486734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
487734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// An XPt represents an "execution point", ie. a code address.  Each XPt is
488734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// part of a tree of XPts (an "execution tree", or "XTree").  The details of
489734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// the heap are represented by a single XTree.
490734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//
491734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// The root of the tree is 'alloc_xpt', which represents all allocation
492734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// functions, eg:
493734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// - malloc/calloc/realloc/memalign/new/new[];
494734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// - user-specified allocation functions (using --alloc-fn);
495734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// - custom allocation (MALLOCLIKE) points
496734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// It's a bit of a fake XPt (ie. its 'ip' is zero), and is only used because
497734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// it makes the code simpler.
498734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//
499734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// Any child of 'alloc_xpt' is called a "top-XPt".  The XPts at the bottom
500734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// of an XTree (leaf nodes) are "bottom-XPTs".
501734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//
502734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// Each path from a top-XPt to a bottom-XPt through an XTree gives an
503734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// execution context ("XCon"), ie. a stack trace.  (And sub-paths represent
504734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// stack sub-traces.)  The number of XCons in an XTree is equal to the
505734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// number of bottom-XPTs in that XTree.
506734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//
507734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//      alloc_xpt       XTrees are bi-directional.
508734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//        | ^
509734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//        v |
510734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//     > parent <       Example: if child1() calls parent() and child2()
511734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//    /    |     \      also calls parent(), and parent() calls malloc(),
512734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   |    / \     |     the XTree will look like this.
513734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   |   v   v    |
514734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//  child1   child2
515734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//
516dbeb53581d4595a0513d879ba884b108bd3e571enjn// (Note that malformed stack traces can lead to difficulties.  See the
517dbeb53581d4595a0513d879ba884b108bd3e571enjn// comment at the bottom of get_XCon.)
518dbeb53581d4595a0513d879ba884b108bd3e571enjn//
519734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// XTrees and XPts are mirrored by SXTrees and SXPts, where the 'S' is short
520734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// for "saved".  When the XTree is duplicated for a snapshot, we duplicate
521734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// it as an SXTree, which is similar but omits some things it does not need,
522734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// and aggregates up insignificant nodes.  This is important as an SXTree is
523734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// typically much smaller than an XTree.
524734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
525734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// XXX: make XPt and SXPt extensible arrays, to avoid having to do two
526734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// allocations per Pt.
527734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
528734b805cb3af82ddd7d3ba22a0e22aba29b78305njntypedef struct _XPt XPt;
529734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstruct _XPt {
530734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   Addr  ip;              // code address
531734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
532734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Bottom-XPts: space for the precise context.
533734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Other XPts:  space of all the descendent bottom-XPts.
534734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Nb: this value goes up and down as the program executes.
535734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   SizeT szB;
536734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
537734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   XPt*  parent;           // pointer to parent XPt
538734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
539734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Children.
540734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // n_children and max_children are 32-bit integers.  16-bit integers
541734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // are too small -- a very big program might have more than 65536
542734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // allocation points (ie. top-XPts) -- Konqueror starting up has 1800.
543734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   UInt  n_children;       // number of children
544734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   UInt  max_children;     // capacity of children array
545734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   XPt** children;         // pointers to children XPts
546734b805cb3af82ddd7d3ba22a0e22aba29b78305njn};
547734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
548734b805cb3af82ddd7d3ba22a0e22aba29b78305njntypedef
549734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   enum {
550734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      SigSXPt,
551734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      InsigSXPt
552734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
553734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   SXPtTag;
554734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
555734b805cb3af82ddd7d3ba22a0e22aba29b78305njntypedef struct _SXPt SXPt;
556734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstruct _SXPt {
557734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   SXPtTag tag;
558734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   SizeT szB;              // memory size for the node, be it Sig or Insig
559734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   union {
560734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // An SXPt representing a single significant code location.  Much like
561734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // an XPt, minus the fields that aren't necessary.
562734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      struct {
563734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         Addr   ip;
564734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         UInt   n_children;
565734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         SXPt** children;
566734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      }
567734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      Sig;
568734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
569734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // An SXPt representing one or more code locations, all below the
570734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // significance threshold.
571734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      struct {
572734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         Int   n_xpts;     // number of aggregated XPts
573734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      }
574734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      Insig;
575734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   };
576734b805cb3af82ddd7d3ba22a0e22aba29b78305njn};
577c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
578c9f3692175ba544ecef6f905f5dcd755c3b153benethercote// Fake XPt representing all allocation functions like malloc().  Acts as
579c9f3692175ba544ecef6f905f5dcd755c3b153benethercote// parent node to all top-XPts.
580c9f3692175ba544ecef6f905f5dcd755c3b153benethercotestatic XPt* alloc_xpt;
581c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
582734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic XPt* new_XPt(Addr ip, XPt* parent)
583734b805cb3af82ddd7d3ba22a0e22aba29b78305njn{
5846e4b71339ecdf4accc77e86a892718516a531b0fphilippe   // XPts are never freed, so we can use VG_(perm_malloc) to allocate them.
5856e4b71339ecdf4accc77e86a892718516a531b0fphilippe   // Note that we cannot use VG_(perm_malloc) for the 'children' array, because
586734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // that needs to be resizable.
5876e4b71339ecdf4accc77e86a892718516a531b0fphilippe   XPt* xpt    = VG_(perm_malloc)(sizeof(XPt), vg_alignof(XPt));
588734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   xpt->ip     = ip;
589734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   xpt->szB    = 0;
590734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   xpt->parent = parent;
591734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
592734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // We don't initially allocate any space for children.  We let that
593734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // happen on demand.  Many XPts (ie. all the bottom-XPts) don't have any
594734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // children anyway.
595734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   xpt->n_children   = 0;
596734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   xpt->max_children = 0;
597734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   xpt->children     = NULL;
598734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
599734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Update statistics
600734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   n_xpts++;
601c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
602734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   return xpt;
603734b805cb3af82ddd7d3ba22a0e22aba29b78305njn}
604c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
605734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic void add_child_xpt(XPt* parent, XPt* child)
606c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
607734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Expand 'children' if necessary.
608734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   tl_assert(parent->n_children <= parent->max_children);
609734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (parent->n_children == parent->max_children) {
61084f32b200936319bb716cefb38553c9ac414d30anjn      if (0 == parent->max_children) {
611734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         parent->max_children = 4;
6129c606bd8634cd6b67bb41fa645b5c639668cfa2dsewardj         parent->children = VG_(malloc)( "ms.main.acx.1",
6139c606bd8634cd6b67bb41fa645b5c639668cfa2dsewardj                                         parent->max_children * sizeof(XPt*) );
614734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         n_xpt_init_expansions++;
615734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      } else {
616734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         parent->max_children *= 2;    // Double size
6179c606bd8634cd6b67bb41fa645b5c639668cfa2dsewardj         parent->children = VG_(realloc)( "ms.main.acx.2",
6189c606bd8634cd6b67bb41fa645b5c639668cfa2dsewardj                                          parent->children,
619734b805cb3af82ddd7d3ba22a0e22aba29b78305njn                                          parent->max_children * sizeof(XPt*) );
620734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         n_xpt_later_expansions++;
621734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      }
622734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
623c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
624734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Insert new child XPt in parent's children list.
625734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   parent->children[ parent->n_children++ ] = child;
626734b805cb3af82ddd7d3ba22a0e22aba29b78305njn}
627c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
628734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// Reverse comparison for a reverse sort -- biggest to smallest.
6296bd9dc18c043927c1196caba20a327238a179c42florianstatic Int SXPt_revcmp_szB(const void* n1, const void* n2)
630734b805cb3af82ddd7d3ba22a0e22aba29b78305njn{
6313e7986312a0ffc7646b0552d4c4ea3744a870e73florian   const SXPt* sxpt1 = *(const SXPt *const *)n1;
6323e7986312a0ffc7646b0552d4c4ea3744a870e73florian   const SXPt* sxpt2 = *(const SXPt *const *)n2;
633734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   return ( sxpt1->szB < sxpt2->szB ?  1
634734b805cb3af82ddd7d3ba22a0e22aba29b78305njn          : sxpt1->szB > sxpt2->szB ? -1
635734b805cb3af82ddd7d3ba22a0e22aba29b78305njn          :                            0);
636734b805cb3af82ddd7d3ba22a0e22aba29b78305njn}
637fc01635cb093d0b6cae883f8e347cdf9dceb01ddnethercote
638734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
639734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//--- XTree Operations                                     ---//
640734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
641c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
642734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// Duplicates an XTree as an SXTree.
643734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic SXPt* dup_XTree(XPt* xpt, SizeT total_szB)
644734b805cb3af82ddd7d3ba22a0e22aba29b78305njn{
645734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   Int  i, n_sig_children, n_insig_children, n_child_sxpts;
646dbeb53581d4595a0513d879ba884b108bd3e571enjn   SizeT sig_child_threshold_szB;
647734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   SXPt* sxpt;
648734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
649734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Number of XPt children  Action for SXPT
650734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // ------------------      ---------------
651734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // 0 sig, 0 insig          alloc 0 children
652734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // N sig, 0 insig          alloc N children, dup all
653734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // N sig, M insig          alloc N+1, dup first N, aggregate remaining M
654734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // 0 sig, M insig          alloc 1, aggregate M
655734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
656734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Work out how big a child must be to be significant.  If the current
657734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // total_szB is zero, then we set it to 1, which means everything will be
658734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // judged insignificant -- this is sensible, as there's no point showing
659734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // any detail for this case.  Unless they used --threshold=0, in which
660734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // case we show them everything because that's what they asked for.
661734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   //
662734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Nb: We do this once now, rather than once per child, because if we do
663734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // that the cost of all the divisions adds up to something significant.
66484f32b200936319bb716cefb38553c9ac414d30anjn   if (0 == total_szB && 0 != clo_threshold) {
665734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      sig_child_threshold_szB = 1;
666734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   } else {
66762721e90cec685b202424719f7237620e2c5780dnjn      sig_child_threshold_szB = (SizeT)((total_szB * clo_threshold) / 100);
668734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
669734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
670734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // How many children are significant?  And do we need an aggregate SXPt?
671734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   n_sig_children = 0;
672734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   for (i = 0; i < xpt->n_children; i++) {
673734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      if (xpt->children[i]->szB >= sig_child_threshold_szB) {
674734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         n_sig_children++;
675734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      }
676734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
677734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   n_insig_children = xpt->n_children - n_sig_children;
678734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   n_child_sxpts = n_sig_children + ( n_insig_children > 0 ? 1 : 0 );
679734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
680734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Duplicate the XPt.
6819c606bd8634cd6b67bb41fa645b5c639668cfa2dsewardj   sxpt                 = VG_(malloc)("ms.main.dX.1", sizeof(SXPt));
682734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   n_sxpt_allocs++;
683734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   sxpt->tag            = SigSXPt;
684734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   sxpt->szB            = xpt->szB;
685734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   sxpt->Sig.ip         = xpt->ip;
686734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   sxpt->Sig.n_children = n_child_sxpts;
687734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
688734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Create the SXPt's children.
689734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (n_child_sxpts > 0) {
690734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      Int j;
691dbeb53581d4595a0513d879ba884b108bd3e571enjn      SizeT sig_children_szB = 0, insig_children_szB = 0;
6929c606bd8634cd6b67bb41fa645b5c639668cfa2dsewardj      sxpt->Sig.children = VG_(malloc)("ms.main.dX.2",
6939c606bd8634cd6b67bb41fa645b5c639668cfa2dsewardj                                       n_child_sxpts * sizeof(SXPt*));
694734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
695dbeb53581d4595a0513d879ba884b108bd3e571enjn      // Duplicate the significant children.  (Nb: sig_children_szB +
696dbeb53581d4595a0513d879ba884b108bd3e571enjn      // insig_children_szB doesn't necessarily equal xpt->szB.)
697734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      j = 0;
698734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      for (i = 0; i < xpt->n_children; i++) {
699734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         if (xpt->children[i]->szB >= sig_child_threshold_szB) {
700734b805cb3af82ddd7d3ba22a0e22aba29b78305njn            sxpt->Sig.children[j++] = dup_XTree(xpt->children[i], total_szB);
701dbeb53581d4595a0513d879ba884b108bd3e571enjn            sig_children_szB   += xpt->children[i]->szB;
702dbeb53581d4595a0513d879ba884b108bd3e571enjn         } else {
703dbeb53581d4595a0513d879ba884b108bd3e571enjn            insig_children_szB += xpt->children[i]->szB;
704734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         }
705734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      }
706c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
707734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // Create the SXPt for the insignificant children, if any, and put it
708734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // in the last child entry.
709734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      if (n_insig_children > 0) {
710734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         // Nb: We 'n_sxpt_allocs' here because creating an Insig SXPt
711734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         // doesn't involve a call to dup_XTree().
7129c606bd8634cd6b67bb41fa645b5c639668cfa2dsewardj         SXPt* insig_sxpt = VG_(malloc)("ms.main.dX.3", sizeof(SXPt));
713734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         n_sxpt_allocs++;
714734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         insig_sxpt->tag = InsigSXPt;
715734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         insig_sxpt->szB = insig_children_szB;
716734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         insig_sxpt->Insig.n_xpts = n_insig_children;
717734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         sxpt->Sig.children[n_sig_children] = insig_sxpt;
718734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      }
719c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   } else {
720734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      sxpt->Sig.children = NULL;
721c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   }
722c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
723734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   return sxpt;
724734b805cb3af82ddd7d3ba22a0e22aba29b78305njn}
725c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
726734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic void free_SXTree(SXPt* sxpt)
727734b805cb3af82ddd7d3ba22a0e22aba29b78305njn{
728734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   Int  i;
729734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   tl_assert(sxpt != NULL);
730734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
731734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   switch (sxpt->tag) {
732734b805cb3af82ddd7d3ba22a0e22aba29b78305njn    case SigSXPt:
733734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // Free all children SXPts, then the children array.
734734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      for (i = 0; i < sxpt->Sig.n_children; i++) {
735734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         free_SXTree(sxpt->Sig.children[i]);
736734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         sxpt->Sig.children[i] = NULL;
737734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      }
738734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      VG_(free)(sxpt->Sig.children);  sxpt->Sig.children = NULL;
739734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      break;
740734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
741734b805cb3af82ddd7d3ba22a0e22aba29b78305njn    case InsigSXPt:
742734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      break;
743734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
744734b805cb3af82ddd7d3ba22a0e22aba29b78305njn    default: tl_assert2(0, "free_SXTree: unknown SXPt tag");
745734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
746734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
747734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Free the SXPt itself.
748734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   VG_(free)(sxpt);     sxpt = NULL;
749734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   n_sxpt_frees++;
750c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
751c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
752734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// Sanity checking:  we periodically check the heap XTree with
753734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// ms_expensive_sanity_check.
754734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic void sanity_check_XTree(XPt* xpt, XPt* parent)
755c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
756734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   tl_assert(xpt != NULL);
757734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
758734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Check back-pointer.
759734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   tl_assert2(xpt->parent == parent,
760734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      "xpt->parent = %p, parent = %p\n", xpt->parent, parent);
761734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
762734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Check children counts look sane.
763734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   tl_assert(xpt->n_children <= xpt->max_children);
764734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
765dbeb53581d4595a0513d879ba884b108bd3e571enjn   // Unfortunately, xpt's size is not necessarily equal to the sum of xpt's
766dbeb53581d4595a0513d879ba884b108bd3e571enjn   // children's sizes.  See comment at the bottom of get_XCon.
767c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
768c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
769734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// Sanity checking:  we check SXTrees (which are in snapshots) after
770734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// snapshots are created, before they are deleted, and before they are
771734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// printed.
772734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic void sanity_check_SXTree(SXPt* sxpt)
773c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
774734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   Int i;
775c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
776734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   tl_assert(sxpt != NULL);
777734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
778734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Check the sum of any children szBs equals the SXPt's szB.  Check the
779734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // children at the same time.
780734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   switch (sxpt->tag) {
781734b805cb3af82ddd7d3ba22a0e22aba29b78305njn    case SigSXPt: {
782734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      if (sxpt->Sig.n_children > 0) {
783734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         for (i = 0; i < sxpt->Sig.n_children; i++) {
784734b805cb3af82ddd7d3ba22a0e22aba29b78305njn            sanity_check_SXTree(sxpt->Sig.children[i]);
785734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         }
786734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      }
787734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      break;
788734b805cb3af82ddd7d3ba22a0e22aba29b78305njn    }
789734b805cb3af82ddd7d3ba22a0e22aba29b78305njn    case InsigSXPt:
790734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      break;         // do nothing
791734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
792734b805cb3af82ddd7d3ba22a0e22aba29b78305njn    default: tl_assert2(0, "sanity_check_SXTree: unknown SXPt tag");
793734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
794734b805cb3af82ddd7d3ba22a0e22aba29b78305njn}
795734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
796734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
797734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
798734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//--- XCon Operations                                      ---//
799734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
800734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
801734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// This is the limit on the number of removed alloc-fns that can be in a
802734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// single XCon.
803734b805cb3af82ddd7d3ba22a0e22aba29b78305njn#define MAX_OVERESTIMATE   50
804734b805cb3af82ddd7d3ba22a0e22aba29b78305njn#define MAX_IPS            (MAX_DEPTH + MAX_OVERESTIMATE)
805734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
806f6b0076ba64f5c22f9e09be70c351a9d4b095883njn// Determine if the given IP belongs to a function that should be ignored.
807f6b0076ba64f5c22f9e09be70c351a9d4b095883njnstatic Bool fn_should_be_ignored(Addr ip)
808f6b0076ba64f5c22f9e09be70c351a9d4b095883njn{
80946cc04521acf2827eb33310fadc119bf2dc039e4florian   const HChar *buf;
810f6b0076ba64f5c22f9e09be70c351a9d4b095883njn   return
81146cc04521acf2827eb33310fadc119bf2dc039e4florian      ( VG_(get_fnname)(ip, &buf) && is_member_fn(ignore_fns, buf)
812f6b0076ba64f5c22f9e09be70c351a9d4b095883njn      ? True : False );
813f6b0076ba64f5c22f9e09be70c351a9d4b095883njn}
814f6b0076ba64f5c22f9e09be70c351a9d4b095883njn
815734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// Get the stack trace for an XCon, filtering out uninteresting entries:
816734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// alloc-fns and entries above alloc-fns, and entries below main-or-below-main.
817734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   Eg:       alloc-fn1 / alloc-fn2 / a / b / main / (below main) / c
818734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//   becomes:  a / b / main
819734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// Nb: it's possible to end up with an empty trace, eg. if 'main' is marked
820734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// as an alloc-fn.  This is ok.
821734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic
822e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjnInt get_IPs( ThreadId tid, Bool exclude_first_entry, Addr ips[])
823734b805cb3af82ddd7d3ba22a0e22aba29b78305njn{
824734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   Int n_ips, i, n_alloc_fns_removed;
825734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   Int overestimate;
826734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   Bool redo;
827734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
828734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // We ask for a few more IPs than clo_depth suggests we need.  Then we
829734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // remove every entry that is an alloc-fn.  Depending on the
830734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // circumstances, we may need to redo it all, asking for more IPs.
831734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Details:
832734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // - If the original stack trace is smaller than asked-for, redo=False
833734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // - Else if after filtering we have >= clo_depth IPs,      redo=False
834734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // - Else redo=True
835734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // In other words, to redo, we'd have to get a stack trace as big as we
836734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // asked for and remove more than 'overestimate' alloc-fns.
837734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
838734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Main loop.
839734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   redo = True;      // Assume this to begin with.
840734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   for (overestimate = 3; redo; overestimate += 6) {
841734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // This should never happen -- would require MAX_OVERESTIMATE
842734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // alloc-fns to be removed from the stack trace.
843734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      if (overestimate > MAX_OVERESTIMATE)
844734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         VG_(tool_panic)("get_IPs: ips[] too small, inc. MAX_OVERESTIMATE?");
845734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
846734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // Ask for more IPs than clo_depth suggests we need.
84739f3423cd68c385be301e6b44848b4c6276da7b5sewardj      n_ips = VG_(get_StackTrace)( tid, ips, clo_depth + overestimate,
848b8b79addf04dd5d0b558916e26df0b1927cbd758sewardj                                   NULL/*array to dump SP values in*/,
849b8b79addf04dd5d0b558916e26df0b1927cbd758sewardj                                   NULL/*array to dump FP values in*/,
850b8b79addf04dd5d0b558916e26df0b1927cbd758sewardj                                   0/*first_ip_delta*/ );
851734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      tl_assert(n_ips > 0);
852734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
853734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // If the original stack trace is smaller than asked-for, redo=False.
854734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      if (n_ips < clo_depth + overestimate) { redo = False; }
855734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
856e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      // Filter out alloc fns.  If requested, we automatically remove the
857e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      // first entry (which presumably will be something like malloc or
858e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      // __builtin_new that we're sure to filter out) without looking at it,
859e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      // because VG_(get_fnname) is expensive.
860e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      n_alloc_fns_removed = ( exclude_first_entry ? 1 : 0 );
861734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      for (i = n_alloc_fns_removed; i < n_ips; i++) {
86246cc04521acf2827eb33310fadc119bf2dc039e4florian         const HChar *buf;
86346cc04521acf2827eb33310fadc119bf2dc039e4florian         if (VG_(get_fnname)(ips[i], &buf)) {
864f6b0076ba64f5c22f9e09be70c351a9d4b095883njn            if (is_member_fn(alloc_fns, buf)) {
865734b805cb3af82ddd7d3ba22a0e22aba29b78305njn               n_alloc_fns_removed++;
866734b805cb3af82ddd7d3ba22a0e22aba29b78305njn            } else {
867734b805cb3af82ddd7d3ba22a0e22aba29b78305njn               break;
868734b805cb3af82ddd7d3ba22a0e22aba29b78305njn            }
869734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         }
870734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      }
871734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // Remove the alloc fns by shuffling the rest down over them.
872734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      n_ips -= n_alloc_fns_removed;
873734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      for (i = 0; i < n_ips; i++) {
874734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         ips[i] = ips[i + n_alloc_fns_removed];
875734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      }
876c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
877734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // If after filtering we have >= clo_depth IPs, redo=False
878734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      if (n_ips >= clo_depth) {
879734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         redo = False;
880734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         n_ips = clo_depth;      // Ignore any IPs below --depth.
881734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      }
882734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
883734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      if (redo) {
884734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         n_XCon_redos++;
885c9f3692175ba544ecef6f905f5dcd755c3b153benethercote      }
886c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   }
887734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   return n_ips;
888734b805cb3af82ddd7d3ba22a0e22aba29b78305njn}
889734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
890734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// Gets an XCon and puts it in the tree.  Returns the XCon's bottom-XPt.
891f6b0076ba64f5c22f9e09be70c351a9d4b095883njn// Unless the allocation should be ignored, in which case we return NULL.
892e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjnstatic XPt* get_XCon( ThreadId tid, Bool exclude_first_entry )
893734b805cb3af82ddd7d3ba22a0e22aba29b78305njn{
894f6b0076ba64f5c22f9e09be70c351a9d4b095883njn   static Addr ips[MAX_IPS];
895734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   Int i;
896734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   XPt* xpt = alloc_xpt;
897c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
898734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // After this call, the IPs we want are in ips[0]..ips[n_ips-1].
899e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   Int n_ips = get_IPs(tid, exclude_first_entry, ips);
900c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
901f6b0076ba64f5c22f9e09be70c351a9d4b095883njn   // Should we ignore this allocation?  (Nb: n_ips can be zero, eg. if
902f6b0076ba64f5c22f9e09be70c351a9d4b095883njn   // 'main' is marked as an alloc-fn.)
903f6b0076ba64f5c22f9e09be70c351a9d4b095883njn   if (n_ips > 0 && fn_should_be_ignored(ips[0])) {
904f6b0076ba64f5c22f9e09be70c351a9d4b095883njn      return NULL;
905f6b0076ba64f5c22f9e09be70c351a9d4b095883njn   }
906f6b0076ba64f5c22f9e09be70c351a9d4b095883njn
907734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Now do the search/insertion of the XCon.
908734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   for (i = 0; i < n_ips; i++) {
909734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      Addr ip = ips[i];
910734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      Int ch;
911d01fef7de693582a6ce32bdbef7c9040ad6b356bnjn      // Look for IP in xpt's children.
912734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // Linear search, ugh -- about 10% of time for konqueror startup tried
913734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // caching last result, only hit about 4% for konqueror.
914c9f3692175ba544ecef6f905f5dcd755c3b153benethercote      // Nb:  this search hits about 98% of the time for konqueror
915734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      for (ch = 0; True; ch++) {
916734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         if (ch == xpt->n_children) {
917734b805cb3af82ddd7d3ba22a0e22aba29b78305njn            // IP not found in the children.
918734b805cb3af82ddd7d3ba22a0e22aba29b78305njn            // Create and add new child XPt, then stop.
919734b805cb3af82ddd7d3ba22a0e22aba29b78305njn            XPt* new_child_xpt = new_XPt(ip, xpt);
920734b805cb3af82ddd7d3ba22a0e22aba29b78305njn            add_child_xpt(xpt, new_child_xpt);
921734b805cb3af82ddd7d3ba22a0e22aba29b78305njn            xpt = new_child_xpt;
922734b805cb3af82ddd7d3ba22a0e22aba29b78305njn            break;
923c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
924734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         } else if (ip == xpt->children[ch]->ip) {
925734b805cb3af82ddd7d3ba22a0e22aba29b78305njn            // Found the IP in the children, stop.
926734b805cb3af82ddd7d3ba22a0e22aba29b78305njn            xpt = xpt->children[ch];
927c9f3692175ba544ecef6f905f5dcd755c3b153benethercote            break;
928c9f3692175ba544ecef6f905f5dcd755c3b153benethercote         }
929c9f3692175ba544ecef6f905f5dcd755c3b153benethercote      }
930c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   }
931dbeb53581d4595a0513d879ba884b108bd3e571enjn
932dbeb53581d4595a0513d879ba884b108bd3e571enjn   // [Note: several comments refer to this comment.  Do not delete it
933dbeb53581d4595a0513d879ba884b108bd3e571enjn   // without updating them.]
934dbeb53581d4595a0513d879ba884b108bd3e571enjn   //
935dbeb53581d4595a0513d879ba884b108bd3e571enjn   // A complication... If all stack traces were well-formed, then the
936dbeb53581d4595a0513d879ba884b108bd3e571enjn   // returned xpt would always be a bottom-XPt.  As a consequence, an XPt's
937dbeb53581d4595a0513d879ba884b108bd3e571enjn   // size would always be equal to the sum of its children's sizes, which
938dbeb53581d4595a0513d879ba884b108bd3e571enjn   // is an excellent sanity check.
939dbeb53581d4595a0513d879ba884b108bd3e571enjn   //
940dbeb53581d4595a0513d879ba884b108bd3e571enjn   // Unfortunately, stack traces occasionally are malformed, ie. truncated.
941dbeb53581d4595a0513d879ba884b108bd3e571enjn   // This allows a stack trace to be a sub-trace of another, eg. a/b/c is a
942dbeb53581d4595a0513d879ba884b108bd3e571enjn   // sub-trace of a/b/c/d.  So we can't assume this xpt is a bottom-XPt;
943dbeb53581d4595a0513d879ba884b108bd3e571enjn   // nor can we do sanity check an XPt's size against its children's sizes.
944dbeb53581d4595a0513d879ba884b108bd3e571enjn   // This is annoying, but must be dealt with.  (Older versions of Massif
945dbeb53581d4595a0513d879ba884b108bd3e571enjn   // had this assertion in, and it was reported to fail by real users a
946dbeb53581d4595a0513d879ba884b108bd3e571enjn   // couple of times.)  Even more annoyingly, I can't come up with a simple
947dbeb53581d4595a0513d879ba884b108bd3e571enjn   // test case that exhibit such a malformed stack trace, so I can't
948dbeb53581d4595a0513d879ba884b108bd3e571enjn   // regression test it.  Sigh.
949dbeb53581d4595a0513d879ba884b108bd3e571enjn   //
950dbeb53581d4595a0513d879ba884b108bd3e571enjn   // However, we can print a warning, so that if it happens (unexpectedly)
951dbeb53581d4595a0513d879ba884b108bd3e571enjn   // in existing regression tests we'll know.  Also, it warns users that
952dbeb53581d4595a0513d879ba884b108bd3e571enjn   // the output snapshots may not add up the way they might expect.
953dbeb53581d4595a0513d879ba884b108bd3e571enjn   //
954dbeb53581d4595a0513d879ba884b108bd3e571enjn   //tl_assert(0 == xpt->n_children); // Must be bottom-XPt
955dbeb53581d4595a0513d879ba884b108bd3e571enjn   if (0 != xpt->n_children) {
956dbeb53581d4595a0513d879ba884b108bd3e571enjn      static Int n_moans = 0;
957dbeb53581d4595a0513d879ba884b108bd3e571enjn      if (n_moans < 3) {
9585ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj         VG_(umsg)(
9595ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj            "Warning: Malformed stack trace detected.  In Massif's output,\n");
9605ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj         VG_(umsg)(
9615ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj            "         the size of an entry's child entries may not sum up\n");
9625ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj         VG_(umsg)(
9635ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj            "         to the entry's size as they normally do.\n");
964dbeb53581d4595a0513d879ba884b108bd3e571enjn         n_moans++;
965dbeb53581d4595a0513d879ba884b108bd3e571enjn         if (3 == n_moans)
9665ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj            VG_(umsg)(
9675ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj            "         (And Massif now won't warn about this again.)\n");
968dbeb53581d4595a0513d879ba884b108bd3e571enjn      }
969dbeb53581d4595a0513d879ba884b108bd3e571enjn   }
970734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   return xpt;
971c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
972c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
973734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// Update 'szB' of every XPt in the XCon, by percolating upwards.
974734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic void update_XCon(XPt* xpt, SSizeT space_delta)
975c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
976e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   tl_assert(clo_heap);
977ca82cc01fb1580551144b69d3f17213a80d952e1njn   tl_assert(NULL != xpt);
978c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
979734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (0 == space_delta)
980734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      return;
981734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
982c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   while (xpt != alloc_xpt) {
983734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      if (space_delta < 0) tl_assert(xpt->szB >= -space_delta);
984734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      xpt->szB += space_delta;
985c9f3692175ba544ecef6f905f5dcd755c3b153benethercote      xpt = xpt->parent;
986734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
987734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (space_delta < 0) tl_assert(alloc_xpt->szB >= -space_delta);
988734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   alloc_xpt->szB += space_delta;
989c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
990c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
991c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
992734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
993734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//--- Snapshots                                            ---//
994734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
995c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
996734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// Snapshots are done in a way so that we always have a reasonable number of
997734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// them.  We start by taking them quickly.  Once we hit our limit, we cull
998734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// some (eg. half), and start taking them more slowly.  Once we hit the
999734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// limit again, we again cull and then take them even more slowly, and so
1000734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// on.
1001c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
10021a2741aad64315cd5da0cc877f474d53af16b5a3njn// Time is measured either in i or ms or bytes, depending on the --time-unit
1003734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// option.  It's a Long because it can exceed 32-bits reasonably easily, and
1004734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// because we need to allow negative values to represent unset times.
1005734b805cb3af82ddd7d3ba22a0e22aba29b78305njntypedef Long Time;
1006734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1007734b805cb3af82ddd7d3ba22a0e22aba29b78305njn#define UNUSED_SNAPSHOT_TIME  -333  // A conspicuous negative number.
1008c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1009c9f3692175ba544ecef6f905f5dcd755c3b153benethercotetypedef
1010734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   enum {
1011734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      Normal = 77,
1012734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      Peak,
1013734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      Unused
1014c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   }
1015734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   SnapshotKind;
1016c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1017734b805cb3af82ddd7d3ba22a0e22aba29b78305njntypedef
1018734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   struct {
1019734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      SnapshotKind kind;
1020734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      Time  time;
1021734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      SizeT heap_szB;
102232397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn      SizeT heap_extra_szB;// Heap slop + admin bytes.
1023734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      SizeT stacks_szB;
1024734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      SXPt* alloc_sxpt;    // Heap XTree root, if a detailed snapshot,
102532397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn   }                       // otherwise NULL.
1026734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   Snapshot;
1027734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1028734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic UInt      next_snapshot_i = 0;  // Index of where next snapshot will go.
1029734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic Snapshot* snapshots;            // Array of snapshots.
1030734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1031734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic Bool is_snapshot_in_use(Snapshot* snapshot)
1032c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
1033734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (Unused == snapshot->kind) {
1034734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // If snapshot is unused, check all the fields are unset.
1035734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      tl_assert(snapshot->time           == UNUSED_SNAPSHOT_TIME);
103632397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn      tl_assert(snapshot->heap_extra_szB == 0);
1037734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      tl_assert(snapshot->heap_szB       == 0);
1038734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      tl_assert(snapshot->stacks_szB     == 0);
1039734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      tl_assert(snapshot->alloc_sxpt     == NULL);
1040734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      return False;
1041734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   } else {
1042734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      tl_assert(snapshot->time           != UNUSED_SNAPSHOT_TIME);
1043734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      return True;
1044734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
1045c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
1046c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1047734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic Bool is_detailed_snapshot(Snapshot* snapshot)
1048c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
1049734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   return (snapshot->alloc_sxpt ? True : False);
1050c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
1051c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1052734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic Bool is_uncullable_snapshot(Snapshot* snapshot)
1053c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
1054734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   return &snapshots[0] == snapshot                   // First snapshot
1055734b805cb3af82ddd7d3ba22a0e22aba29b78305njn       || &snapshots[next_snapshot_i-1] == snapshot   // Last snapshot
1056734b805cb3af82ddd7d3ba22a0e22aba29b78305njn       || snapshot->kind == Peak;                     // Peak snapshot
1057c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
1058734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1059734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic void sanity_check_snapshot(Snapshot* snapshot)
1060c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
1061734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (snapshot->alloc_sxpt) {
1062734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      sanity_check_SXTree(snapshot->alloc_sxpt);
1063c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   }
1064c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
1065c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1066734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// All the used entries should look used, all the unused ones should be clear.
1067734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic void sanity_check_snapshots_array(void)
1068c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
1069734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   Int i;
1070734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   for (i = 0; i < next_snapshot_i; i++) {
1071734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      tl_assert( is_snapshot_in_use( & snapshots[i] ));
1072734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
1073734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   for (    ; i < clo_max_snapshots; i++) {
1074734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      tl_assert(!is_snapshot_in_use( & snapshots[i] ));
1075734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
1076c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
1077c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1078734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// This zeroes all the fields in the snapshot, but does not free the heap
1079734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// XTree if present.  It also does a sanity check unless asked not to;  we
1080734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// can't sanity check at startup when clearing the initial snapshots because
1081734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// they're full of junk.
1082734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic void clear_snapshot(Snapshot* snapshot, Bool do_sanity_check)
1083c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
1084734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (do_sanity_check) sanity_check_snapshot(snapshot);
1085734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   snapshot->kind           = Unused;
1086734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   snapshot->time           = UNUSED_SNAPSHOT_TIME;
108732397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn   snapshot->heap_extra_szB = 0;
1088734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   snapshot->heap_szB       = 0;
1089734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   snapshot->stacks_szB     = 0;
1090734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   snapshot->alloc_sxpt     = NULL;
1091c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
1092c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1093734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// This zeroes all the fields in the snapshot, and frees the heap XTree if
1094734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// present.
1095734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic void delete_snapshot(Snapshot* snapshot)
1096c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
1097734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Nb: if there's an XTree, we free it after calling clear_snapshot,
1098734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // because clear_snapshot does a sanity check which includes checking the
1099734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // XTree.
1100734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   SXPt* tmp_sxpt = snapshot->alloc_sxpt;
1101734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   clear_snapshot(snapshot, /*do_sanity_check*/True);
1102734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (tmp_sxpt) {
1103734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      free_SXTree(tmp_sxpt);
1104734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
1105c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
1106c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1107e58e8a7a82f81c9237e7cae9a1b70a31dec67d36florianstatic void VERB_snapshot(Int verbosity, const HChar* prefix, Int i)
1108c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
1109734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   Snapshot* snapshot = &snapshots[i];
1110e58e8a7a82f81c9237e7cae9a1b70a31dec67d36florian   const HChar* suffix;
1111734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   switch (snapshot->kind) {
1112734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   case Peak:   suffix = "p";                                            break;
1113734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   case Normal: suffix = ( is_detailed_snapshot(snapshot) ? "d" : "." ); break;
1114734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   case Unused: suffix = "u";                                            break;
1115734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   default:
1116734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      tl_assert2(0, "VERB_snapshot: unknown snapshot kind: %d", snapshot->kind);
1117734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
11185ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj   VERB(verbosity, "%s S%s%3d (t:%lld, hp:%ld, ex:%ld, st:%ld)\n",
1119734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      prefix, suffix, i,
1120734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      snapshot->time,
1121734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      snapshot->heap_szB,
112232397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn      snapshot->heap_extra_szB,
1123734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      snapshot->stacks_szB
1124734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   );
1125734b805cb3af82ddd7d3ba22a0e22aba29b78305njn}
1126c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1127734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// Cull half the snapshots;  we choose those that represent the smallest
1128734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// time-spans, because that gives us the most even distribution of snapshots
1129734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// over time.  (It's possible to lose interesting spikes, however.)
1130734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//
1131734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// Algorithm for N snapshots:  We find the snapshot representing the smallest
1132734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// timeframe, and remove it.  We repeat this until (N/2) snapshots are gone.
1133734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// We have to do this one snapshot at a time, rather than finding the (N/2)
1134734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// smallest snapshots in one hit, because when a snapshot is removed, its
1135734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// neighbours immediately cover greater timespans.  So it's O(N^2), but N is
1136734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// small, and it's not done very often.
1137734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//
1138734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// Once we're done, we return the new smallest interval between snapshots.
1139734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// That becomes our minimum time interval.
1140734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic UInt cull_snapshots(void)
1141734b805cb3af82ddd7d3ba22a0e22aba29b78305njn{
1142734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   Int  i, jp, j, jn, min_timespan_i;
1143734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   Int  n_deleted = 0;
1144734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   Time min_timespan;
1145734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1146734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   n_cullings++;
1147734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1148734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Sets j to the index of the first not-yet-removed snapshot at or after i
1149734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   #define FIND_SNAPSHOT(i, j) \
1150734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      for (j = i; \
1151734b805cb3af82ddd7d3ba22a0e22aba29b78305njn           j < clo_max_snapshots && !is_snapshot_in_use(&snapshots[j]); \
1152734b805cb3af82ddd7d3ba22a0e22aba29b78305njn           j++) { }
1153734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
11545ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj   VERB(2, "Culling...\n");
1155734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1156734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // First we remove enough snapshots by clearing them in-place.  Once
1157734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // that's done, we can slide the remaining ones down.
1158734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   for (i = 0; i < clo_max_snapshots/2; i++) {
1159734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // Find the snapshot representing the smallest timespan.  The timespan
1160734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // for snapshot n = d(N-1,N)+d(N,N+1), where d(A,B) is the time between
1161734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // snapshot A and B.  We don't consider the first and last snapshots for
1162734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // removal.
1163734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      Snapshot* min_snapshot;
1164734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      Int min_j;
116557e36b3e766c9e33c59f994319b66a51b37319f7nethercote
1166734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // Initial triple: (prev, curr, next) == (jp, j, jn)
1167734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // Initial min_timespan is the first one.
1168734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      jp = 0;
1169734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      FIND_SNAPSHOT(1,   j);
1170734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      FIND_SNAPSHOT(j+1, jn);
1171734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      min_timespan = 0x7fffffffffffffffLL;
1172734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      min_j        = -1;
1173734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      while (jn < clo_max_snapshots) {
1174734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         Time timespan = snapshots[jn].time - snapshots[jp].time;
1175734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         tl_assert(timespan >= 0);
1176734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         // Nb: We never cull the peak snapshot.
1177734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         if (Peak != snapshots[j].kind && timespan < min_timespan) {
1178734b805cb3af82ddd7d3ba22a0e22aba29b78305njn            min_timespan = timespan;
1179734b805cb3af82ddd7d3ba22a0e22aba29b78305njn            min_j        = j;
1180734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         }
1181734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         // Move on to next triple
1182734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         jp = j;
1183734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         j  = jn;
1184734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         FIND_SNAPSHOT(jn+1, jn);
118557e36b3e766c9e33c59f994319b66a51b37319f7nethercote      }
1186734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // We've found the least important snapshot, now delete it.  First
1187734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // print it if necessary.
1188734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      tl_assert(-1 != min_j);    // Check we found a minimum.
1189734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      min_snapshot = & snapshots[ min_j ];
1190734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      if (VG_(clo_verbosity) > 1) {
1191ef901ff97a6a31684529a7e8c836087d2ec28026florian         HChar buf[64];   // large enough
1192734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         VG_(snprintf)(buf, 64, " %3d (t-span = %lld)", i, min_timespan);
1193734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         VERB_snapshot(2, buf, min_j);
1194734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      }
1195734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      delete_snapshot(min_snapshot);
1196734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      n_deleted++;
119757e36b3e766c9e33c59f994319b66a51b37319f7nethercote   }
119857e36b3e766c9e33c59f994319b66a51b37319f7nethercote
1199734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Slide down the remaining snapshots over the removed ones.  First set i
1200734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // to point to the first empty slot, and j to the first full slot after
1201734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // i.  Then slide everything down.
1202734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   for (i = 0;  is_snapshot_in_use( &snapshots[i] ); i++) { }
1203734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   for (j = i; !is_snapshot_in_use( &snapshots[j] ); j++) { }
1204734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   for (  ; j < clo_max_snapshots; j++) {
1205734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      if (is_snapshot_in_use( &snapshots[j] )) {
1206734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         snapshots[i++] = snapshots[j];
1207734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         clear_snapshot(&snapshots[j], /*do_sanity_check*/True);
1208734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      }
1209c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   }
1210734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   next_snapshot_i = i;
1211734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1212734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Check snapshots array looks ok after changes.
1213734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   sanity_check_snapshots_array();
1214734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1215734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Find the minimum timespan remaining;  that will be our new minimum
1216734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // time interval.  Note that above we were finding timespans by measuring
1217734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // two intervals around a snapshot that was under consideration for
1218734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // deletion.  Here we only measure single intervals because all the
1219734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // deletions have occurred.
1220734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   //
1221734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // But we have to be careful -- some snapshots (eg. snapshot 0, and the
1222734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // peak snapshot) are uncullable.  If two uncullable snapshots end up
1223734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // next to each other, they'll never be culled (assuming the peak doesn't
1224734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // change), and the time gap between them will not change.  However, the
1225734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // time between the remaining cullable snapshots will grow ever larger.
1226734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // This means that the min_timespan found will always be that between the
1227734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // two uncullable snapshots, and it will be much smaller than it should
1228734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // be.  To avoid this problem, when computing the minimum timespan, we
1229734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // ignore any timespans between two uncullable snapshots.
1230734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   tl_assert(next_snapshot_i > 1);
1231734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   min_timespan = 0x7fffffffffffffffLL;
1232734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   min_timespan_i = -1;
1233734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   for (i = 1; i < next_snapshot_i; i++) {
1234734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      if (is_uncullable_snapshot(&snapshots[i]) &&
1235734b805cb3af82ddd7d3ba22a0e22aba29b78305njn          is_uncullable_snapshot(&snapshots[i-1]))
1236734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      {
12375ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj         VERB(2, "(Ignoring interval %d--%d when computing minimum)\n", i-1, i);
1238734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      } else {
1239734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         Time timespan = snapshots[i].time - snapshots[i-1].time;
1240734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         tl_assert(timespan >= 0);
1241734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         if (timespan < min_timespan) {
1242734b805cb3af82ddd7d3ba22a0e22aba29b78305njn            min_timespan = timespan;
1243734b805cb3af82ddd7d3ba22a0e22aba29b78305njn            min_timespan_i = i;
1244734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         }
1245734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      }
1246734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
1247734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   tl_assert(-1 != min_timespan_i);    // Check we found a minimum.
1248734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1249734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Print remaining snapshots, if necessary.
1250734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (VG_(clo_verbosity) > 1) {
12515ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj      VERB(2, "Finished culling (%3d of %3d deleted)\n",
1252734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         n_deleted, clo_max_snapshots);
1253734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      for (i = 0; i < next_snapshot_i; i++) {
1254734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         VERB_snapshot(2, "  post-cull", i);
1255734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      }
12565ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj      VERB(2, "New time interval = %lld (between snapshots %d and %d)\n",
1257734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         min_timespan, min_timespan_i-1, min_timespan_i);
1258734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
1259734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1260734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   return min_timespan;
1261c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
1262c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1263734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic Time get_time(void)
1264c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
1265734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Get current time, in whatever time unit we're using.
12661a2741aad64315cd5da0cc877f474d53af16b5a3njn   if (clo_time_unit == TimeI) {
12671a2741aad64315cd5da0cc877f474d53af16b5a3njn      return guest_instrs_executed;
12681a2741aad64315cd5da0cc877f474d53af16b5a3njn   } else if (clo_time_unit == TimeMS) {
1269734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // Some stuff happens between the millisecond timer being initialised
1270734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // to zero and us taking our first snapshot.  We determine that time
1271734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // gap so we can subtract it from all subsequent times so that our
1272734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // first snapshot is considered to be at t = 0ms.  Unfortunately, a
1273734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // bunch of symbols get read after the first snapshot is taken but
1274734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // before the second one (which is triggered by the first allocation),
1275734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // so when the time-unit is 'ms' we always have a big gap between the
1276734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // first two snapshots.  But at least users won't have to wonder why
1277734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // the first snapshot isn't at t=0.
1278734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      static Bool is_first_get_time = True;
1279734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      static Time start_time_ms;
1280734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      if (is_first_get_time) {
1281734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         start_time_ms = VG_(read_millisecond_timer)();
1282734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         is_first_get_time = False;
1283734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         return 0;
1284734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      } else {
1285734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         return VG_(read_millisecond_timer)() - start_time_ms;
1286734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      }
1287734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   } else if (clo_time_unit == TimeB) {
1288734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      return total_allocs_deallocs_szB;
1289734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   } else {
1290734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      tl_assert2(0, "bad --time-unit value");
1291734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
1292734b805cb3af82ddd7d3ba22a0e22aba29b78305njn}
1293c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1294734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// Take a snapshot, and only that -- decisions on whether to take a
1295734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// snapshot, or what kind of snapshot, are made elsewhere.
1296f76d27a697a7b0bf3b84490baf60623fc96a23afnjn// Nb: we call the arg "my_time" because "time" shadows a global declaration
1297f76d27a697a7b0bf3b84490baf60623fc96a23afnjn// in /usr/include/time.h on Darwin.
1298734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic void
1299f76d27a697a7b0bf3b84490baf60623fc96a23afnjntake_snapshot(Snapshot* snapshot, SnapshotKind kind, Time my_time,
1300efc13c21199dbb35ad07a5e00d538aa884863c01njn              Bool is_detailed)
1301734b805cb3af82ddd7d3ba22a0e22aba29b78305njn{
1302734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   tl_assert(!is_snapshot_in_use(snapshot));
1303e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   if (!clo_pages_as_heap) {
1304e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      tl_assert(have_started_executing_code);
1305e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   }
1306c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1307734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Heap and heap admin.
1308734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (clo_heap) {
1309734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      snapshot->heap_szB = heap_szB;
1310734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      if (is_detailed) {
131132397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn         SizeT total_szB = heap_szB + heap_extra_szB + stacks_szB;
1312734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         snapshot->alloc_sxpt = dup_XTree(alloc_xpt, total_szB);
1313734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         tl_assert(           alloc_xpt->szB == heap_szB);
1314734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         tl_assert(snapshot->alloc_sxpt->szB == heap_szB);
1315734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      }
131632397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn      snapshot->heap_extra_szB = heap_extra_szB;
1317734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
1318c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1319734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Stack(s).
1320734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (clo_stacks) {
1321734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      snapshot->stacks_szB = stacks_szB;
1322734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
132357e36b3e766c9e33c59f994319b66a51b37319f7nethercote
1324734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Rest of snapshot.
1325734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   snapshot->kind = kind;
1326f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   snapshot->time = my_time;
1327734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   sanity_check_snapshot(snapshot);
1328c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1329734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Update stats.
1330734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (Peak == kind) n_peak_snapshots++;
1331734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (is_detailed)  n_detailed_snapshots++;
1332734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   n_real_snapshots++;
1333c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
1334c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1335c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1336734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// Take a snapshot, if it's time, or if we've hit a peak.
1337734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic void
1338e58e8a7a82f81c9237e7cae9a1b70a31dec67d36florianmaybe_take_snapshot(SnapshotKind kind, const HChar* what)
1339c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
1340734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // 'min_time_interval' is the minimum time interval between snapshots.
1341734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // If we try to take a snapshot and less than this much time has passed,
1342734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // we don't take it.  It gets larger as the program runs longer.  It's
1343734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // initialised to zero so that we begin by taking snapshots as quickly as
1344734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // possible.
1345734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   static Time min_time_interval = 0;
1346734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Zero allows startup snapshot.
1347734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   static Time earliest_possible_time_of_next_snapshot = 0;
1348734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   static Int  n_snapshots_since_last_detailed         = 0;
1349734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   static Int  n_skipped_snapshots_since_last_snapshot = 0;
1350734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1351734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   Snapshot* snapshot;
1352734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   Bool      is_detailed;
1353f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   // Nb: we call this variable "my_time" because "time" shadows a global
1354f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   // declaration in /usr/include/time.h on Darwin.
1355f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   Time      my_time = get_time();
1356734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1357734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   switch (kind) {
1358734b805cb3af82ddd7d3ba22a0e22aba29b78305njn    case Normal:
1359734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // Only do a snapshot if it's time.
1360f76d27a697a7b0bf3b84490baf60623fc96a23afnjn      if (my_time < earliest_possible_time_of_next_snapshot) {
1361734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         n_skipped_snapshots++;
1362734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         n_skipped_snapshots_since_last_snapshot++;
1363734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         return;
1364734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      }
1365734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      is_detailed = (clo_detailed_freq-1 == n_snapshots_since_last_detailed);
1366734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      break;
1367734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1368734b805cb3af82ddd7d3ba22a0e22aba29b78305njn    case Peak: {
1369734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // Because we're about to do a deallocation, we're coming down from a
1370734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // local peak.  If it is (a) actually a global peak, and (b) a certain
1371734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // amount bigger than the previous peak, then we take a peak snapshot.
1372734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // By not taking a snapshot for every peak, we save a lot of effort --
1373734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // because many peaks remain peak only for a short time.
137432397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn      SizeT total_szB = heap_szB + heap_extra_szB + stacks_szB;
1375734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      SizeT excess_szB_for_new_peak =
137662721e90cec685b202424719f7237620e2c5780dnjn         (SizeT)((peak_snapshot_total_szB * clo_peak_inaccuracy) / 100);
1377734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      if (total_szB <= peak_snapshot_total_szB + excess_szB_for_new_peak) {
1378734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         return;
1379734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      }
1380734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      is_detailed = True;
1381734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      break;
1382734b805cb3af82ddd7d3ba22a0e22aba29b78305njn    }
1383734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1384734b805cb3af82ddd7d3ba22a0e22aba29b78305njn    default:
1385734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      tl_assert2(0, "maybe_take_snapshot: unrecognised snapshot kind");
1386734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
1387734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1388734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Take the snapshot.
1389734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   snapshot = & snapshots[next_snapshot_i];
1390f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   take_snapshot(snapshot, kind, my_time, is_detailed);
1391734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1392734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Record if it was detailed.
1393734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (is_detailed) {
1394734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      n_snapshots_since_last_detailed = 0;
1395734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   } else {
1396734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      n_snapshots_since_last_detailed++;
1397734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
1398734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1399734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Update peak data, if it's a Peak snapshot.
1400734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (Peak == kind) {
1401734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      Int i, number_of_peaks_snapshots_found = 0;
1402734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1403734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // Sanity check the size, then update our recorded peak.
1404734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      SizeT snapshot_total_szB =
140532397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn         snapshot->heap_szB + snapshot->heap_extra_szB + snapshot->stacks_szB;
1406734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      tl_assert2(snapshot_total_szB > peak_snapshot_total_szB,
1407734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         "%ld, %ld\n", snapshot_total_szB, peak_snapshot_total_szB);
1408734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      peak_snapshot_total_szB = snapshot_total_szB;
1409734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1410734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // Find the old peak snapshot, if it exists, and mark it as normal.
1411734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      for (i = 0; i < next_snapshot_i; i++) {
1412734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         if (Peak == snapshots[i].kind) {
1413734b805cb3af82ddd7d3ba22a0e22aba29b78305njn            snapshots[i].kind = Normal;
1414734b805cb3af82ddd7d3ba22a0e22aba29b78305njn            number_of_peaks_snapshots_found++;
1415734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         }
1416734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      }
1417734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      tl_assert(number_of_peaks_snapshots_found <= 1);
1418734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
1419734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1420734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Finish up verbosity and stats stuff.
1421734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (n_skipped_snapshots_since_last_snapshot > 0) {
14225ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj      VERB(2, "  (skipped %d snapshot%s)\n",
1423734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         n_skipped_snapshots_since_last_snapshot,
142484f32b200936319bb716cefb38553c9ac414d30anjn         ( 1 == n_skipped_snapshots_since_last_snapshot ? "" : "s") );
1425734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
1426734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   VERB_snapshot(2, what, next_snapshot_i);
1427734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   n_skipped_snapshots_since_last_snapshot = 0;
1428734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1429734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Cull the entries, if our snapshot table is full.
1430734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   next_snapshot_i++;
1431734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (clo_max_snapshots == next_snapshot_i) {
1432734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      min_time_interval = cull_snapshots();
1433734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
1434734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1435734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Work out the earliest time when the next snapshot can happen.
1436f76d27a697a7b0bf3b84490baf60623fc96a23afnjn   earliest_possible_time_of_next_snapshot = my_time + min_time_interval;
1437c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
1438c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1439734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1440734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
1441734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//--- Sanity checking                                      ---//
1442734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
1443734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1444734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic Bool ms_cheap_sanity_check ( void )
1445c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
1446734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   return True;   // Nothing useful we can cheaply check.
1447c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
1448c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1449734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic Bool ms_expensive_sanity_check ( void )
1450c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
1451734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   sanity_check_XTree(alloc_xpt, /*parent*/NULL);
1452734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   sanity_check_snapshots_array();
1453734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   return True;
1454c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
1455c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1456734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1457734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
1458734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//--- Heap management                                      ---//
1459734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
1460734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1461734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// Metadata for heap blocks.  Each one contains a pointer to a bottom-XPt,
1462734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// which is a foothold into the XCon at which it was allocated.  From
1463734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// HP_Chunks, XPt 'space' fields are incremented (at allocation) and
1464734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// decremented (at deallocation).
1465734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//
1466734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// Nb: first two fields must match core's VgHashNode.
1467734b805cb3af82ddd7d3ba22a0e22aba29b78305njntypedef
1468734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   struct _HP_Chunk {
1469734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      struct _HP_Chunk* next;
147032397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn      Addr              data;       // Ptr to actual block
147132397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn      SizeT             req_szB;    // Size requested
147232397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn      SizeT             slop_szB;   // Extra bytes given above those requested
147332397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn      XPt*              where;      // Where allocated; bottom-XPt
1474734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
1475734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   HP_Chunk;
1476734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
147709a4c794458cdb9dea743fa40e450150a2725257florianstatic VgHashTable *malloc_list  = NULL;   // HP_Chunks
1478734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1479734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic void update_alloc_stats(SSizeT szB_delta)
148051f3ff144429823396f58a91b0268eebb966233cfitzhardinge{
1481734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Update total_allocs_deallocs_szB.
1482734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (szB_delta < 0) szB_delta = -szB_delta;
1483734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   total_allocs_deallocs_szB += szB_delta;
148451f3ff144429823396f58a91b0268eebb966233cfitzhardinge}
148551f3ff144429823396f58a91b0268eebb966233cfitzhardinge
148632397c0c26fd49181e87a409ad986b9e1b5b0dfdnjnstatic void update_heap_stats(SSizeT heap_szB_delta, Int heap_extra_szB_delta)
1487c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
148832397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn   if (heap_szB_delta < 0)
148932397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn      tl_assert(heap_szB >= -heap_szB_delta);
149032397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn   if (heap_extra_szB_delta < 0)
149132397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn      tl_assert(heap_extra_szB >= -heap_extra_szB_delta);
149232397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn
149332397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn   heap_extra_szB += heap_extra_szB_delta;
149432397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn   heap_szB       += heap_szB_delta;
1495734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
149632397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn   update_alloc_stats(heap_szB_delta + heap_extra_szB_delta);
1497c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
1498c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1499734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic
1500e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjnvoid* record_block( ThreadId tid, void* p, SizeT req_szB, SizeT slop_szB,
1501e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn                    Bool exclude_first_entry, Bool maybe_snapshot )
1502c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
1503734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Make new HP_Chunk node, add to malloc_list
1504e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   HP_Chunk* hc = VG_(malloc)("ms.main.rb.1", sizeof(HP_Chunk));
150532397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn   hc->req_szB  = req_szB;
150632397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn   hc->slop_szB = slop_szB;
150732397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn   hc->data     = (Addr)p;
150832397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn   hc->where    = NULL;
1509734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   VG_(HT_add_node)(malloc_list, hc);
1510734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1511734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (clo_heap) {
1512e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      VERB(3, "<<< record_block (%lu, %lu)\n", req_szB, slop_szB);
1513734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1514e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      hc->where = get_XCon( tid, exclude_first_entry );
1515734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1516f6b0076ba64f5c22f9e09be70c351a9d4b095883njn      if (hc->where) {
1517f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         // Update statistics.
1518f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         n_heap_allocs++;
1519734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1520f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         // Update heap stats.
1521f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         update_heap_stats(req_szB, clo_heap_admin + slop_szB);
1522f6b0076ba64f5c22f9e09be70c351a9d4b095883njn
1523f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         // Update XTree.
1524f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         update_XCon(hc->where, req_szB);
1525f6b0076ba64f5c22f9e09be70c351a9d4b095883njn
1526f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         // Maybe take a snapshot.
1527e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn         if (maybe_snapshot) {
1528e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn            maybe_take_snapshot(Normal, "  alloc");
1529e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn         }
1530f6b0076ba64f5c22f9e09be70c351a9d4b095883njn
1531f6b0076ba64f5c22f9e09be70c351a9d4b095883njn      } else {
1532f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         // Ignored allocation.
1533f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         n_ignored_heap_allocs++;
1534734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
15355ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj         VERB(3, "(ignored)\n");
1536f6b0076ba64f5c22f9e09be70c351a9d4b095883njn      }
1537734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
15385ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj      VERB(3, ">>>\n");
1539734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
1540734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1541734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   return p;
1542c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
1543c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1544734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic __inline__
1545e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjnvoid* alloc_and_record_block ( ThreadId tid, SizeT req_szB, SizeT req_alignB,
1546e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn                               Bool is_zeroed )
1547e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn{
1548e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   SizeT actual_szB, slop_szB;
1549e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   void* p;
1550e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
1551e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   if ((SSizeT)req_szB < 0) return NULL;
1552e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
1553e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   // Allocate and zero if necessary.
1554e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   p = VG_(cli_malloc)( req_alignB, req_szB );
1555e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   if (!p) {
1556e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      return NULL;
1557e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   }
1558e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   if (is_zeroed) VG_(memset)(p, 0, req_szB);
1559e464e80d4f2e22ebb6787b555b58d73c9e027ff8florian   actual_szB = VG_(cli_malloc_usable_size)(p);
1560e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   tl_assert(actual_szB >= req_szB);
1561e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   slop_szB = actual_szB - req_szB;
1562e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
1563e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   // Record block.
1564e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   record_block(tid, p, req_szB, slop_szB, /*exclude_first_entry*/True,
1565e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn                /*maybe_snapshot*/True);
1566e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
1567e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   return p;
1568e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn}
1569e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
1570e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjnstatic __inline__
1571e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjnvoid unrecord_block ( void* p, Bool maybe_snapshot )
1572c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
1573734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Remove HP_Chunk from malloc_list
15747081c1a48e1097e910f3d83853b68bc030231814njn   HP_Chunk* hc = VG_(HT_remove)(malloc_list, (UWord)p);
1575734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (NULL == hc) {
1576734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      return;   // must have been a bogus free()
1577734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
1578734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1579734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (clo_heap) {
1580e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      VERB(3, "<<< unrecord_block\n");
1581734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1582f6b0076ba64f5c22f9e09be70c351a9d4b095883njn      if (hc->where) {
1583f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         // Update statistics.
1584f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         n_heap_frees++;
1585734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1586f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         // Maybe take a peak snapshot, since it's a deallocation.
1587e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn         if (maybe_snapshot) {
1588e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn            maybe_take_snapshot(Peak, "de-PEAK");
1589e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn         }
1590734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1591f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         // Update heap stats.
1592f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         update_heap_stats(-hc->req_szB, -clo_heap_admin - hc->slop_szB);
1593734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1594f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         // Update XTree.
1595f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         update_XCon(hc->where, -hc->req_szB);
1596734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1597f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         // Maybe take a snapshot.
1598e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn         if (maybe_snapshot) {
1599e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn            maybe_take_snapshot(Normal, "dealloc");
1600e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn         }
1601f6b0076ba64f5c22f9e09be70c351a9d4b095883njn
1602f6b0076ba64f5c22f9e09be70c351a9d4b095883njn      } else {
1603f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         n_ignored_heap_frees++;
1604f6b0076ba64f5c22f9e09be70c351a9d4b095883njn
16055ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj         VERB(3, "(ignored)\n");
1606f6b0076ba64f5c22f9e09be70c351a9d4b095883njn      }
1607734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
16085ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj      VERB(3, ">>> (-%lu, -%lu)\n", hc->req_szB, hc->slop_szB);
1609734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
1610734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1611734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Actually free the chunk, and the heap block (if necessary)
1612734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   VG_(free)( hc );  hc = NULL;
1613c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
1614c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1615f6b0076ba64f5c22f9e09be70c351a9d4b095883njn// Nb: --ignore-fn is tricky for realloc.  If the block's original alloc was
1616f6b0076ba64f5c22f9e09be70c351a9d4b095883njn// ignored, but the realloc is not requested to be ignored, and we are
1617f6b0076ba64f5c22f9e09be70c351a9d4b095883njn// shrinking the block, then we have to ignore the realloc -- otherwise we
1618f6b0076ba64f5c22f9e09be70c351a9d4b095883njn// could end up with negative heap sizes.  This isn't a danger if we are
1619f6b0076ba64f5c22f9e09be70c351a9d4b095883njn// growing such a block, but for consistency (it also simplifies things) we
1620f6b0076ba64f5c22f9e09be70c351a9d4b095883njn// ignore such reallocs as well.
1621734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic __inline__
1622e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjnvoid* realloc_block ( ThreadId tid, void* p_old, SizeT new_req_szB )
1623c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
16245cc5d7e2b8f361ac222b2cd34fd365abba82dc8enjn   HP_Chunk* hc;
16255cc5d7e2b8f361ac222b2cd34fd365abba82dc8enjn   void*     p_new;
162632397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn   SizeT     old_req_szB, old_slop_szB, new_slop_szB, new_actual_szB;
16275cc5d7e2b8f361ac222b2cd34fd365abba82dc8enjn   XPt      *old_where, *new_where;
1628f6b0076ba64f5c22f9e09be70c351a9d4b095883njn   Bool      is_ignored = False;
1629734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1630a079365fef42a43a2c7b4d5742dc23c0c86e250fnjn   // Remove the old block
16319a46324fe85e70f08777cf7e37863293a25637banjn   hc = VG_(HT_remove)(malloc_list, (UWord)p_old);
1632c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   if (hc == NULL) {
16335cc5d7e2b8f361ac222b2cd34fd365abba82dc8enjn      return NULL;   // must have been a bogus realloc()
1634c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   }
1635c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
163632397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn   old_req_szB  = hc->req_szB;
163732397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn   old_slop_szB = hc->slop_szB;
1638734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1639e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   tl_assert(!clo_pages_as_heap);  // Shouldn't be here if --pages-as-heap=yes.
1640734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (clo_heap) {
1641e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      VERB(3, "<<< realloc_block (%lu)\n", new_req_szB);
1642734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1643f6b0076ba64f5c22f9e09be70c351a9d4b095883njn      if (hc->where) {
1644f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         // Update statistics.
1645f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         n_heap_reallocs++;
1646734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1647f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         // Maybe take a peak snapshot, if it's (effectively) a deallocation.
1648f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         if (new_req_szB < old_req_szB) {
1649f6b0076ba64f5c22f9e09be70c351a9d4b095883njn            maybe_take_snapshot(Peak, "re-PEAK");
1650f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         }
1651f6b0076ba64f5c22f9e09be70c351a9d4b095883njn      } else {
1652f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         // The original malloc was ignored, so we have to ignore the
1653f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         // realloc as well.
1654f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         is_ignored = True;
1655734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      }
1656734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
1657734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1658734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Actually do the allocation, if necessary.
165932397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn   if (new_req_szB <= old_req_szB + old_slop_szB) {
166032397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn      // New size is smaller or same;  block not moved.
1661c9f3692175ba544ecef6f905f5dcd755c3b153benethercote      p_new = p_old;
166232397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn      new_slop_szB = old_slop_szB + (old_req_szB - new_req_szB);
1663c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1664c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   } else {
166532397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn      // New size is bigger;  make new block, copy shared contents, free old.
166632397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn      p_new = VG_(cli_malloc)(VG_(clo_alignment), new_req_szB);
166732397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn      if (!p_new) {
166832397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn         // Nb: if realloc fails, NULL is returned but the old block is not
166932397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn         // touched.  What an awful function.
167032397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn         return NULL;
16710cd42f0881519a581909b670a4aebe27e53155detom      }
1672dfa408c71a5fa3181cb0329269f939f18f5aeb6enjn      VG_(memcpy)(p_new, p_old, old_req_szB + old_slop_szB);
167332397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn      VG_(cli_free)(p_old);
1674e464e80d4f2e22ebb6787b555b58d73c9e027ff8florian      new_actual_szB = VG_(cli_malloc_usable_size)(p_new);
167532397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn      tl_assert(new_actual_szB >= new_req_szB);
167632397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn      new_slop_szB = new_actual_szB - new_req_szB;
1677c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   }
1678c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
16790cd42f0881519a581909b670a4aebe27e53155detom   if (p_new) {
1680734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // Update HP_Chunk.
168132397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn      hc->data     = (Addr)p_new;
168232397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn      hc->req_szB  = new_req_szB;
168332397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn      hc->slop_szB = new_slop_szB;
168432397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn      old_where    = hc->where;
168532397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn      hc->where    = NULL;
16860cd42f0881519a581909b670a4aebe27e53155detom
1687734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // Update XTree.
16880cd42f0881519a581909b670a4aebe27e53155detom      if (clo_heap) {
1689e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn         new_where = get_XCon( tid, /*exclude_first_entry*/True);
1690f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         if (!is_ignored && new_where) {
1691f6b0076ba64f5c22f9e09be70c351a9d4b095883njn            hc->where = new_where;
1692f6b0076ba64f5c22f9e09be70c351a9d4b095883njn            update_XCon(old_where, -old_req_szB);
1693f6b0076ba64f5c22f9e09be70c351a9d4b095883njn            update_XCon(new_where,  new_req_szB);
1694f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         } else {
1695f6b0076ba64f5c22f9e09be70c351a9d4b095883njn            // The realloc itself is ignored.
1696f6b0076ba64f5c22f9e09be70c351a9d4b095883njn            is_ignored = True;
1697f6b0076ba64f5c22f9e09be70c351a9d4b095883njn
1698f6b0076ba64f5c22f9e09be70c351a9d4b095883njn            // Update statistics.
1699f6b0076ba64f5c22f9e09be70c351a9d4b095883njn            n_ignored_heap_reallocs++;
1700f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         }
17010cd42f0881519a581909b670a4aebe27e53155detom      }
1702c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   }
1703c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
17045cc5d7e2b8f361ac222b2cd34fd365abba82dc8enjn   // Now insert the new hc (with a possibly new 'data' field) into
17055cc5d7e2b8f361ac222b2cd34fd365abba82dc8enjn   // malloc_list.  If this realloc() did not increase the memory size, we
1706734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // will have removed and then re-added hc unnecessarily.  But that's ok
17075cc5d7e2b8f361ac222b2cd34fd365abba82dc8enjn   // because shrinking a block with realloc() is (presumably) much rarer
17085cc5d7e2b8f361ac222b2cd34fd365abba82dc8enjn   // than growing it, and this way simplifies the growing case.
1709246a9d2e0c66b3f69d7a23f370205a48368843b7njn   VG_(HT_add_node)(malloc_list, hc);
1710c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1711734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (clo_heap) {
1712f6b0076ba64f5c22f9e09be70c351a9d4b095883njn      if (!is_ignored) {
1713f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         // Update heap stats.
1714f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         update_heap_stats(new_req_szB - old_req_szB,
1715f6b0076ba64f5c22f9e09be70c351a9d4b095883njn                          new_slop_szB - old_slop_szB);
1716f6b0076ba64f5c22f9e09be70c351a9d4b095883njn
1717f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         // Maybe take a snapshot.
1718f6b0076ba64f5c22f9e09be70c351a9d4b095883njn         maybe_take_snapshot(Normal, "realloc");
1719f6b0076ba64f5c22f9e09be70c351a9d4b095883njn      } else {
172032397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn
17215ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj         VERB(3, "(ignored)\n");
1722f6b0076ba64f5c22f9e09be70c351a9d4b095883njn      }
1723734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
17245ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj      VERB(3, ">>> (%ld, %ld)\n",
172532397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn         new_req_szB - old_req_szB, new_slop_szB - old_slop_szB);
1726734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
1727734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1728c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   return p_new;
1729c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
1730c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1731c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1732734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
1733734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//--- malloc() et al replacement wrappers                  ---//
1734734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
1735c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1736734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic void* ms_malloc ( ThreadId tid, SizeT szB )
1737c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
1738e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   return alloc_and_record_block( tid, szB, VG_(clo_alignment), /*is_zeroed*/False );
1739c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
1740c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1741734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic void* ms___builtin_new ( ThreadId tid, SizeT szB )
1742c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
1743e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   return alloc_and_record_block( tid, szB, VG_(clo_alignment), /*is_zeroed*/False );
1744c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
1745c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1746734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic void* ms___builtin_vec_new ( ThreadId tid, SizeT szB )
1747c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
1748e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   return alloc_and_record_block( tid, szB, VG_(clo_alignment), /*is_zeroed*/False );
1749c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
1750c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1751734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic void* ms_calloc ( ThreadId tid, SizeT m, SizeT szB )
1752c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
1753e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   return alloc_and_record_block( tid, m*szB, VG_(clo_alignment), /*is_zeroed*/True );
1754734b805cb3af82ddd7d3ba22a0e22aba29b78305njn}
1755c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1756734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic void *ms_memalign ( ThreadId tid, SizeT alignB, SizeT szB )
1757734b805cb3af82ddd7d3ba22a0e22aba29b78305njn{
1758e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   return alloc_and_record_block( tid, szB, alignB, False );
1759734b805cb3af82ddd7d3ba22a0e22aba29b78305njn}
1760c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1761efc13c21199dbb35ad07a5e00d538aa884863c01njnstatic void ms_free ( ThreadId tid __attribute__((unused)), void* p )
1762734b805cb3af82ddd7d3ba22a0e22aba29b78305njn{
1763e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   unrecord_block(p, /*maybe_snapshot*/True);
1764e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   VG_(cli_free)(p);
1765734b805cb3af82ddd7d3ba22a0e22aba29b78305njn}
1766c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1767734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic void ms___builtin_delete ( ThreadId tid, void* p )
1768734b805cb3af82ddd7d3ba22a0e22aba29b78305njn{
1769e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   unrecord_block(p, /*maybe_snapshot*/True);
1770e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   VG_(cli_free)(p);
1771734b805cb3af82ddd7d3ba22a0e22aba29b78305njn}
1772c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1773734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic void ms___builtin_vec_delete ( ThreadId tid, void* p )
1774734b805cb3af82ddd7d3ba22a0e22aba29b78305njn{
1775e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   unrecord_block(p, /*maybe_snapshot*/True);
1776e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   VG_(cli_free)(p);
1777734b805cb3af82ddd7d3ba22a0e22aba29b78305njn}
1778c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1779734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic void* ms_realloc ( ThreadId tid, void* p_old, SizeT new_szB )
1780734b805cb3af82ddd7d3ba22a0e22aba29b78305njn{
1781e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   return realloc_block(tid, p_old, new_szB);
1782734b805cb3af82ddd7d3ba22a0e22aba29b78305njn}
1783c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1784efc13c21199dbb35ad07a5e00d538aa884863c01njnstatic SizeT ms_malloc_usable_size ( ThreadId tid, void* p )
17858b140dee891a850c09d27f316df913acc7d7bae7njn{
17868b140dee891a850c09d27f316df913acc7d7bae7njn   HP_Chunk* hc = VG_(HT_lookup)( malloc_list, (UWord)p );
17878b140dee891a850c09d27f316df913acc7d7bae7njn
17888b140dee891a850c09d27f316df913acc7d7bae7njn   return ( hc ? hc->req_szB + hc->slop_szB : 0 );
17898b140dee891a850c09d27f316df913acc7d7bae7njn}
1790c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1791734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
1792e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn//--- Page handling                                        ---//
1793e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn//------------------------------------------------------------//
1794e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
1795e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjnstatic
1796e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjnvoid ms_record_page_mem ( Addr a, SizeT len )
1797e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn{
1798e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   ThreadId tid = VG_(get_running_tid)();
1799e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   Addr end;
1800e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   tl_assert(VG_IS_PAGE_ALIGNED(len));
1801e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   tl_assert(len >= VKI_PAGE_SIZE);
1802e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   // Record the first N-1 pages as blocks, but don't do any snapshots.
1803e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   for (end = a + len - VKI_PAGE_SIZE; a < end; a += VKI_PAGE_SIZE) {
1804e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      record_block( tid, (void*)a, VKI_PAGE_SIZE, /*slop_szB*/0,
1805e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn                    /*exclude_first_entry*/False, /*maybe_snapshot*/False );
1806e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   }
1807e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   // Record the last page as a block, and maybe do a snapshot afterwards.
1808e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   record_block( tid, (void*)a, VKI_PAGE_SIZE, /*slop_szB*/0,
1809e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn                 /*exclude_first_entry*/False, /*maybe_snapshot*/True );
1810e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn}
1811e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
1812e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjnstatic
1813e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjnvoid ms_unrecord_page_mem( Addr a, SizeT len )
1814e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn{
1815e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   Addr end;
1816e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   tl_assert(VG_IS_PAGE_ALIGNED(len));
1817e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   tl_assert(len >= VKI_PAGE_SIZE);
1818e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   for (end = a + len - VKI_PAGE_SIZE; a < end; a += VKI_PAGE_SIZE) {
1819e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      unrecord_block((void*)a, /*maybe_snapshot*/False);
1820e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   }
1821e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   unrecord_block((void*)a, /*maybe_snapshot*/True);
1822e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn}
1823e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
1824e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn//------------------------------------------------------------//
1825e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
1826e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjnstatic
1827e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjnvoid ms_new_mem_mmap ( Addr a, SizeT len,
1828e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn                       Bool rr, Bool ww, Bool xx, ULong di_handle )
1829e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn{
1830e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   tl_assert(VG_IS_PAGE_ALIGNED(len));
1831e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   ms_record_page_mem(a, len);
1832e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn}
1833e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
1834e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjnstatic
1835e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjnvoid ms_new_mem_startup( Addr a, SizeT len,
1836e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn                         Bool rr, Bool ww, Bool xx, ULong di_handle )
1837e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn{
1838e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   // startup maps are always be page-sized, except the trampoline page is
1839e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   // marked by the core as only being the size of the trampoline itself,
1840e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   // which is something like 57 bytes.  Round it up to page size.
1841e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   len = VG_PGROUNDUP(len);
1842e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   ms_record_page_mem(a, len);
1843e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn}
1844e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
1845e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjnstatic
1846e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjnvoid ms_new_mem_brk ( Addr a, SizeT len, ThreadId tid )
1847e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn{
1848e6a26cc2fd3877993e14b1e3caffeb1324dd23a8philippe   // brk limit is not necessarily aligned on a page boundary.
1849e6a26cc2fd3877993e14b1e3caffeb1324dd23a8philippe   // If new memory being brk-ed implies to allocate a new page,
1850e6a26cc2fd3877993e14b1e3caffeb1324dd23a8philippe   // then call ms_record_page_mem with page aligned parameters
1851e6a26cc2fd3877993e14b1e3caffeb1324dd23a8philippe   // otherwise just ignore.
1852e6a26cc2fd3877993e14b1e3caffeb1324dd23a8philippe   Addr old_bottom_page = VG_PGROUNDDN(a - 1);
1853e6a26cc2fd3877993e14b1e3caffeb1324dd23a8philippe   Addr new_top_page = VG_PGROUNDDN(a + len - 1);
1854e6a26cc2fd3877993e14b1e3caffeb1324dd23a8philippe   if (old_bottom_page != new_top_page)
1855e6a26cc2fd3877993e14b1e3caffeb1324dd23a8philippe      ms_record_page_mem(VG_PGROUNDDN(a),
1856e6a26cc2fd3877993e14b1e3caffeb1324dd23a8philippe                         (new_top_page - old_bottom_page));
1857e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn}
1858e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
1859e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjnstatic
1860e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjnvoid ms_copy_mem_remap( Addr from, Addr to, SizeT len)
1861e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn{
1862e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   tl_assert(VG_IS_PAGE_ALIGNED(len));
1863e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   ms_unrecord_page_mem(from, len);
1864e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   ms_record_page_mem(to, len);
1865e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn}
1866e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
1867e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjnstatic
1868e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjnvoid ms_die_mem_munmap( Addr a, SizeT len )
1869e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn{
1870e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   tl_assert(VG_IS_PAGE_ALIGNED(len));
1871e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   ms_unrecord_page_mem(a, len);
1872e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn}
1873e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
1874e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjnstatic
1875e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjnvoid ms_die_mem_brk( Addr a, SizeT len )
1876e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn{
1877e6a26cc2fd3877993e14b1e3caffeb1324dd23a8philippe   // Call ms_unrecord_page_mem only if one or more pages are de-allocated.
1878e6a26cc2fd3877993e14b1e3caffeb1324dd23a8philippe   // See ms_new_mem_brk for more details.
1879e6a26cc2fd3877993e14b1e3caffeb1324dd23a8philippe   Addr new_bottom_page = VG_PGROUNDDN(a - 1);
1880e6a26cc2fd3877993e14b1e3caffeb1324dd23a8philippe   Addr old_top_page = VG_PGROUNDDN(a + len - 1);
1881e6a26cc2fd3877993e14b1e3caffeb1324dd23a8philippe   if (old_top_page != new_bottom_page)
1882e6a26cc2fd3877993e14b1e3caffeb1324dd23a8philippe      ms_unrecord_page_mem(VG_PGROUNDDN(a),
1883e6a26cc2fd3877993e14b1e3caffeb1324dd23a8philippe                           (old_top_page - new_bottom_page));
1884e6a26cc2fd3877993e14b1e3caffeb1324dd23a8philippe
1885e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn}
1886e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
1887e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn//------------------------------------------------------------//
1888734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//--- Stacks                                               ---//
1889734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
1890c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1891734b805cb3af82ddd7d3ba22a0e22aba29b78305njn// We really want the inlining to occur...
1892734b805cb3af82ddd7d3ba22a0e22aba29b78305njn#define INLINE    inline __attribute__((always_inline))
1893c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1894734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic void update_stack_stats(SSizeT stack_szB_delta)
1895734b805cb3af82ddd7d3ba22a0e22aba29b78305njn{
1896734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (stack_szB_delta < 0) tl_assert(stacks_szB >= -stack_szB_delta);
1897734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   stacks_szB += stack_szB_delta;
1898c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1899734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   update_alloc_stats(stack_szB_delta);
1900734b805cb3af82ddd7d3ba22a0e22aba29b78305njn}
1901c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1902e58e8a7a82f81c9237e7cae9a1b70a31dec67d36florianstatic INLINE void new_mem_stack_2(SizeT len, const HChar* what)
1903734b805cb3af82ddd7d3ba22a0e22aba29b78305njn{
1904734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (have_started_executing_code) {
19055ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj      VERB(3, "<<< new_mem_stack (%ld)\n", len);
1906734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      n_stack_allocs++;
1907734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      update_stack_stats(len);
1908734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      maybe_take_snapshot(Normal, what);
19095ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj      VERB(3, ">>>\n");
1910c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   }
1911734b805cb3af82ddd7d3ba22a0e22aba29b78305njn}
1912c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1913e58e8a7a82f81c9237e7cae9a1b70a31dec67d36florianstatic INLINE void die_mem_stack_2(SizeT len, const HChar* what)
1914734b805cb3af82ddd7d3ba22a0e22aba29b78305njn{
1915734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (have_started_executing_code) {
19165ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj      VERB(3, "<<< die_mem_stack (%ld)\n", -len);
1917734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      n_stack_frees++;
1918734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      maybe_take_snapshot(Peak,   "stkPEAK");
1919734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      update_stack_stats(-len);
1920734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      maybe_take_snapshot(Normal, what);
19215ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj      VERB(3, ">>>\n");
1922c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   }
1923734b805cb3af82ddd7d3ba22a0e22aba29b78305njn}
1924c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1925734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic void new_mem_stack(Addr a, SizeT len)
1926734b805cb3af82ddd7d3ba22a0e22aba29b78305njn{
1927efc13c21199dbb35ad07a5e00d538aa884863c01njn   new_mem_stack_2(len, "stk-new");
1928734b805cb3af82ddd7d3ba22a0e22aba29b78305njn}
1929c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1930734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic void die_mem_stack(Addr a, SizeT len)
1931734b805cb3af82ddd7d3ba22a0e22aba29b78305njn{
1932efc13c21199dbb35ad07a5e00d538aa884863c01njn   die_mem_stack_2(len, "stk-die");
1933734b805cb3af82ddd7d3ba22a0e22aba29b78305njn}
1934c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
19357cf4e6b6aed533af53339f36099ed244dc4a5b7fsewardjstatic void new_mem_stack_signal(Addr a, SizeT len, ThreadId tid)
1936c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
1937efc13c21199dbb35ad07a5e00d538aa884863c01njn   new_mem_stack_2(len, "sig-new");
1938c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
1939c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
19408b5f40c481a89483c1738e5d5e9e718b418948d4nethercotestatic void die_mem_stack_signal(Addr a, SizeT len)
1941c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
1942efc13c21199dbb35ad07a5e00d538aa884863c01njn   die_mem_stack_2(len, "sig-die");
1943c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
1944c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
1945734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
1946734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
1947734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//--- Client Requests                                      ---//
1948734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
1949c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
19503b290486cd4cd601b20e04340e593c9ed9717e5fsewardjstatic void print_monitor_help ( void )
19513b290486cd4cd601b20e04340e593c9ed9717e5fsewardj{
19523b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   VG_(gdb_printf) ("\n");
19533b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   VG_(gdb_printf) ("massif monitor commands:\n");
195430b3eca94e609214d9ac8dabfee9be3f3ab46d85sewardj   VG_(gdb_printf) ("  snapshot [<filename>]\n");
195530b3eca94e609214d9ac8dabfee9be3f3ab46d85sewardj   VG_(gdb_printf) ("  detailed_snapshot [<filename>]\n");
1956868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe   VG_(gdb_printf) ("      takes a snapshot (or a detailed snapshot)\n");
1957868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe   VG_(gdb_printf) ("      and saves it in <filename>\n");
1958868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe   VG_(gdb_printf) ("             default <filename> is massif.vgdb.out\n");
1959868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe   VG_(gdb_printf) ("  all_snapshots [<filename>]\n");
1960868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe   VG_(gdb_printf) ("      saves all snapshot(s) taken so far in <filename>\n");
19613b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   VG_(gdb_printf) ("             default <filename> is massif.vgdb.out\n");
19623b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   VG_(gdb_printf) ("\n");
19633b290486cd4cd601b20e04340e593c9ed9717e5fsewardj}
19643b290486cd4cd601b20e04340e593c9ed9717e5fsewardj
19653b290486cd4cd601b20e04340e593c9ed9717e5fsewardj
19663b290486cd4cd601b20e04340e593c9ed9717e5fsewardj/* Forward declaration.
19673b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   return True if request recognised, False otherwise */
196819f91bbaedb4caef8a60ce94b0f507193cc0bc10florianstatic Bool handle_gdb_monitor_command (ThreadId tid, HChar *req);
196951d827bcd88ce045a383ea1ca81768757df2d1fanjnstatic Bool ms_handle_client_request ( ThreadId tid, UWord* argv, UWord* ret )
1970c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
1971c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   switch (argv[0]) {
1972c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   case VG_USERREQ__MALLOCLIKE_BLOCK: {
1973734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      void* p   = (void*)argv[1];
1974734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      SizeT szB =        argv[2];
1975e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      record_block( tid, p, szB, /*slop_szB*/0, /*exclude_first_entry*/False,
1976e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn                    /*maybe_snapshot*/True );
1977734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      *ret = 0;
1978c9f3692175ba544ecef6f905f5dcd755c3b153benethercote      return True;
1979c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   }
1980913473803432ee37d6edaf232e21978d4f426125bart   case VG_USERREQ__RESIZEINPLACE_BLOCK: {
1981913473803432ee37d6edaf232e21978d4f426125bart      void* p        = (void*)argv[1];
1982913473803432ee37d6edaf232e21978d4f426125bart      SizeT newSizeB =       argv[3];
1983913473803432ee37d6edaf232e21978d4f426125bart
1984913473803432ee37d6edaf232e21978d4f426125bart      unrecord_block(p, /*maybe_snapshot*/True);
1985913473803432ee37d6edaf232e21978d4f426125bart      record_block(tid, p, newSizeB, /*slop_szB*/0,
1986913473803432ee37d6edaf232e21978d4f426125bart                   /*exclude_first_entry*/False, /*maybe_snapshot*/True);
1987913473803432ee37d6edaf232e21978d4f426125bart      return True;
1988913473803432ee37d6edaf232e21978d4f426125bart   }
1989c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   case VG_USERREQ__FREELIKE_BLOCK: {
1990734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      void* p = (void*)argv[1];
1991e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      unrecord_block(p, /*maybe_snapshot*/True);
1992734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      *ret = 0;
1993c9f3692175ba544ecef6f905f5dcd755c3b153benethercote      return True;
1994c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   }
19953b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   case VG_USERREQ__GDB_MONITOR_COMMAND: {
199619f91bbaedb4caef8a60ce94b0f507193cc0bc10florian     Bool handled = handle_gdb_monitor_command (tid, (HChar*)argv[1]);
19973b290486cd4cd601b20e04340e593c9ed9717e5fsewardj     if (handled)
19983b290486cd4cd601b20e04340e593c9ed9717e5fsewardj       *ret = 1;
19993b290486cd4cd601b20e04340e593c9ed9717e5fsewardj     else
20003b290486cd4cd601b20e04340e593c9ed9717e5fsewardj       *ret = 0;
20013b290486cd4cd601b20e04340e593c9ed9717e5fsewardj     return handled;
20023b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   }
20033b290486cd4cd601b20e04340e593c9ed9717e5fsewardj
2004c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   default:
2005c9f3692175ba544ecef6f905f5dcd755c3b153benethercote      *ret = 0;
2006c9f3692175ba544ecef6f905f5dcd755c3b153benethercote      return False;
2007c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   }
2008c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
2009c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
2010734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
2011734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//--- Instrumentation                                      ---//
2012734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
2013c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
20141a2741aad64315cd5da0cc877f474d53af16b5a3njnstatic void add_counter_update(IRSB* sbOut, Int n)
20151a2741aad64315cd5da0cc877f474d53af16b5a3njn{
20161a2741aad64315cd5da0cc877f474d53af16b5a3njn   #if defined(VG_BIGENDIAN)
20171a2741aad64315cd5da0cc877f474d53af16b5a3njn   # define END Iend_BE
20181a2741aad64315cd5da0cc877f474d53af16b5a3njn   #elif defined(VG_LITTLEENDIAN)
20191a2741aad64315cd5da0cc877f474d53af16b5a3njn   # define END Iend_LE
20201a2741aad64315cd5da0cc877f474d53af16b5a3njn   #else
20211a2741aad64315cd5da0cc877f474d53af16b5a3njn   # error "Unknown endianness"
20221a2741aad64315cd5da0cc877f474d53af16b5a3njn   #endif
20231a2741aad64315cd5da0cc877f474d53af16b5a3njn   // Add code to increment 'guest_instrs_executed' by 'n', like this:
20241a2741aad64315cd5da0cc877f474d53af16b5a3njn   //   WrTmp(t1, Load64(&guest_instrs_executed))
20251a2741aad64315cd5da0cc877f474d53af16b5a3njn   //   WrTmp(t2, Add64(RdTmp(t1), Const(n)))
20261a2741aad64315cd5da0cc877f474d53af16b5a3njn   //   Store(&guest_instrs_executed, t2)
20271a2741aad64315cd5da0cc877f474d53af16b5a3njn   IRTemp t1 = newIRTemp(sbOut->tyenv, Ity_I64);
20281a2741aad64315cd5da0cc877f474d53af16b5a3njn   IRTemp t2 = newIRTemp(sbOut->tyenv, Ity_I64);
20291a2741aad64315cd5da0cc877f474d53af16b5a3njn   IRExpr* counter_addr = mkIRExpr_HWord( (HWord)&guest_instrs_executed );
20301a2741aad64315cd5da0cc877f474d53af16b5a3njn
2031db5907d7b94ce492f29a96c95e186fdcda23a149sewardj   IRStmt* st1 = IRStmt_WrTmp(t1, IRExpr_Load(END, Ity_I64, counter_addr));
20321a2741aad64315cd5da0cc877f474d53af16b5a3njn   IRStmt* st2 =
20331a2741aad64315cd5da0cc877f474d53af16b5a3njn      IRStmt_WrTmp(t2,
20341a2741aad64315cd5da0cc877f474d53af16b5a3njn                   IRExpr_Binop(Iop_Add64, IRExpr_RdTmp(t1),
20351a2741aad64315cd5da0cc877f474d53af16b5a3njn                                           IRExpr_Const(IRConst_U64(n))));
2036db5907d7b94ce492f29a96c95e186fdcda23a149sewardj   IRStmt* st3 = IRStmt_Store(END, counter_addr, IRExpr_RdTmp(t2));
20371a2741aad64315cd5da0cc877f474d53af16b5a3njn
20381a2741aad64315cd5da0cc877f474d53af16b5a3njn   addStmtToIRSB( sbOut, st1 );
20391a2741aad64315cd5da0cc877f474d53af16b5a3njn   addStmtToIRSB( sbOut, st2 );
20401a2741aad64315cd5da0cc877f474d53af16b5a3njn   addStmtToIRSB( sbOut, st3 );
20411a2741aad64315cd5da0cc877f474d53af16b5a3njn}
20421a2741aad64315cd5da0cc877f474d53af16b5a3njn
20431a2741aad64315cd5da0cc877f474d53af16b5a3njnstatic IRSB* ms_instrument2( IRSB* sbIn )
20441a2741aad64315cd5da0cc877f474d53af16b5a3njn{
20451a2741aad64315cd5da0cc877f474d53af16b5a3njn   Int   i, n = 0;
20461a2741aad64315cd5da0cc877f474d53af16b5a3njn   IRSB* sbOut;
20471a2741aad64315cd5da0cc877f474d53af16b5a3njn
20481a2741aad64315cd5da0cc877f474d53af16b5a3njn   // We increment the instruction count in two places:
20491a2741aad64315cd5da0cc877f474d53af16b5a3njn   // - just before any Ist_Exit statements;
20501a2741aad64315cd5da0cc877f474d53af16b5a3njn   // - just before the IRSB's end.
20511a2741aad64315cd5da0cc877f474d53af16b5a3njn   // In the former case, we zero 'n' and then continue instrumenting.
20521a2741aad64315cd5da0cc877f474d53af16b5a3njn
20531a2741aad64315cd5da0cc877f474d53af16b5a3njn   sbOut = deepCopyIRSBExceptStmts(sbIn);
20541a2741aad64315cd5da0cc877f474d53af16b5a3njn
20551a2741aad64315cd5da0cc877f474d53af16b5a3njn   for (i = 0; i < sbIn->stmts_used; i++) {
20561a2741aad64315cd5da0cc877f474d53af16b5a3njn      IRStmt* st = sbIn->stmts[i];
20571a2741aad64315cd5da0cc877f474d53af16b5a3njn
20581a2741aad64315cd5da0cc877f474d53af16b5a3njn      if (!st || st->tag == Ist_NoOp) continue;
20591a2741aad64315cd5da0cc877f474d53af16b5a3njn
20601a2741aad64315cd5da0cc877f474d53af16b5a3njn      if (st->tag == Ist_IMark) {
20611a2741aad64315cd5da0cc877f474d53af16b5a3njn         n++;
20621a2741aad64315cd5da0cc877f474d53af16b5a3njn      } else if (st->tag == Ist_Exit) {
20631a2741aad64315cd5da0cc877f474d53af16b5a3njn         if (n > 0) {
20641a2741aad64315cd5da0cc877f474d53af16b5a3njn            // Add an increment before the Exit statement, then reset 'n'.
20651a2741aad64315cd5da0cc877f474d53af16b5a3njn            add_counter_update(sbOut, n);
20661a2741aad64315cd5da0cc877f474d53af16b5a3njn            n = 0;
20671a2741aad64315cd5da0cc877f474d53af16b5a3njn         }
20681a2741aad64315cd5da0cc877f474d53af16b5a3njn      }
20691a2741aad64315cd5da0cc877f474d53af16b5a3njn      addStmtToIRSB( sbOut, st );
20701a2741aad64315cd5da0cc877f474d53af16b5a3njn   }
20711a2741aad64315cd5da0cc877f474d53af16b5a3njn
20721a2741aad64315cd5da0cc877f474d53af16b5a3njn   if (n > 0) {
20731a2741aad64315cd5da0cc877f474d53af16b5a3njn      // Add an increment before the SB end.
20741a2741aad64315cd5da0cc877f474d53af16b5a3njn      add_counter_update(sbOut, n);
20751a2741aad64315cd5da0cc877f474d53af16b5a3njn   }
20761a2741aad64315cd5da0cc877f474d53af16b5a3njn   return sbOut;
20771a2741aad64315cd5da0cc877f474d53af16b5a3njn}
20781a2741aad64315cd5da0cc877f474d53af16b5a3njn
20794ba057cce1d81a949f5a899b5abb99e90a731bccsewardjstatic
20800b9d74abd0a663b530d290b2b788ddeda46e5400sewardjIRSB* ms_instrument ( VgCallbackClosure* closure,
20811a2741aad64315cd5da0cc877f474d53af16b5a3njn                      IRSB* sbIn,
20823c0c94777f547bcb5eadbe8cb4328debf0f51875florian                      const VexGuestLayout* layout,
20833c0c94777f547bcb5eadbe8cb4328debf0f51875florian                      const VexGuestExtents* vge,
20843c0c94777f547bcb5eadbe8cb4328debf0f51875florian                      const VexArchInfo* archinfo_host,
20854ba057cce1d81a949f5a899b5abb99e90a731bccsewardj                      IRType gWordTy, IRType hWordTy )
2086c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
2087734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (! have_started_executing_code) {
2088734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // Do an initial sample to guarantee that we have at least one.
2089734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // We use 'maybe_take_snapshot' instead of 'take_snapshot' to ensure
2090734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // 'maybe_take_snapshot's internal static variables are initialised.
2091734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      have_started_executing_code = True;
2092734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      maybe_take_snapshot(Normal, "startup");
2093c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   }
20941a2741aad64315cd5da0cc877f474d53af16b5a3njn
20951a2741aad64315cd5da0cc877f474d53af16b5a3njn   if      (clo_time_unit == TimeI)  { return ms_instrument2(sbIn); }
20961a2741aad64315cd5da0cc877f474d53af16b5a3njn   else if (clo_time_unit == TimeMS) { return sbIn; }
20971a2741aad64315cd5da0cc877f474d53af16b5a3njn   else if (clo_time_unit == TimeB)  { return sbIn; }
20981a2741aad64315cd5da0cc877f474d53af16b5a3njn   else                              { tl_assert2(0, "bad --time-unit value"); }
2099c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
2100c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
2101c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
2102734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
2103734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//--- Writing snapshots                                    ---//
2104734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
2105c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
210612d2eb58c09505f8b1a171bcdd8352c9713591b4florian#define FP(format, args...) ({ VG_(fprintf)(fp, format, ##args); })
2107b11e5aaab306bbbf5280a3d0efc473664a48a306njn
210812d2eb58c09505f8b1a171bcdd8352c9713591b4florianstatic void pp_snapshot_SXPt(VgFile *fp, SXPt* sxpt, Int depth,
210912d2eb58c09505f8b1a171bcdd8352c9713591b4florian                             HChar* depth_str, Int depth_str_len,
211012d2eb58c09505f8b1a171bcdd8352c9713591b4florian                             SizeT snapshot_heap_szB, SizeT snapshot_total_szB)
2111c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
2112466ed6e1efeab3b32a30a9002622fb03c0686688njn   Int   i, j, n_insig_children_sxpts;
2113734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   SXPt* child = NULL;
2114734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
2115f330ae85d6b6c603dedb10bf1c70606c8df92dd1sewardj   // Used for printing function names.  Is made static to keep it out
2116f330ae85d6b6c603dedb10bf1c70606c8df92dd1sewardj   // of the stack frame -- this function is recursive.  Obviously this
2117f330ae85d6b6c603dedb10bf1c70606c8df92dd1sewardj   // now means its contents are trashed across the recursive call.
2118770a8d23e40b980b5745e59ecb8e4037d81af357florian   const HChar* ip_desc;
2119f330ae85d6b6c603dedb10bf1c70606c8df92dd1sewardj
2120734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   switch (sxpt->tag) {
2121734b805cb3af82ddd7d3ba22a0e22aba29b78305njn    case SigSXPt:
2122734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // Print the SXPt itself.
212384f32b200936319bb716cefb38553c9ac414d30anjn      if (0 == depth) {
2124e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn         if (clo_heap) {
2125e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn            ip_desc =
2126e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn               ( clo_pages_as_heap
2127e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn               ? "(page allocation syscalls) mmap/mremap/brk, --alloc-fns, etc."
2128e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn               : "(heap allocation functions) malloc/new/new[], --alloc-fns, etc."
2129e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn               );
2130e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn         } else {
2131e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn            // XXX: --alloc-fns?
21326bd9dc18c043927c1196caba20a327238a179c42florian
2133ef901ff97a6a31684529a7e8c836087d2ec28026florian            // Nick thinks this case cannot happen. ip_desc would be
21346bd9dc18c043927c1196caba20a327238a179c42florian            // conceptually uninitialised here. Therefore:
21356bd9dc18c043927c1196caba20a327238a179c42florian            tl_assert2(0, "pp_snapshot_SXPt: unexpected");
2136e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn         }
2137c9f3692175ba544ecef6f905f5dcd755c3b153benethercote      } else {
2138734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         // If it's main-or-below-main, we (if appropriate) ignore everything
2139734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         // below it by pretending it has no children.
21406882443ef154bca367bc591287de641e43a9e108njn         if ( ! VG_(clo_show_below_main) ) {
21416882443ef154bca367bc591287de641e43a9e108njn            Vg_FnNameKind kind = VG_(get_fnname_kind_from_IP)(sxpt->Sig.ip);
21426882443ef154bca367bc591287de641e43a9e108njn            if (Vg_FnNameMain == kind || Vg_FnNameBelowMain == kind) {
21436882443ef154bca367bc591287de641e43a9e108njn               sxpt->Sig.n_children = 0;
21446882443ef154bca367bc591287de641e43a9e108njn            }
2145c9f3692175ba544ecef6f905f5dcd755c3b153benethercote         }
21466882443ef154bca367bc591287de641e43a9e108njn
2147734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         // We need the -1 to get the line number right, But I'm not sure why.
2148770a8d23e40b980b5745e59ecb8e4037d81af357florian         ip_desc = VG_(describe_IP)(sxpt->Sig.ip-1, NULL);
2149c9f3692175ba544ecef6f905f5dcd755c3b153benethercote      }
2150466ed6e1efeab3b32a30a9002622fb03c0686688njn
2151466ed6e1efeab3b32a30a9002622fb03c0686688njn      // Do the non-ip_desc part first...
2152466ed6e1efeab3b32a30a9002622fb03c0686688njn      FP("%sn%d: %lu ", depth_str, sxpt->Sig.n_children, sxpt->szB);
2153466ed6e1efeab3b32a30a9002622fb03c0686688njn
2154466ed6e1efeab3b32a30a9002622fb03c0686688njn      // For ip_descs beginning with "0xABCD...:" addresses, we first
2155466ed6e1efeab3b32a30a9002622fb03c0686688njn      // measure the length of the "0xabcd: " address at the start of the
2156466ed6e1efeab3b32a30a9002622fb03c0686688njn      // ip_desc.
2157466ed6e1efeab3b32a30a9002622fb03c0686688njn      j = 0;
2158466ed6e1efeab3b32a30a9002622fb03c0686688njn      if ('0' == ip_desc[0] && 'x' == ip_desc[1]) {
2159466ed6e1efeab3b32a30a9002622fb03c0686688njn         j = 2;
2160466ed6e1efeab3b32a30a9002622fb03c0686688njn         while (True) {
2161466ed6e1efeab3b32a30a9002622fb03c0686688njn            if (ip_desc[j]) {
2162466ed6e1efeab3b32a30a9002622fb03c0686688njn               if (':' == ip_desc[j]) break;
2163466ed6e1efeab3b32a30a9002622fb03c0686688njn               j++;
2164466ed6e1efeab3b32a30a9002622fb03c0686688njn            } else {
2165466ed6e1efeab3b32a30a9002622fb03c0686688njn               tl_assert2(0, "ip_desc has unexpected form: %s\n", ip_desc);
2166466ed6e1efeab3b32a30a9002622fb03c0686688njn            }
2167466ed6e1efeab3b32a30a9002622fb03c0686688njn         }
2168466ed6e1efeab3b32a30a9002622fb03c0686688njn      }
2169770a8d23e40b980b5745e59ecb8e4037d81af357florian      // It used to be that ip_desc was truncated at the end.
2170770a8d23e40b980b5745e59ecb8e4037d81af357florian      // But there does not seem to be a good reason for that. Besides,
2171770a8d23e40b980b5745e59ecb8e4037d81af357florian      // the string was truncated at the right, which is less than ideal.
2172770a8d23e40b980b5745e59ecb8e4037d81af357florian      // Truncation at the beginning of the string would have been preferable.
2173770a8d23e40b980b5745e59ecb8e4037d81af357florian      // Think several nested namespaces in C++....
2174770a8d23e40b980b5745e59ecb8e4037d81af357florian      // Anyhow, we spit out the full-length string now.
2175ef901ff97a6a31684529a7e8c836087d2ec28026florian      FP("%s\n", ip_desc);
2176734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
2177734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // Indent.
2178734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      tl_assert(depth+1 < depth_str_len-1);    // -1 for end NUL char
2179734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      depth_str[depth+0] = ' ';
2180734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      depth_str[depth+1] = '\0';
2181734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
2182734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // Sort SXPt's children by szB (reverse order:  biggest to smallest).
2183734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // Nb: we sort them here, rather than earlier (eg. in dup_XTree), for
2184734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // two reasons.  First, if we do it during dup_XTree, it can get
2185734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // expensive (eg. 15% of execution time for konqueror
2186734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // startup/shutdown).  Second, this way we get the Insig SXPt (if one
2187734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // is present) in its sorted position, not at the end.
2188734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      VG_(ssort)(sxpt->Sig.children, sxpt->Sig.n_children, sizeof(SXPt*),
2189734b805cb3af82ddd7d3ba22a0e22aba29b78305njn                 SXPt_revcmp_szB);
2190734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
2191734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // Print the SXPt's children.  They should already be in sorted order.
2192734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      n_insig_children_sxpts = 0;
2193734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      for (i = 0; i < sxpt->Sig.n_children; i++) {
2194734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         child = sxpt->Sig.children[i];
2195734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
2196734b805cb3af82ddd7d3ba22a0e22aba29b78305njn         if (InsigSXPt == child->tag)
2197734b805cb3af82ddd7d3ba22a0e22aba29b78305njn            n_insig_children_sxpts++;
2198734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
2199770a8d23e40b980b5745e59ecb8e4037d81af357florian         // Ok, print the child.  NB: contents of ip_desc will be
2200f330ae85d6b6c603dedb10bf1c70606c8df92dd1sewardj         // trashed by this recursive call.  Doesn't matter currently,
2201f330ae85d6b6c603dedb10bf1c70606c8df92dd1sewardj         // but worth noting.
220212d2eb58c09505f8b1a171bcdd8352c9713591b4florian         pp_snapshot_SXPt(fp, child, depth+1, depth_str, depth_str_len,
2203734b805cb3af82ddd7d3ba22a0e22aba29b78305njn            snapshot_heap_szB, snapshot_total_szB);
2204c9f3692175ba544ecef6f905f5dcd755c3b153benethercote      }
2205dbeb53581d4595a0513d879ba884b108bd3e571enjn
2206dbeb53581d4595a0513d879ba884b108bd3e571enjn      // Unindent.
2207dbeb53581d4595a0513d879ba884b108bd3e571enjn      depth_str[depth+0] = '\0';
2208dbeb53581d4595a0513d879ba884b108bd3e571enjn      depth_str[depth+1] = '\0';
2209dbeb53581d4595a0513d879ba884b108bd3e571enjn
2210734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // There should be 0 or 1 Insig children SXPts.
2211734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      tl_assert(n_insig_children_sxpts <= 1);
2212734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      break;
2213734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
2214734b805cb3af82ddd7d3ba22a0e22aba29b78305njn    case InsigSXPt: {
2215e58e8a7a82f81c9237e7cae9a1b70a31dec67d36florian      const HChar* s = ( 1 == sxpt->Insig.n_xpts ? "," : "s, all" );
2216227a1ecca7f44cb07e74aa8f1bd24b29df629499florian      FP("%sn0: %lu in %d place%s below massif's threshold (%.2f%%)\n",
2217227a1ecca7f44cb07e74aa8f1bd24b29df629499florian         depth_str, sxpt->szB, sxpt->Insig.n_xpts, s, clo_threshold);
2218734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      break;
2219734b805cb3af82ddd7d3ba22a0e22aba29b78305njn    }
2220734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
2221734b805cb3af82ddd7d3ba22a0e22aba29b78305njn    default:
2222734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      tl_assert2(0, "pp_snapshot_SXPt: unrecognised SXPt tag");
2223c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   }
2224c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
2225c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
222612d2eb58c09505f8b1a171bcdd8352c9713591b4florianstatic void pp_snapshot(VgFile *fp, Snapshot* snapshot, Int snapshot_n)
2227c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
2228734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   sanity_check_snapshot(snapshot);
2229734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
2230734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   FP("#-----------\n");
2231734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   FP("snapshot=%d\n", snapshot_n);
2232734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   FP("#-----------\n");
2233734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   FP("time=%lld\n",            snapshot->time);
2234734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   FP("mem_heap_B=%lu\n",       snapshot->heap_szB);
223532397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn   FP("mem_heap_extra_B=%lu\n", snapshot->heap_extra_szB);
2236734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   FP("mem_stacks_B=%lu\n",     snapshot->stacks_szB);
2237734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
2238734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (is_detailed_snapshot(snapshot)) {
2239734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // Detailed snapshot -- print heap tree.
2240734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      Int   depth_str_len = clo_depth + 3;
224119f91bbaedb4caef8a60ce94b0f507193cc0bc10florian      HChar* depth_str = VG_(malloc)("ms.main.pps.1",
224219f91bbaedb4caef8a60ce94b0f507193cc0bc10florian                                     sizeof(HChar) * depth_str_len);
2243734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      SizeT snapshot_total_szB =
224432397c0c26fd49181e87a409ad986b9e1b5b0dfdnjn         snapshot->heap_szB + snapshot->heap_extra_szB + snapshot->stacks_szB;
2245734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      depth_str[0] = '\0';   // Initialise depth_str to "".
2246734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
2247734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      FP("heap_tree=%s\n", ( Peak == snapshot->kind ? "peak" : "detailed" ));
224812d2eb58c09505f8b1a171bcdd8352c9713591b4florian      pp_snapshot_SXPt(fp, snapshot->alloc_sxpt, 0, depth_str,
2249734b805cb3af82ddd7d3ba22a0e22aba29b78305njn                       depth_str_len, snapshot->heap_szB,
2250734b805cb3af82ddd7d3ba22a0e22aba29b78305njn                       snapshot_total_szB);
2251734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
2252734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      VG_(free)(depth_str);
225343a15ce615589c8a44d19b1b7d1531a04618913anethercote
2254734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   } else {
2255734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      FP("heap_tree=empty\n");
2256734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
2257c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
2258c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
225919f91bbaedb4caef8a60ce94b0f507193cc0bc10florianstatic void write_snapshots_to_file(const HChar* massif_out_file,
22603b290486cd4cd601b20e04340e593c9ed9717e5fsewardj                                    Snapshot snapshots_array[],
22613b290486cd4cd601b20e04340e593c9ed9717e5fsewardj                                    Int nr_elements)
2262c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
226312d2eb58c09505f8b1a171bcdd8352c9713591b4florian   Int i;
226412d2eb58c09505f8b1a171bcdd8352c9713591b4florian   VgFile *fp;
2265c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
226612d2eb58c09505f8b1a171bcdd8352c9713591b4florian   fp = VG_(fopen)(massif_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
226712d2eb58c09505f8b1a171bcdd8352c9713591b4florian                                    VKI_S_IRUSR|VKI_S_IWUSR);
226812d2eb58c09505f8b1a171bcdd8352c9713591b4florian   if (fp == NULL) {
2269734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // If the file can't be opened for whatever reason (conflict
2270734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      // between multiple cachegrinded processes?), give up now.
22715ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj      VG_(umsg)("error: can't open output file '%s'\n", massif_out_file );
22725ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj      VG_(umsg)("       ... so profiling results will be missing.\n");
2273c9f3692175ba544ecef6f905f5dcd755c3b153benethercote      return;
2274c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   }
2275c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
2276734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Print massif-specific options that were used.
2277734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // XXX: is it worth having a "desc:" line?  Could just call it "options:"
2278734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // -- this file format isn't as generic as Cachegrind's, so the
2279734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // implied genericity of "desc:" is bogus.
2280734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   FP("desc:");
2281734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   for (i = 0; i < VG_(sizeXA)(args_for_massif); i++) {
228219f91bbaedb4caef8a60ce94b0f507193cc0bc10florian      HChar* arg = *(HChar**)VG_(indexXA)(args_for_massif, i);
2283734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      FP(" %s", arg);
2284c9f3692175ba544ecef6f905f5dcd755c3b153benethercote   }
2285734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (0 == i) FP(" (none)");
2286734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   FP("\n");
2287c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
2288734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Print "cmd:" line.
2289734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   FP("cmd: ");
2290b16609bf952bf381154cb6cba87efc99c2c86a23florian   FP("%s", VG_(args_the_exename));
2291b16609bf952bf381154cb6cba87efc99c2c86a23florian   for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
2292b16609bf952bf381154cb6cba87efc99c2c86a23florian      HChar* arg = * (HChar**) VG_(indexXA)( VG_(args_for_client), i );
22935980e9df10ed1b0497bc09f4b2fa708b52c9addaflorian      FP(" %s", arg);
2294d111d100b250215516c66f0fceda76815191afa0njn   }
2295734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   FP("\n");
2296c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
2297734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   FP("time_unit: %s\n", TimeUnit_to_string(clo_time_unit));
2298c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
22993b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   for (i = 0; i < nr_elements; i++) {
23003b290486cd4cd601b20e04340e593c9ed9717e5fsewardj      Snapshot* snapshot = & snapshots_array[i];
230112d2eb58c09505f8b1a171bcdd8352c9713591b4florian      pp_snapshot(fp, snapshot, i);     // Detailed snapshot!
2302734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
230312d2eb58c09505f8b1a171bcdd8352c9713591b4florian   VG_(fclose) (fp);
23043b290486cd4cd601b20e04340e593c9ed9717e5fsewardj}
23053b290486cd4cd601b20e04340e593c9ed9717e5fsewardj
23063b290486cd4cd601b20e04340e593c9ed9717e5fsewardjstatic void write_snapshots_array_to_file(void)
23073b290486cd4cd601b20e04340e593c9ed9717e5fsewardj{
23083b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   // Setup output filename.  Nb: it's important to do this now, ie. as late
23093b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   // as possible.  If we do it at start-up and the program forks and the
23103b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   // output file format string contains a %p (pid) specifier, both the
23113b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   // parent and child will incorrectly write to the same file;  this
23123b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   // happened in 3.3.0.
231319f91bbaedb4caef8a60ce94b0f507193cc0bc10florian   HChar* massif_out_file =
23143b290486cd4cd601b20e04340e593c9ed9717e5fsewardj      VG_(expand_file_name)("--massif-out-file", clo_massif_out_file);
23153b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   write_snapshots_to_file (massif_out_file, snapshots, next_snapshot_i);
23163b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   VG_(free)(massif_out_file);
2317c9f3692175ba544ecef6f905f5dcd755c3b153benethercote}
2318c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
231919f91bbaedb4caef8a60ce94b0f507193cc0bc10florianstatic void handle_snapshot_monitor_command (const HChar *filename,
232019f91bbaedb4caef8a60ce94b0f507193cc0bc10florian                                             Bool detailed)
2321d142f99836471d4245250247cc9ac7bc5a1391fasewardj{
2322d142f99836471d4245250247cc9ac7bc5a1391fasewardj   Snapshot snapshot;
2323d142f99836471d4245250247cc9ac7bc5a1391fasewardj
232427c9f0d1a2193440791748efd3821828dff5ff70philippe   if (!clo_pages_as_heap && !have_started_executing_code) {
232527c9f0d1a2193440791748efd3821828dff5ff70philippe      // See comments of variable have_started_executing_code.
232627c9f0d1a2193440791748efd3821828dff5ff70philippe      VG_(gdb_printf)
232727c9f0d1a2193440791748efd3821828dff5ff70philippe         ("error: cannot take snapshot before execution has started\n");
232827c9f0d1a2193440791748efd3821828dff5ff70philippe      return;
232927c9f0d1a2193440791748efd3821828dff5ff70philippe   }
233027c9f0d1a2193440791748efd3821828dff5ff70philippe
2331d142f99836471d4245250247cc9ac7bc5a1391fasewardj   clear_snapshot(&snapshot, /* do_sanity_check */ False);
2332d142f99836471d4245250247cc9ac7bc5a1391fasewardj   take_snapshot(&snapshot, Normal, get_time(), detailed);
233327c9f0d1a2193440791748efd3821828dff5ff70philippe   write_snapshots_to_file ((filename == NULL) ?
233419f91bbaedb4caef8a60ce94b0f507193cc0bc10florian                            "massif.vgdb.out" : filename,
2335d142f99836471d4245250247cc9ac7bc5a1391fasewardj                            &snapshot,
2336d142f99836471d4245250247cc9ac7bc5a1391fasewardj                            1);
2337d142f99836471d4245250247cc9ac7bc5a1391fasewardj   delete_snapshot(&snapshot);
2338d142f99836471d4245250247cc9ac7bc5a1391fasewardj}
2339d142f99836471d4245250247cc9ac7bc5a1391fasewardj
2340868bfa276b0c84071cf9bd00f1958ba4c53397aephilippestatic void handle_all_snapshots_monitor_command (const HChar *filename)
2341868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe{
2342868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe   if (!clo_pages_as_heap && !have_started_executing_code) {
2343868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe      // See comments of variable have_started_executing_code.
2344868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe      VG_(gdb_printf)
2345868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe         ("error: cannot take snapshot before execution has started\n");
2346868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe      return;
2347868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe   }
2348868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe
2349868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe   write_snapshots_to_file ((filename == NULL) ?
2350868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe                            "massif.vgdb.out" : filename,
2351868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe                            snapshots, next_snapshot_i);
2352868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe}
2353868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe
235419f91bbaedb4caef8a60ce94b0f507193cc0bc10florianstatic Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
23553b290486cd4cd601b20e04340e593c9ed9717e5fsewardj{
235619f91bbaedb4caef8a60ce94b0f507193cc0bc10florian   HChar* wcmd;
2357c29761f54236f27d3bb3663998121bf1c7cbec8cdejanj   HChar s[VG_(strlen(req)) + 1]; /* copy for strtok_r */
235819f91bbaedb4caef8a60ce94b0f507193cc0bc10florian   HChar *ssaveptr;
23593b290486cd4cd601b20e04340e593c9ed9717e5fsewardj
23603b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   VG_(strcpy) (s, req);
23613b290486cd4cd601b20e04340e593c9ed9717e5fsewardj
23623b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   wcmd = VG_(strtok_r) (s, " ", &ssaveptr);
2363868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe   switch (VG_(keyword_id) ("help snapshot detailed_snapshot all_snapshots",
23643b290486cd4cd601b20e04340e593c9ed9717e5fsewardj                            wcmd, kwd_report_duplicated_matches)) {
23653b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   case -2: /* multiple matches */
23663b290486cd4cd601b20e04340e593c9ed9717e5fsewardj      return True;
23673b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   case -1: /* not found */
23683b290486cd4cd601b20e04340e593c9ed9717e5fsewardj      return False;
23693b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   case  0: /* help */
23703b290486cd4cd601b20e04340e593c9ed9717e5fsewardj      print_monitor_help();
23713b290486cd4cd601b20e04340e593c9ed9717e5fsewardj      return True;
237230b3eca94e609214d9ac8dabfee9be3f3ab46d85sewardj   case  1: { /* snapshot */
237319f91bbaedb4caef8a60ce94b0f507193cc0bc10florian      HChar* filename;
2374d142f99836471d4245250247cc9ac7bc5a1391fasewardj      filename = VG_(strtok_r) (NULL, " ", &ssaveptr);
2375d142f99836471d4245250247cc9ac7bc5a1391fasewardj      handle_snapshot_monitor_command (filename, False /* detailed */);
2376d142f99836471d4245250247cc9ac7bc5a1391fasewardj      return True;
2377d142f99836471d4245250247cc9ac7bc5a1391fasewardj   }
237830b3eca94e609214d9ac8dabfee9be3f3ab46d85sewardj   case  2: { /* detailed_snapshot */
237919f91bbaedb4caef8a60ce94b0f507193cc0bc10florian      HChar* filename;
2380d142f99836471d4245250247cc9ac7bc5a1391fasewardj      filename = VG_(strtok_r) (NULL, " ", &ssaveptr);
2381d142f99836471d4245250247cc9ac7bc5a1391fasewardj      handle_snapshot_monitor_command (filename, True /* detailed */);
23823b290486cd4cd601b20e04340e593c9ed9717e5fsewardj      return True;
23833b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   }
2384868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe   case  3: { /* all_snapshots */
2385868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe      HChar* filename;
2386868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe      filename = VG_(strtok_r) (NULL, " ", &ssaveptr);
2387868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe      handle_all_snapshots_monitor_command (filename);
2388868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe      return True;
2389868bfa276b0c84071cf9bd00f1958ba4c53397aephilippe   }
23903b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   default:
23913b290486cd4cd601b20e04340e593c9ed9717e5fsewardj      tl_assert(0);
23923b290486cd4cd601b20e04340e593c9ed9717e5fsewardj      return False;
23933b290486cd4cd601b20e04340e593c9ed9717e5fsewardj   }
23943b290486cd4cd601b20e04340e593c9ed9717e5fsewardj}
2395c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
2396f066315b49748c77424220bb822f603120bdf139philippestatic void ms_print_stats (void)
2397c9f3692175ba544ecef6f905f5dcd755c3b153benethercote{
2398f066315b49748c77424220bb822f603120bdf139philippe#define STATS(format, args...) \
2399f066315b49748c77424220bb822f603120bdf139philippe      VG_(dmsg)("Massif: " format, ##args)
2400734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
24012d9e874b7a628ada216f09cc4f065798c65fffa4sewardj   STATS("heap allocs:           %u\n", n_heap_allocs);
24022d9e874b7a628ada216f09cc4f065798c65fffa4sewardj   STATS("heap reallocs:         %u\n", n_heap_reallocs);
24032d9e874b7a628ada216f09cc4f065798c65fffa4sewardj   STATS("heap frees:            %u\n", n_heap_frees);
24042d9e874b7a628ada216f09cc4f065798c65fffa4sewardj   STATS("ignored heap allocs:   %u\n", n_ignored_heap_allocs);
24052d9e874b7a628ada216f09cc4f065798c65fffa4sewardj   STATS("ignored heap frees:    %u\n", n_ignored_heap_frees);
24062d9e874b7a628ada216f09cc4f065798c65fffa4sewardj   STATS("ignored heap reallocs: %u\n", n_ignored_heap_reallocs);
24072d9e874b7a628ada216f09cc4f065798c65fffa4sewardj   STATS("stack allocs:          %u\n", n_stack_allocs);
24082d9e874b7a628ada216f09cc4f065798c65fffa4sewardj   STATS("stack frees:           %u\n", n_stack_frees);
24092d9e874b7a628ada216f09cc4f065798c65fffa4sewardj   STATS("XPts:                  %u\n", n_xpts);
24102d9e874b7a628ada216f09cc4f065798c65fffa4sewardj   STATS("top-XPts:              %u (%d%%)\n",
2411734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      alloc_xpt->n_children,
2412734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      ( n_xpts ? alloc_xpt->n_children * 100 / n_xpts : 0));
24132d9e874b7a628ada216f09cc4f065798c65fffa4sewardj   STATS("XPt init expansions:   %u\n", n_xpt_init_expansions);
24142d9e874b7a628ada216f09cc4f065798c65fffa4sewardj   STATS("XPt later expansions:  %u\n", n_xpt_later_expansions);
24152d9e874b7a628ada216f09cc4f065798c65fffa4sewardj   STATS("SXPt allocs:           %u\n", n_sxpt_allocs);
24162d9e874b7a628ada216f09cc4f065798c65fffa4sewardj   STATS("SXPt frees:            %u\n", n_sxpt_frees);
24172d9e874b7a628ada216f09cc4f065798c65fffa4sewardj   STATS("skipped snapshots:     %u\n", n_skipped_snapshots);
24182d9e874b7a628ada216f09cc4f065798c65fffa4sewardj   STATS("real snapshots:        %u\n", n_real_snapshots);
24192d9e874b7a628ada216f09cc4f065798c65fffa4sewardj   STATS("detailed snapshots:    %u\n", n_detailed_snapshots);
24202d9e874b7a628ada216f09cc4f065798c65fffa4sewardj   STATS("peak snapshots:        %u\n", n_peak_snapshots);
24212d9e874b7a628ada216f09cc4f065798c65fffa4sewardj   STATS("cullings:              %u\n", n_cullings);
24222d9e874b7a628ada216f09cc4f065798c65fffa4sewardj   STATS("XCon redos:            %u\n", n_XCon_redos);
2423f066315b49748c77424220bb822f603120bdf139philippe#undef STATS
2424f066315b49748c77424220bb822f603120bdf139philippe}
2425f066315b49748c77424220bb822f603120bdf139philippe
2426f066315b49748c77424220bb822f603120bdf139philippe//------------------------------------------------------------//
2427f066315b49748c77424220bb822f603120bdf139philippe//--- Finalisation                                         ---//
2428f066315b49748c77424220bb822f603120bdf139philippe//------------------------------------------------------------//
2429f066315b49748c77424220bb822f603120bdf139philippe
2430f066315b49748c77424220bb822f603120bdf139philippestatic void ms_fini(Int exit_status)
2431f066315b49748c77424220bb822f603120bdf139philippe{
2432f066315b49748c77424220bb822f603120bdf139philippe   // Output.
2433f066315b49748c77424220bb822f603120bdf139philippe   write_snapshots_array_to_file();
2434f066315b49748c77424220bb822f603120bdf139philippe
2435f066315b49748c77424220bb822f603120bdf139philippe   // Stats
2436f066315b49748c77424220bb822f603120bdf139philippe   tl_assert(n_xpts > 0);  // always have alloc_xpt
2437f066315b49748c77424220bb822f603120bdf139philippe
2438f066315b49748c77424220bb822f603120bdf139philippe   if (VG_(clo_stats))
2439f066315b49748c77424220bb822f603120bdf139philippe      ms_print_stats();
2440734b805cb3af82ddd7d3ba22a0e22aba29b78305njn}
2441c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
2442c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
2443734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
2444734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//--- Initialisation                                       ---//
2445734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//------------------------------------------------------------//
2446c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
2447734b805cb3af82ddd7d3ba22a0e22aba29b78305njnstatic void ms_post_clo_init(void)
2448734b805cb3af82ddd7d3ba22a0e22aba29b78305njn{
2449734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   Int i;
245019f91bbaedb4caef8a60ce94b0f507193cc0bc10florian   HChar* LD_PRELOAD_val;
245119f91bbaedb4caef8a60ce94b0f507193cc0bc10florian   HChar* s;
245219f91bbaedb4caef8a60ce94b0f507193cc0bc10florian   HChar* s2;
2453c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
2454734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Check options.
2455e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   if (clo_pages_as_heap) {
2456e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      if (clo_stacks) {
24575b99e6669a0b2a925bb3fb2604259cc317963b6dflorian         VG_(fmsg_bad_option)("--pages-as-heap=yes",
24585b99e6669a0b2a925bb3fb2604259cc317963b6dflorian            "Cannot be used together with --stacks=yes");
2459e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      }
2460e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   }
2461734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (!clo_heap) {
2462e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      clo_pages_as_heap = False;
2463e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   }
2464e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
2465e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   // If --pages-as-heap=yes we don't want malloc replacement to occur.  So we
2466e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   // disable vgpreload_massif-$PLATFORM.so by removing it from LD_PRELOAD (or
2467e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   // platform-equivalent).  We replace it entirely with spaces because then
2468e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   // the linker doesn't complain (it does complain if we just change the name
2469e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   // to a bogus file).  This is a bit of a hack, but LD_PRELOAD is setup well
2470e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   // before tool initialisation, so this seems the best way to do it.
2471e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   if (clo_pages_as_heap) {
2472e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      clo_heap_admin = 0;     // No heap admin on pages.
2473e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
247419f91bbaedb4caef8a60ce94b0f507193cc0bc10florian      LD_PRELOAD_val = VG_(getenv)( VG_(LD_PRELOAD_var_name) );
2475e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      tl_assert(LD_PRELOAD_val);
2476e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
2477e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      // Make sure the vgpreload_core-$PLATFORM entry is there, for sanity.
2478e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      s2 = VG_(strstr)(LD_PRELOAD_val, "vgpreload_core");
2479e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      tl_assert(s2);
2480e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
2481e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      // Now find the vgpreload_massif-$PLATFORM entry.
2482e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      s2 = VG_(strstr)(LD_PRELOAD_val, "vgpreload_massif");
2483e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      tl_assert(s2);
2484e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
2485e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      // Blank out everything to the previous ':', which must be there because
2486e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      // of the preceding vgpreload_core-$PLATFORM entry.
2487e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      for (s = s2; *s != ':'; s--) {
2488e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn         *s = ' ';
2489e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      }
2490e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
2491e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      // Blank out everything to the end of the entry, which will be '\0' if
2492e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      // LD_PRELOAD was empty before Valgrind started, or ':' otherwise.
2493e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      for (s = s2; *s != ':' && *s != '\0'; s++) {
2494e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn         *s = ' ';
2495e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      }
2496734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
2497c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
2498f6b0076ba64f5c22f9e09be70c351a9d4b095883njn   // Print alloc-fns and ignore-fns, if necessary.
2499734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (VG_(clo_verbosity) > 1) {
25005ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj      VERB(1, "alloc-fns:\n");
2501734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      for (i = 0; i < VG_(sizeXA)(alloc_fns); i++) {
250219f91bbaedb4caef8a60ce94b0f507193cc0bc10florian         HChar** fn_ptr = VG_(indexXA)(alloc_fns, i);
25035ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj         VERB(1, "  %s\n", *fn_ptr);
2504f6b0076ba64f5c22f9e09be70c351a9d4b095883njn      }
2505f6b0076ba64f5c22f9e09be70c351a9d4b095883njn
25065ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj      VERB(1, "ignore-fns:\n");
2507f6b0076ba64f5c22f9e09be70c351a9d4b095883njn      if (0 == VG_(sizeXA)(ignore_fns)) {
25085ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj         VERB(1, "  <empty>\n");
2509f6b0076ba64f5c22f9e09be70c351a9d4b095883njn      }
2510f6b0076ba64f5c22f9e09be70c351a9d4b095883njn      for (i = 0; i < VG_(sizeXA)(ignore_fns); i++) {
251119f91bbaedb4caef8a60ce94b0f507193cc0bc10florian         HChar** fn_ptr = VG_(indexXA)(ignore_fns, i);
25125ea0f390fb3f7bf1a618d03b6144dc50b4ae96b8sewardj         VERB(1, "  %d: %s\n", i, *fn_ptr);
2513734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      }
2514734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
251551d827bcd88ce045a383ea1ca81768757df2d1fanjn
2516734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Events to track.
2517734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   if (clo_stacks) {
2518734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      VG_(track_new_mem_stack)        ( new_mem_stack        );
2519734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      VG_(track_die_mem_stack)        ( die_mem_stack        );
2520734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      VG_(track_new_mem_stack_signal) ( new_mem_stack_signal );
2521734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      VG_(track_die_mem_stack_signal) ( die_mem_stack_signal );
2522734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
252351d827bcd88ce045a383ea1ca81768757df2d1fanjn
2524e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   if (clo_pages_as_heap) {
2525e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      VG_(track_new_mem_startup) ( ms_new_mem_startup );
2526e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      VG_(track_new_mem_brk)     ( ms_new_mem_brk     );
2527e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      VG_(track_new_mem_mmap)    ( ms_new_mem_mmap    );
2528e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
2529e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      VG_(track_copy_mem_remap)  ( ms_copy_mem_remap  );
2530e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
2531e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      VG_(track_die_mem_brk)     ( ms_die_mem_brk     );
2532e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn      VG_(track_die_mem_munmap)  ( ms_die_mem_munmap  );
2533e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn   }
2534e323a6bf5d28a9fe6f3dae9b3f02b9ccd25fc7ecnjn
2535734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Initialise snapshot array, and sanity-check it.
25369c606bd8634cd6b67bb41fa645b5c639668cfa2dsewardj   snapshots = VG_(malloc)("ms.main.mpoci.1",
25379c606bd8634cd6b67bb41fa645b5c639668cfa2dsewardj                           sizeof(Snapshot) * clo_max_snapshots);
2538734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // We don't want to do snapshot sanity checks here, because they're
2539734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // currently uninitialised.
2540734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   for (i = 0; i < clo_max_snapshots; i++) {
2541734b805cb3af82ddd7d3ba22a0e22aba29b78305njn      clear_snapshot( & snapshots[i], /*do_sanity_check*/False );
2542734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   }
2543734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   sanity_check_snapshots_array();
254451d827bcd88ce045a383ea1ca81768757df2d1fanjn}
254551d827bcd88ce045a383ea1ca81768757df2d1fanjn
2546151a639d523a1d9b4cbd6629992e48ed8ee9408etomstatic void ms_pre_clo_init(void)
2547734b805cb3af82ddd7d3ba22a0e22aba29b78305njn{
254851d827bcd88ce045a383ea1ca81768757df2d1fanjn   VG_(details_name)            ("Massif");
254951d827bcd88ce045a383ea1ca81768757df2d1fanjn   VG_(details_version)         (NULL);
25501a2741aad64315cd5da0cc877f474d53af16b5a3njn   VG_(details_description)     ("a heap profiler");
25519a0cba4e767f487c2abaa35f95a3452d6bd0ff66njn   VG_(details_copyright_author)(
25520f157ddb404bcde7815a1c5bf2d7e41c114f3d73sewardj      "Copyright (C) 2003-2013, and GNU GPL'd, by Nicholas Nethercote");
255351d827bcd88ce045a383ea1ca81768757df2d1fanjn   VG_(details_bug_reports_to)  (VG_BUGS_TO);
255451d827bcd88ce045a383ea1ca81768757df2d1fanjn
25551e0fff690e9c571275e8025eb2dcff7bf29b53afsewardj   VG_(details_avg_translation_sizeB) ( 330 );
25561e0fff690e9c571275e8025eb2dcff7bf29b53afsewardj
25578d47a61e503b69ffbc783717f5faf09d0bbc4723sewardj   VG_(clo_vex_control).iropt_register_updates_default
25588d47a61e503b69ffbc783717f5faf09d0bbc4723sewardj      = VG_(clo_px_file_backed)
25595b240c20b48c86955e574d5880a145927c60a686philippe      = VexRegUpdSpAtMemAccess; // overridable by the user.
25605b240c20b48c86955e574d5880a145927c60a686philippe
2561f6b0076ba64f5c22f9e09be70c351a9d4b095883njn   // Basic functions.
256251d827bcd88ce045a383ea1ca81768757df2d1fanjn   VG_(basic_tool_funcs)          (ms_post_clo_init,
256351d827bcd88ce045a383ea1ca81768757df2d1fanjn                                   ms_instrument,
256451d827bcd88ce045a383ea1ca81768757df2d1fanjn                                   ms_fini);
256551d827bcd88ce045a383ea1ca81768757df2d1fanjn
2566f6b0076ba64f5c22f9e09be70c351a9d4b095883njn   // Needs.
256751d827bcd88ce045a383ea1ca81768757df2d1fanjn   VG_(needs_libc_freeres)();
256851d827bcd88ce045a383ea1ca81768757df2d1fanjn   VG_(needs_command_line_options)(ms_process_cmd_line_option,
256951d827bcd88ce045a383ea1ca81768757df2d1fanjn                                   ms_print_usage,
257051d827bcd88ce045a383ea1ca81768757df2d1fanjn                                   ms_print_debug_usage);
257151d827bcd88ce045a383ea1ca81768757df2d1fanjn   VG_(needs_client_requests)     (ms_handle_client_request);
2572734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   VG_(needs_sanity_checks)       (ms_cheap_sanity_check,
2573734b805cb3af82ddd7d3ba22a0e22aba29b78305njn                                   ms_expensive_sanity_check);
2574f066315b49748c77424220bb822f603120bdf139philippe   VG_(needs_print_stats)         (ms_print_stats);
2575fc51f8d9538eda285c2ea0974f29b075168f3433njn   VG_(needs_malloc_replacement)  (ms_malloc,
257651d827bcd88ce045a383ea1ca81768757df2d1fanjn                                   ms___builtin_new,
257751d827bcd88ce045a383ea1ca81768757df2d1fanjn                                   ms___builtin_vec_new,
257851d827bcd88ce045a383ea1ca81768757df2d1fanjn                                   ms_memalign,
257951d827bcd88ce045a383ea1ca81768757df2d1fanjn                                   ms_calloc,
258051d827bcd88ce045a383ea1ca81768757df2d1fanjn                                   ms_free,
258151d827bcd88ce045a383ea1ca81768757df2d1fanjn                                   ms___builtin_delete,
258251d827bcd88ce045a383ea1ca81768757df2d1fanjn                                   ms___builtin_vec_delete,
258351d827bcd88ce045a383ea1ca81768757df2d1fanjn                                   ms_realloc,
25848b140dee891a850c09d27f316df913acc7d7bae7njn                                   ms_malloc_usable_size,
258551d827bcd88ce045a383ea1ca81768757df2d1fanjn                                   0 );
258651d827bcd88ce045a383ea1ca81768757df2d1fanjn
2587f6b0076ba64f5c22f9e09be70c351a9d4b095883njn   // HP_Chunks.
2588734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   malloc_list = VG_(HT_construct)( "Massif's malloc list" );
258951d827bcd88ce045a383ea1ca81768757df2d1fanjn
259051d827bcd88ce045a383ea1ca81768757df2d1fanjn   // Dummy node at top of the context structure.
2591734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   alloc_xpt = new_XPt(/*ip*/0, /*parent*/NULL);
2592734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
2593f6b0076ba64f5c22f9e09be70c351a9d4b095883njn   // Initialise alloc_fns and ignore_fns.
2594734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   init_alloc_fns();
2595f6b0076ba64f5c22f9e09be70c351a9d4b095883njn   init_ignore_fns();
2596734b805cb3af82ddd7d3ba22a0e22aba29b78305njn
2597734b805cb3af82ddd7d3ba22a0e22aba29b78305njn   // Initialise args_for_massif.
25989c606bd8634cd6b67bb41fa645b5c639668cfa2dsewardj   args_for_massif = VG_(newXA)(VG_(malloc), "ms.main.mprci.1",
25999c606bd8634cd6b67bb41fa645b5c639668cfa2dsewardj                                VG_(free), sizeof(HChar*));
260051d827bcd88ce045a383ea1ca81768757df2d1fanjn}
260151d827bcd88ce045a383ea1ca81768757df2d1fanjn
260245f4e7c91119c7d01a59f5e827c67841632c9314sewardjVG_DETERMINE_INTERFACE_VERSION(ms_pre_clo_init)
2603c9f3692175ba544ecef6f905f5dcd755c3b153benethercote
2604734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//--------------------------------------------------------------------//
2605734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//--- end                                                          ---//
2606734b805cb3af82ddd7d3ba22a0e22aba29b78305njn//--------------------------------------------------------------------//
2607