1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--------------------------------------------------------------------*/
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--- Massif: a heap profiling tool.                     ms_main.c ---*/
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--------------------------------------------------------------------*/
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This file is part of Massif, a Valgrind tool for profiling memory
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   usage of programs.
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Copyright (C) 2003-2011 Nicholas Nethercote
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      njn@valgrind.org
11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is free software; you can redistribute it and/or
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modify it under the terms of the GNU General Public License as
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   published by the Free Software Foundation; either version 2 of the
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   License, or (at your option) any later version.
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is distributed in the hope that it will be useful, but
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WITHOUT ANY WARRANTY; without even the implied warranty of
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   General Public License for more details.
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   You should have received a copy of the GNU General Public License
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   along with this program; if not, write to the Free Software
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   02111-1307, USA.
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The GNU General Public License is contained in the file COPYING.
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//---------------------------------------------------------------------------
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// XXX:
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//---------------------------------------------------------------------------
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Todo -- nice, but less critical:
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - do a graph-drawing test
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - make file format more generic.  Obstacles:
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   - unit prefixes are not generic
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   - preset column widths for stats are not generic
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   - preset column headers are not generic
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   - "Massif arguments:" line is not generic
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - do snapshots on client requests
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   - (Michael Meeks): have an interactive way to request a dump
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//     (callgrind_control-style)
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//     - "profile now"
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//     - "show me the extra allocations since the last snapshot"
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//     - "start/stop logging" (eg. quickly skip boring bits)
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - Add ability to draw multiple graphs, eg. heap-only, stack-only, total.
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   Give each graph a title.  (try to do it generically!)
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - allow truncation of long fnnames if the exact line number is
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   identified?  [hmm, could make getting the name of alloc-fns more
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   difficult] [could dump full names to file, truncate in ms_print]
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - make --show-below-main=no work
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - Options like --alloc-fn='operator new(unsigned, std::nothrow_t const&)'
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   don't work in a .valgrindrc file or in $VALGRIND_OPTS.
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   m_commandline.c:add_args_from_string() needs to respect single quotes.
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - With --stack=yes, want to add a stack trace for detailed snapshots so
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   it's clear where/why the peak is occurring. (Mattieu Castet)  Also,
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   possibly useful even with --stack=no? (Andi Yin)
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Performance:
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - To run the benchmarks:
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//     perl perf/vg_perf --tools=massif --reps=3 perf/{heap,tinycc} massif
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//     time valgrind --tool=massif --depth=100 konqueror
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   The other benchmarks don't do much allocation, and so give similar speeds
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   to Nulgrind.
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   Timing results on 'nevermore' (njn's machine) as of r7013:
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//     heap      0.53s  ma:12.4s (23.5x, -----)
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//     tinycc    0.46s  ma: 4.9s (10.7x, -----)
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//     many-xpts 0.08s  ma: 2.0s (25.0x, -----)
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//     konqueror 29.6s real  0:21.0s user
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   [Introduction of --time-unit=i as the default slowed things down by
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   roughly 0--20%.]
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - get_XCon accounts for about 9% of konqueror startup time.  Try
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   keeping XPt children sorted by 'ip' and use binary search in get_XCon.
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   Requires factoring out binary search code from various places into a
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   VG_(bsearch) function.
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Todo -- low priority:
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - In each XPt, record both bytes and the number of allocations, and
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   possibly the global number of allocations.
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - (Andy Lin) Give a stack trace on detailed snapshots?
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - (Artur Wisz) add a feature to Massif to ignore any heap blocks larger
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   than a certain size!  Because: "linux's malloc allows to set a
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   MMAP_THRESHOLD value, so we set it to 4096 - all blocks above that will
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   be handled directly by the kernel, and are guaranteed to be returned to
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   the system when freed. So we needed to profile only blocks below this
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   limit."
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// File format working notes:
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if 0
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browndesc: --heap-admin=foo
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browncmd: date
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntime_unit: ms
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#-----------
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsnapshot=0
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#-----------
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntime=0
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmem_heap_B=0
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmem_heap_admin_B=0
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmem_stacks_B=0
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownheap_tree=empty
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#-----------
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsnapshot=1
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#-----------
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntime=353
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmem_heap_B=5
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmem_heap_admin_B=0
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmem_stacks_B=0
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownheap_tree=detailed
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownn1: 5 (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown n1: 5 0x27F6E0: _nl_normalize_codeset (in /lib/libc-2.3.5.so)
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  n1: 5 0x279DE6: _nl_load_locale_from_archive (in /lib/libc-2.3.5.so)
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n1: 5 0x278E97: _nl_find_locale (in /lib/libc-2.3.5.so)
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    n1: 5 0x278871: setlocale (in /lib/libc-2.3.5.so)
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     n1: 5 0x8049821: (within /bin/date)
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n0: 5 0x26ED5E: (below main) (in /lib/libc-2.3.5.so)
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownn_events: n  time(ms)  total(B)    useful-heap(B)  admin-heap(B)  stacks(B)
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownt_events: B
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownn 0 0 0 0 0
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownn 0 0 0 0 0
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownt1: 5 <string...>
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown t1: 6 <string...>
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownIdeas:
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown- each snapshot specifies an x-axis value and one or more y-axis values.
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown- can display the y-axis values separately if you like
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown- can completely separate connection between snapshots and trees.
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownChallenges:
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown- how to specify and scale/abbreviate units on axes?
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown- how to combine multiple values into the y-axis?
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown--------------------------------------------------------------------------------Command:            date
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownMassif arguments:   --heap-admin=foo
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownms_print arguments: massif.out
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown--------------------------------------------------------------------------------
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    KB
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown6.472^                                                       :#
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     |                                                       :#  ::  .    .
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     ...
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     |                                     ::@  :@    :@ :@:::#  ::  :    ::::
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   0 +-----------------------------------@---@---@-----@--@---#-------------->ms     0                                                                     713
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownNumber of snapshots: 50
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Detailed snapshots: [2, 11, 13, 19, 25, 32 (peak)]
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown--------------------------------------------------------------------------------  n       time(ms)         total(B)   useful-heap(B) admin-heap(B)    stacks(B)
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown--------------------------------------------------------------------------------  0              0                0                0             0            0
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  1            345                5                5             0            0
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  2            353                5                5             0            0
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown100.00% (5B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown->100.00% (5B) 0x27F6E0: _nl_normalize_codeset (in /lib/libc-2.3.5.so)
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//---------------------------------------------------------------------------
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_basics.h"
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_vki.h"
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_aspacemgr.h"
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_debuginfo.h"
168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_hashtable.h"
169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcbase.h"
170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcassert.h"
171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcfile.h"
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcprint.h"
173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcproc.h"
174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_machine.h"
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_mallocfree.h"
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_options.h"
177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_replacemalloc.h"
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_stacktrace.h"
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_threadstate.h"
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_tooliface.h"
181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_xarray.h"
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_clientstate.h"
183b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include "pub_tool_gdbserver.h"
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "valgrind.h"           // For {MALLOC,FREE}LIKE_BLOCK
186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------*/
188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--- Overview of operation                                ---*/
189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------*/
190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// The size of the stacks and heap is tracked.  The heap is tracked in a lot
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// of detail, enough to tell how many bytes each line of code is responsible
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// for, more or less.  The main data structure is a tree representing the
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// call tree beneath all the allocation functions like malloc().
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// (Alternatively, if --pages-as-heap=yes is specified, memory is tracked at
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// the page level, and each page is treated much like a heap block.  We use
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// "heap" throughout below to cover this case because the concepts are all the
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// same.)
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// "Snapshots" are recordings of the memory usage.  There are two basic
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// kinds:
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - Normal:  these record the current time, total memory size, total heap
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   size, heap admin size and stack size.
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - Detailed: these record those things in a normal snapshot, plus a very
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   detailed XTree (see below) indicating how the heap is structured.
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Snapshots are taken every so often.  There are two storage classes of
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// snapshots:
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - Temporary:  Massif does a temporary snapshot every so often.  The idea
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   is to always have a certain number of temporary snapshots around.  So
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   we take them frequently to begin with, but decreasingly often as the
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   program continues to run.  Also, we remove some old ones after a while.
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   Overall it's a kind of exponential decay thing.  Most of these are
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   normal snapshots, a small fraction are detailed snapshots.
215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - Permanent:  Massif takes a permanent (detailed) snapshot in some
216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   circumstances.  They are:
217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   - Peak snapshot:  When the memory usage peak is reached, it takes a
218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//     snapshot.  It keeps this, unless the peak is subsequently exceeded,
219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//     in which case it will overwrite the peak snapshot.
220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   - User-requested snapshots:  These are done in response to client
221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//     requests.  They are always kept.
222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Used for printing things when clo_verbosity > 1.
224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define VERB(verb, format, args...) \
225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_verbosity) > verb) { \
226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(dmsg)("Massif: " format, ##args); \
227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Used for printing stats when clo_stats == True.
230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define STATS(format, args...) \
231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_stats)) { \
232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(dmsg)("Massif: " format, ##args); \
233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--- Statistics                                           ---//
237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Konqueror startup, to give an idea of the numbers involved with a biggish
240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// program, with default depth:
241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//  depth=3                   depth=40
243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//  - 310,000 allocations
244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//  - 300,000 frees
245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//  -  15,000 XPts            800,000 XPts
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//  -   1,800 top-XPts
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt n_heap_allocs           = 0;
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt n_heap_reallocs         = 0;
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt n_heap_frees            = 0;
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt n_ignored_heap_allocs   = 0;
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt n_ignored_heap_frees    = 0;
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt n_ignored_heap_reallocs = 0;
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt n_stack_allocs          = 0;
255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt n_stack_frees           = 0;
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt n_xpts                  = 0;
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt n_xpt_init_expansions   = 0;
258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt n_xpt_later_expansions  = 0;
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt n_sxpt_allocs           = 0;
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt n_sxpt_frees            = 0;
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt n_skipped_snapshots     = 0;
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt n_real_snapshots        = 0;
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt n_detailed_snapshots    = 0;
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt n_peak_snapshots        = 0;
265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt n_cullings              = 0;
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt n_XCon_redos            = 0;
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--- Globals                                              ---//
270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Number of guest instructions executed so far.  Only used with
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// --time-unit=i.
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Long guest_instrs_executed = 0;
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic SizeT heap_szB       = 0; // Live heap size
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic SizeT heap_extra_szB = 0; // Live heap extra size -- slop + admin bytes
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic SizeT stacks_szB     = 0; // Live stacks size
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// This is the total size from the current peak snapshot, or 0 if no peak
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// snapshot has been taken yet.
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic SizeT peak_snapshot_total_szB = 0;
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Incremented every time memory is allocated/deallocated, by the
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// allocated/deallocated amount;  includes heap, heap-admin and stack
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// memory.  An alternative to milliseconds as a unit of program "time".
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong total_allocs_deallocs_szB = 0;
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// When running with --heap=yes --pages-as-heap=no, we don't start taking
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// snapshots until the first basic block is executed, rather than doing it in
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// ms_post_clo_init (which is the obvious spot), for two reasons.
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - It lets us ignore stack events prior to that, because they're not
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   really proper ones and just would screw things up.
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - Because there's still some core initialisation to do, and so there
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   would be an artificial time gap between the first and second snapshots.
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// When running with --heap=yes --pages-as-heap=yes, snapshots start much
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// earlier due to new_mem_startup so this isn't relevant.
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool have_started_executing_code = False;
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--- Alloc fns                                            ---//
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic XArray* alloc_fns;
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic XArray* ignore_fns;
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void init_alloc_fns(void)
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Create the list, and add the default elements.
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   alloc_fns = VG_(newXA)(VG_(malloc), "ms.main.iaf.1",
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       VG_(free), sizeof(Char*));
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   #define DO(x)  { Char* s = x; VG_(addToXA)(alloc_fns, &s); }
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Ordered roughly according to (presumed) frequency.
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Nb: The C++ "operator new*" ones are overloadable.  We include them
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // always anyway, because even if they're overloaded, it would be a
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // prodigiously stupid overloading that caused them to not allocate
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // memory.
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // XXX: because we don't look at the first stack entry (unless it's a
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // custom allocation) there's not much point to having all these alloc
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // functions here -- they should never appear anywhere (I think?) other
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // than the top stack entry.  The only exceptions are those that in
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // vg_replace_malloc.c are partly or fully implemented in terms of another
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // alloc function: realloc (which uses malloc);  valloc,
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // malloc_zone_valloc, posix_memalign and memalign_common (which use
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // memalign).
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO("malloc"                                              );
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO("__builtin_new"                                       );
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO("operator new(unsigned)"                              );
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO("operator new(unsigned long)"                         );
335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO("__builtin_vec_new"                                   );
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO("operator new[](unsigned)"                            );
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO("operator new[](unsigned long)"                       );
338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO("calloc"                                              );
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO("realloc"                                             );
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO("memalign"                                            );
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO("posix_memalign"                                      );
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO("valloc"                                              );
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO("operator new(unsigned, std::nothrow_t const&)"       );
344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO("operator new[](unsigned, std::nothrow_t const&)"     );
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO("operator new(unsigned long, std::nothrow_t const&)"  );
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO("operator new[](unsigned long, std::nothrow_t const&)");
347b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#if defined(VGO_darwin)
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO("malloc_zone_malloc"                                  );
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO("malloc_zone_calloc"                                  );
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO("malloc_zone_realloc"                                 );
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO("malloc_zone_memalign"                                );
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DO("malloc_zone_valloc"                                  );
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void init_ignore_fns(void)
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Create the (empty) list.
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ignore_fns = VG_(newXA)(VG_(malloc), "ms.main.iif.1",
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        VG_(free), sizeof(Char*));
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Determines if the named function is a member of the XArray.
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool is_member_fn(XArray* fns, Char* fnname)
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char** fn_ptr;
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Nb: It's a linear search through the list, because we're comparing
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // strings rather than pointers to strings.
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Nb: This gets called a lot.  It was an OSet, but they're quite slow to
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // iterate through so it wasn't a good choice.
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < VG_(sizeXA)(fns); i++) {
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fn_ptr = VG_(indexXA)(fns, i);
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_STREQ(fnname, *fn_ptr))
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--- Command line args                                    ---//
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define MAX_DEPTH       200
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef enum { TimeI, TimeMS, TimeB } TimeUnit;
389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Char* TimeUnit_to_string(TimeUnit time_unit)
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (time_unit) {
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case TimeI:  return "i";
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case TimeMS: return "ms";
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case TimeB:  return "B";
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   default:     tl_assert2(0, "TimeUnit_to_string: unrecognised TimeUnit");
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool   clo_heap            = True;
401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // clo_heap_admin is deliberately a word-sized type.  At one point it was
402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // a UInt, but this caused problems on 64-bit machines when it was
403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // multiplied by a small negative number and then promoted to a
404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // word-sized type -- it ended up with a value of 4.2 billion.  Sigh.
405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic SSizeT clo_heap_admin      = 8;
406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool   clo_pages_as_heap   = False;
407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool   clo_stacks          = False;
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int    clo_depth           = 30;
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic double clo_threshold       = 1.0;  // percentage
410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic double clo_peak_inaccuracy = 1.0;  // percentage
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int    clo_time_unit       = TimeI;
412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int    clo_detailed_freq   = 10;
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int    clo_max_snapshots   = 100;
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Char*  clo_massif_out_file = "massif.out.%p";
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic XArray* args_for_massif;
417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool ms_process_cmd_line_option(Char* arg)
419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char* tmp_str;
421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Remember the arg for later use.
423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(addToXA)(args_for_massif, &arg);
424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if VG_BOOL_CLO(arg, "--heap",           clo_heap)   {}
426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_BINT_CLO(arg, "--heap-admin",     clo_heap_admin, 0, 1024) {}
427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_BOOL_CLO(arg, "--stacks",         clo_stacks) {}
429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_BOOL_CLO(arg, "--pages-as-heap",  clo_pages_as_heap) {}
431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_BINT_CLO(arg, "--depth",          clo_depth, 1, MAX_DEPTH) {}
433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_STR_CLO(arg, "--alloc-fn",        tmp_str) {
435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(addToXA)(alloc_fns, &tmp_str);
436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_STR_CLO(arg, "--ignore-fn",       tmp_str) {
438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(addToXA)(ignore_fns, &tmp_str);
439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_DBL_CLO(arg, "--threshold",  clo_threshold) {
442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (clo_threshold < 0 || clo_threshold > 100) {
443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(fmsg_bad_option)(arg,
444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            "--threshold must be between 0.0 and 100.0\n");
445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_DBL_CLO(arg, "--peak-inaccuracy", clo_peak_inaccuracy) {}
449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_XACT_CLO(arg, "--time-unit=i",    clo_time_unit, TimeI)  {}
451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_XACT_CLO(arg, "--time-unit=ms",   clo_time_unit, TimeMS) {}
452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_XACT_CLO(arg, "--time-unit=B",    clo_time_unit, TimeB)  {}
453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
454f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   else if VG_BINT_CLO(arg, "--detailed-freq",  clo_detailed_freq, 1, 1000000) {}
455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_BINT_CLO(arg, "--max-snapshots",  clo_max_snapshots, 10, 1000) {}
457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_STR_CLO(arg, "--massif-out-file", clo_massif_out_file) {}
459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return VG_(replacement_malloc_process_cmd_line_option)(arg);
462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void ms_print_usage(void)
467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)(
469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"    --heap=no|yes             profile heap blocks [yes]\n"
470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"    --heap-admin=<size>       average admin bytes per heap block;\n"
471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"                               ignored if --heap=no [8]\n"
472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"    --stacks=no|yes           profile stack(s) [no]\n"
473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"    --pages-as-heap=no|yes    profile memory at the page level [no]\n"
474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"    --depth=<number>          depth of contexts [30]\n"
475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"    --alloc-fn=<name>         specify <name> as an alloc function [empty]\n"
476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"    --ignore-fn=<name>        ignore heap allocations within <name> [empty]\n"
477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"    --threshold=<m.n>         significance threshold, as a percentage [1.0]\n"
478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"    --peak-inaccuracy=<m.n>   maximum peak inaccuracy, as a percentage [1.0]\n"
479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"    --time-unit=i|ms|B        time unit: instructions executed, milliseconds\n"
480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"                              or heap bytes alloc'd/dealloc'd [i]\n"
481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"    --detailed-freq=<N>       every Nth snapshot should be detailed [10]\n"
482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"    --max-snapshots=<N>       maximum number of snapshots recorded [100]\n"
483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"    --massif-out-file=<file>  output file name [massif.out.%%p]\n"
484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void ms_print_debug_usage(void)
488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)(
490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"    (none)\n"
491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--- XPts, XTrees and XCons                               ---//
497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// An XPt represents an "execution point", ie. a code address.  Each XPt is
500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// part of a tree of XPts (an "execution tree", or "XTree").  The details of
501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// the heap are represented by a single XTree.
502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// The root of the tree is 'alloc_xpt', which represents all allocation
504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// functions, eg:
505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - malloc/calloc/realloc/memalign/new/new[];
506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - user-specified allocation functions (using --alloc-fn);
507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - custom allocation (MALLOCLIKE) points
508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// It's a bit of a fake XPt (ie. its 'ip' is zero), and is only used because
509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// it makes the code simpler.
510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Any child of 'alloc_xpt' is called a "top-XPt".  The XPts at the bottom
512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// of an XTree (leaf nodes) are "bottom-XPTs".
513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Each path from a top-XPt to a bottom-XPt through an XTree gives an
515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// execution context ("XCon"), ie. a stack trace.  (And sub-paths represent
516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// stack sub-traces.)  The number of XCons in an XTree is equal to the
517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// number of bottom-XPTs in that XTree.
518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      alloc_xpt       XTrees are bi-directional.
520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//        | ^
521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//        v |
522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//     > parent <       Example: if child1() calls parent() and child2()
523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//    /    |     \      also calls parent(), and parent() calls malloc(),
524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   |    / \     |     the XTree will look like this.
525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   |   v   v    |
526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//  child1   child2
527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// (Note that malformed stack traces can lead to difficulties.  See the
529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// comment at the bottom of get_XCon.)
530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// XTrees and XPts are mirrored by SXTrees and SXPts, where the 'S' is short
532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// for "saved".  When the XTree is duplicated for a snapshot, we duplicate
533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// it as an SXTree, which is similar but omits some things it does not need,
534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// and aggregates up insignificant nodes.  This is important as an SXTree is
535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// typically much smaller than an XTree.
536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// XXX: make XPt and SXPt extensible arrays, to avoid having to do two
538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// allocations per Pt.
539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef struct _XPt XPt;
541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstruct _XPt {
542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr  ip;              // code address
543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Bottom-XPts: space for the precise context.
545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Other XPts:  space of all the descendent bottom-XPts.
546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Nb: this value goes up and down as the program executes.
547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SizeT szB;
548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XPt*  parent;           // pointer to parent XPt
550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Children.
552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // n_children and max_children are 32-bit integers.  16-bit integers
553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // are too small -- a very big program might have more than 65536
554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // allocation points (ie. top-XPts) -- Konqueror starting up has 1800.
555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt  n_children;       // number of children
556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt  max_children;     // capacity of children array
557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XPt** children;         // pointers to children XPts
558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown};
559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   enum {
562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SigSXPt,
563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      InsigSXPt
564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SXPtTag;
566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef struct _SXPt SXPt;
568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstruct _SXPt {
569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SXPtTag tag;
570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SizeT szB;              // memory size for the node, be it Sig or Insig
571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   union {
572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // An SXPt representing a single significant code location.  Much like
573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // an XPt, minus the fields that aren't necessary.
574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      struct {
575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Addr   ip;
576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   n_children;
577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         SXPt** children;
578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Sig;
580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // An SXPt representing one or more code locations, all below the
582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // significance threshold.
583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      struct {
584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int   n_xpts;     // number of aggregated XPts
585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Insig;
587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   };
588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown};
589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Fake XPt representing all allocation functions like malloc().  Acts as
591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// parent node to all top-XPts.
592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic XPt* alloc_xpt;
593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Cheap allocation for blocks that never need to be freed.  Saves about 10%
595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// for Konqueror startup with --depth=40.
596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void* perm_malloc(SizeT n_bytes)
597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static Addr hp     = 0;    // current heap pointer
599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static Addr hp_lim = 0;    // maximum usable byte in current block
600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   #define SUPERBLOCK_SIZE  (1 << 20)         // 1 MB
602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (hp + n_bytes > hp_lim) {
604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hp = (Addr)VG_(am_shadow_alloc)(SUPERBLOCK_SIZE);
605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0 == hp)
606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(out_of_memory_NORETURN)( "massif:perm_malloc",
607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      SUPERBLOCK_SIZE);
608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hp_lim = hp + SUPERBLOCK_SIZE - 1;
609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   hp += n_bytes;
612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (void*)(hp - n_bytes);
614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic XPt* new_XPt(Addr ip, XPt* parent)
617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // XPts are never freed, so we can use perm_malloc to allocate them.
619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Note that we cannot use perm_malloc for the 'children' array, because
620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // that needs to be resizable.
621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XPt* xpt    = perm_malloc(sizeof(XPt));
622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xpt->ip     = ip;
623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xpt->szB    = 0;
624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xpt->parent = parent;
625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // We don't initially allocate any space for children.  We let that
627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // happen on demand.  Many XPts (ie. all the bottom-XPts) don't have any
628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // children anyway.
629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xpt->n_children   = 0;
630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xpt->max_children = 0;
631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xpt->children     = NULL;
632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Update statistics
634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_xpts++;
635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return xpt;
637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void add_child_xpt(XPt* parent, XPt* child)
640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Expand 'children' if necessary.
642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(parent->n_children <= parent->max_children);
643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (parent->n_children == parent->max_children) {
644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0 == parent->max_children) {
645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         parent->max_children = 4;
646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         parent->children = VG_(malloc)( "ms.main.acx.1",
647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         parent->max_children * sizeof(XPt*) );
648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         n_xpt_init_expansions++;
649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         parent->max_children *= 2;    // Double size
651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         parent->children = VG_(realloc)( "ms.main.acx.2",
652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          parent->children,
653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          parent->max_children * sizeof(XPt*) );
654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         n_xpt_later_expansions++;
655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Insert new child XPt in parent's children list.
659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   parent->children[ parent->n_children++ ] = child;
660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Reverse comparison for a reverse sort -- biggest to smallest.
663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int SXPt_revcmp_szB(void* n1, void* n2)
664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SXPt* sxpt1 = *(SXPt**)n1;
666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SXPt* sxpt2 = *(SXPt**)n2;
667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return ( sxpt1->szB < sxpt2->szB ?  1
668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          : sxpt1->szB > sxpt2->szB ? -1
669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          :                            0);
670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--- XTree Operations                                     ---//
674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Duplicates an XTree as an SXTree.
677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic SXPt* dup_XTree(XPt* xpt, SizeT total_szB)
678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int  i, n_sig_children, n_insig_children, n_child_sxpts;
680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SizeT sig_child_threshold_szB;
681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SXPt* sxpt;
682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Number of XPt children  Action for SXPT
684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // ------------------      ---------------
685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // 0 sig, 0 insig          alloc 0 children
686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // N sig, 0 insig          alloc N children, dup all
687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // N sig, M insig          alloc N+1, dup first N, aggregate remaining M
688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // 0 sig, M insig          alloc 1, aggregate M
689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Work out how big a child must be to be significant.  If the current
691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // total_szB is zero, then we set it to 1, which means everything will be
692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // judged insignificant -- this is sensible, as there's no point showing
693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // any detail for this case.  Unless they used --threshold=0, in which
694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // case we show them everything because that's what they asked for.
695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //
696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Nb: We do this once now, rather than once per child, because if we do
697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // that the cost of all the divisions adds up to something significant.
698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0 == total_szB && 0 != clo_threshold) {
699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sig_child_threshold_szB = 1;
700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sig_child_threshold_szB = (SizeT)((total_szB * clo_threshold) / 100);
702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // How many children are significant?  And do we need an aggregate SXPt?
705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_sig_children = 0;
706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < xpt->n_children; i++) {
707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (xpt->children[i]->szB >= sig_child_threshold_szB) {
708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         n_sig_children++;
709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_insig_children = xpt->n_children - n_sig_children;
712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_child_sxpts = n_sig_children + ( n_insig_children > 0 ? 1 : 0 );
713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Duplicate the XPt.
715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sxpt                 = VG_(malloc)("ms.main.dX.1", sizeof(SXPt));
716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_sxpt_allocs++;
717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sxpt->tag            = SigSXPt;
718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sxpt->szB            = xpt->szB;
719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sxpt->Sig.ip         = xpt->ip;
720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sxpt->Sig.n_children = n_child_sxpts;
721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Create the SXPt's children.
723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (n_child_sxpts > 0) {
724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int j;
725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SizeT sig_children_szB = 0, insig_children_szB = 0;
726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sxpt->Sig.children = VG_(malloc)("ms.main.dX.2",
727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       n_child_sxpts * sizeof(SXPt*));
728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Duplicate the significant children.  (Nb: sig_children_szB +
730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // insig_children_szB doesn't necessarily equal xpt->szB.)
731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      j = 0;
732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < xpt->n_children; i++) {
733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (xpt->children[i]->szB >= sig_child_threshold_szB) {
734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sxpt->Sig.children[j++] = dup_XTree(xpt->children[i], total_szB);
735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sig_children_szB   += xpt->children[i]->szB;
736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            insig_children_szB += xpt->children[i]->szB;
738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Create the SXPt for the insignificant children, if any, and put it
742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // in the last child entry.
743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (n_insig_children > 0) {
744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Nb: We 'n_sxpt_allocs' here because creating an Insig SXPt
745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // doesn't involve a call to dup_XTree().
746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         SXPt* insig_sxpt = VG_(malloc)("ms.main.dX.3", sizeof(SXPt));
747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         n_sxpt_allocs++;
748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         insig_sxpt->tag = InsigSXPt;
749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         insig_sxpt->szB = insig_children_szB;
750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         insig_sxpt->Insig.n_xpts = n_insig_children;
751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         sxpt->Sig.children[n_sig_children] = insig_sxpt;
752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sxpt->Sig.children = NULL;
755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sxpt;
758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void free_SXTree(SXPt* sxpt)
761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int  i;
763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(sxpt != NULL);
764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sxpt->tag) {
766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    case SigSXPt:
767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Free all children SXPts, then the children array.
768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < sxpt->Sig.n_children; i++) {
769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         free_SXTree(sxpt->Sig.children[i]);
770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         sxpt->Sig.children[i] = NULL;
771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(free)(sxpt->Sig.children);  sxpt->Sig.children = NULL;
773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    case InsigSXPt:
776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    default: tl_assert2(0, "free_SXTree: unknown SXPt tag");
779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Free the SXPt itself.
782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(free)(sxpt);     sxpt = NULL;
783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_sxpt_frees++;
784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Sanity checking:  we periodically check the heap XTree with
787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// ms_expensive_sanity_check.
788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void sanity_check_XTree(XPt* xpt, XPt* parent)
789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(xpt != NULL);
791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Check back-pointer.
793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert2(xpt->parent == parent,
794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "xpt->parent = %p, parent = %p\n", xpt->parent, parent);
795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Check children counts look sane.
797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(xpt->n_children <= xpt->max_children);
798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Unfortunately, xpt's size is not necessarily equal to the sum of xpt's
800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // children's sizes.  See comment at the bottom of get_XCon.
801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Sanity checking:  we check SXTrees (which are in snapshots) after
804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// snapshots are created, before they are deleted, and before they are
805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// printed.
806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void sanity_check_SXTree(SXPt* sxpt)
807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(sxpt != NULL);
811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Check the sum of any children szBs equals the SXPt's szB.  Check the
813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // children at the same time.
814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sxpt->tag) {
815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    case SigSXPt: {
816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sxpt->Sig.n_children > 0) {
817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (i = 0; i < sxpt->Sig.n_children; i++) {
818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sanity_check_SXTree(sxpt->Sig.children[i]);
819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    case InsigSXPt:
824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;         // do nothing
825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    default: tl_assert2(0, "sanity_check_SXTree: unknown SXPt tag");
827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--- XCon Operations                                      ---//
833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// This is the limit on the number of removed alloc-fns that can be in a
836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// single XCon.
837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define MAX_OVERESTIMATE   50
838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define MAX_IPS            (MAX_DEPTH + MAX_OVERESTIMATE)
839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// This is used for various buffers which can hold function names/IP
841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// description.  Some C++ names can get really long so 1024 isn't big
842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// enough.
843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define BUF_LEN   2048
844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Determine if the given IP belongs to a function that should be ignored.
846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool fn_should_be_ignored(Addr ip)
847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static Char buf[BUF_LEN];
849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ( VG_(get_fnname)(ip, buf, BUF_LEN) && is_member_fn(ignore_fns, buf)
851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ? True : False );
852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Get the stack trace for an XCon, filtering out uninteresting entries:
855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// alloc-fns and entries above alloc-fns, and entries below main-or-below-main.
856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   Eg:       alloc-fn1 / alloc-fn2 / a / b / main / (below main) / c
857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   becomes:  a / b / main
858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Nb: it's possible to end up with an empty trace, eg. if 'main' is marked
859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// as an alloc-fn.  This is ok.
860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt get_IPs( ThreadId tid, Bool exclude_first_entry, Addr ips[])
862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static Char buf[BUF_LEN];
864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int n_ips, i, n_alloc_fns_removed;
865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int overestimate;
866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool redo;
867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // We ask for a few more IPs than clo_depth suggests we need.  Then we
869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // remove every entry that is an alloc-fn.  Depending on the
870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // circumstances, we may need to redo it all, asking for more IPs.
871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Details:
872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // - If the original stack trace is smaller than asked-for, redo=False
873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // - Else if after filtering we have >= clo_depth IPs,      redo=False
874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // - Else redo=True
875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // In other words, to redo, we'd have to get a stack trace as big as we
876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // asked for and remove more than 'overestimate' alloc-fns.
877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Main loop.
879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   redo = True;      // Assume this to begin with.
880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (overestimate = 3; redo; overestimate += 6) {
881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // This should never happen -- would require MAX_OVERESTIMATE
882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // alloc-fns to be removed from the stack trace.
883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (overestimate > MAX_OVERESTIMATE)
884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(tool_panic)("get_IPs: ips[] too small, inc. MAX_OVERESTIMATE?");
885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Ask for more IPs than clo_depth suggests we need.
887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_ips = VG_(get_StackTrace)( tid, ips, clo_depth + overestimate,
888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   NULL/*array to dump SP values in*/,
889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   NULL/*array to dump FP values in*/,
890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   0/*first_ip_delta*/ );
891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(n_ips > 0);
892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // If the original stack trace is smaller than asked-for, redo=False.
894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (n_ips < clo_depth + overestimate) { redo = False; }
895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Filter out alloc fns.  If requested, we automatically remove the
897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // first entry (which presumably will be something like malloc or
898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // __builtin_new that we're sure to filter out) without looking at it,
899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // because VG_(get_fnname) is expensive.
900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_alloc_fns_removed = ( exclude_first_entry ? 1 : 0 );
901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = n_alloc_fns_removed; i < n_ips; i++) {
902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (VG_(get_fnname)(ips[i], buf, BUF_LEN)) {
903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (is_member_fn(alloc_fns, buf)) {
904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               n_alloc_fns_removed++;
905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Remove the alloc fns by shuffling the rest down over them.
911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_ips -= n_alloc_fns_removed;
912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < n_ips; i++) {
913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ips[i] = ips[i + n_alloc_fns_removed];
914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // If after filtering we have >= clo_depth IPs, redo=False
917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (n_ips >= clo_depth) {
918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         redo = False;
919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         n_ips = clo_depth;      // Ignore any IPs below --depth.
920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (redo) {
923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         n_XCon_redos++;
924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return n_ips;
927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Gets an XCon and puts it in the tree.  Returns the XCon's bottom-XPt.
930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Unless the allocation should be ignored, in which case we return NULL.
931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic XPt* get_XCon( ThreadId tid, Bool exclude_first_entry )
932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static Addr ips[MAX_IPS];
934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XPt* xpt = alloc_xpt;
936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // After this call, the IPs we want are in ips[0]..ips[n_ips-1].
938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int n_ips = get_IPs(tid, exclude_first_entry, ips);
939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Should we ignore this allocation?  (Nb: n_ips can be zero, eg. if
941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // 'main' is marked as an alloc-fn.)
942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (n_ips > 0 && fn_should_be_ignored(ips[0])) {
943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return NULL;
944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Now do the search/insertion of the XCon.
947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < n_ips; i++) {
948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Addr ip = ips[i];
949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int ch;
950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Look for IP in xpt's children.
951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Linear search, ugh -- about 10% of time for konqueror startup tried
952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // caching last result, only hit about 4% for konqueror.
953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Nb:  this search hits about 98% of the time for konqueror
954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (ch = 0; True; ch++) {
955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (ch == xpt->n_children) {
956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // IP not found in the children.
957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // Create and add new child XPt, then stop.
958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            XPt* new_child_xpt = new_XPt(ip, xpt);
959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            add_child_xpt(xpt, new_child_xpt);
960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            xpt = new_child_xpt;
961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else if (ip == xpt->children[ch]->ip) {
964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // Found the IP in the children, stop.
965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            xpt = xpt->children[ch];
966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // [Note: several comments refer to this comment.  Do not delete it
972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // without updating them.]
973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //
974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // A complication... If all stack traces were well-formed, then the
975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // returned xpt would always be a bottom-XPt.  As a consequence, an XPt's
976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // size would always be equal to the sum of its children's sizes, which
977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // is an excellent sanity check.
978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //
979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Unfortunately, stack traces occasionally are malformed, ie. truncated.
980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // This allows a stack trace to be a sub-trace of another, eg. a/b/c is a
981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // sub-trace of a/b/c/d.  So we can't assume this xpt is a bottom-XPt;
982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // nor can we do sanity check an XPt's size against its children's sizes.
983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // This is annoying, but must be dealt with.  (Older versions of Massif
984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // had this assertion in, and it was reported to fail by real users a
985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // couple of times.)  Even more annoyingly, I can't come up with a simple
986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // test case that exhibit such a malformed stack trace, so I can't
987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // regression test it.  Sigh.
988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //
989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // However, we can print a warning, so that if it happens (unexpectedly)
990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // in existing regression tests we'll know.  Also, it warns users that
991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // the output snapshots may not add up the way they might expect.
992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //
993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //tl_assert(0 == xpt->n_children); // Must be bottom-XPt
994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0 != xpt->n_children) {
995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      static Int n_moans = 0;
996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (n_moans < 3) {
997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(umsg)(
998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            "Warning: Malformed stack trace detected.  In Massif's output,\n");
999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(umsg)(
1000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            "         the size of an entry's child entries may not sum up\n");
1001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(umsg)(
1002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            "         to the entry's size as they normally do.\n");
1003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         n_moans++;
1004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (3 == n_moans)
1005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(umsg)(
1006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            "         (And Massif now won't warn about this again.)\n");
1007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return xpt;
1010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Update 'szB' of every XPt in the XCon, by percolating upwards.
1013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void update_XCon(XPt* xpt, SSizeT space_delta)
1014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(clo_heap);
1016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(NULL != xpt);
1017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0 == space_delta)
1019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
1020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (xpt != alloc_xpt) {
1022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (space_delta < 0) tl_assert(xpt->szB >= -space_delta);
1023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xpt->szB += space_delta;
1024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xpt = xpt->parent;
1025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (space_delta < 0) tl_assert(alloc_xpt->szB >= -space_delta);
1027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   alloc_xpt->szB += space_delta;
1028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
1032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--- Snapshots                                            ---//
1033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
1034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Snapshots are done in a way so that we always have a reasonable number of
1036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// them.  We start by taking them quickly.  Once we hit our limit, we cull
1037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// some (eg. half), and start taking them more slowly.  Once we hit the
1038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// limit again, we again cull and then take them even more slowly, and so
1039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// on.
1040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Time is measured either in i or ms or bytes, depending on the --time-unit
1042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// option.  It's a Long because it can exceed 32-bits reasonably easily, and
1043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// because we need to allow negative values to represent unset times.
1044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef Long Time;
1045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define UNUSED_SNAPSHOT_TIME  -333  // A conspicuous negative number.
1047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
1049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   enum {
1050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Normal = 77,
1051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Peak,
1052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Unused
1053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SnapshotKind;
1055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
1057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct {
1058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SnapshotKind kind;
1059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Time  time;
1060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SizeT heap_szB;
1061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SizeT heap_extra_szB;// Heap slop + admin bytes.
1062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SizeT stacks_szB;
1063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SXPt* alloc_sxpt;    // Heap XTree root, if a detailed snapshot,
1064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }                       // otherwise NULL.
1065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Snapshot;
1066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt      next_snapshot_i = 0;  // Index of where next snapshot will go.
1068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Snapshot* snapshots;            // Array of snapshots.
1069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool is_snapshot_in_use(Snapshot* snapshot)
1071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (Unused == snapshot->kind) {
1073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // If snapshot is unused, check all the fields are unset.
1074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(snapshot->time           == UNUSED_SNAPSHOT_TIME);
1075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(snapshot->heap_extra_szB == 0);
1076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(snapshot->heap_szB       == 0);
1077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(snapshot->stacks_szB     == 0);
1078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(snapshot->alloc_sxpt     == NULL);
1079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
1080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(snapshot->time           != UNUSED_SNAPSHOT_TIME);
1082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
1083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool is_detailed_snapshot(Snapshot* snapshot)
1087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (snapshot->alloc_sxpt ? True : False);
1089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool is_uncullable_snapshot(Snapshot* snapshot)
1092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return &snapshots[0] == snapshot                   // First snapshot
1094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       || &snapshots[next_snapshot_i-1] == snapshot   // Last snapshot
1095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       || snapshot->kind == Peak;                     // Peak snapshot
1096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void sanity_check_snapshot(Snapshot* snapshot)
1099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (snapshot->alloc_sxpt) {
1101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sanity_check_SXTree(snapshot->alloc_sxpt);
1102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// All the used entries should look used, all the unused ones should be clear.
1106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void sanity_check_snapshots_array(void)
1107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
1109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < next_snapshot_i; i++) {
1110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert( is_snapshot_in_use( & snapshots[i] ));
1111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (    ; i < clo_max_snapshots; i++) {
1113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(!is_snapshot_in_use( & snapshots[i] ));
1114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// This zeroes all the fields in the snapshot, but does not free the heap
1118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// XTree if present.  It also does a sanity check unless asked not to;  we
1119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// can't sanity check at startup when clearing the initial snapshots because
1120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// they're full of junk.
1121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void clear_snapshot(Snapshot* snapshot, Bool do_sanity_check)
1122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (do_sanity_check) sanity_check_snapshot(snapshot);
1124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   snapshot->kind           = Unused;
1125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   snapshot->time           = UNUSED_SNAPSHOT_TIME;
1126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   snapshot->heap_extra_szB = 0;
1127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   snapshot->heap_szB       = 0;
1128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   snapshot->stacks_szB     = 0;
1129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   snapshot->alloc_sxpt     = NULL;
1130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// This zeroes all the fields in the snapshot, and frees the heap XTree if
1133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// present.
1134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void delete_snapshot(Snapshot* snapshot)
1135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Nb: if there's an XTree, we free it after calling clear_snapshot,
1137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // because clear_snapshot does a sanity check which includes checking the
1138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // XTree.
1139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SXPt* tmp_sxpt = snapshot->alloc_sxpt;
1140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   clear_snapshot(snapshot, /*do_sanity_check*/True);
1141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (tmp_sxpt) {
1142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      free_SXTree(tmp_sxpt);
1143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void VERB_snapshot(Int verbosity, Char* prefix, Int i)
1147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Snapshot* snapshot = &snapshots[i];
1149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char* suffix;
1150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (snapshot->kind) {
1151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case Peak:   suffix = "p";                                            break;
1152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case Normal: suffix = ( is_detailed_snapshot(snapshot) ? "d" : "." ); break;
1153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case Unused: suffix = "u";                                            break;
1154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   default:
1155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert2(0, "VERB_snapshot: unknown snapshot kind: %d", snapshot->kind);
1156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VERB(verbosity, "%s S%s%3d (t:%lld, hp:%ld, ex:%ld, st:%ld)\n",
1158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      prefix, suffix, i,
1159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      snapshot->time,
1160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      snapshot->heap_szB,
1161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      snapshot->heap_extra_szB,
1162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      snapshot->stacks_szB
1163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Cull half the snapshots;  we choose those that represent the smallest
1167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// time-spans, because that gives us the most even distribution of snapshots
1168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// over time.  (It's possible to lose interesting spikes, however.)
1169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
1170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Algorithm for N snapshots:  We find the snapshot representing the smallest
1171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// timeframe, and remove it.  We repeat this until (N/2) snapshots are gone.
1172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// We have to do this one snapshot at a time, rather than finding the (N/2)
1173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// smallest snapshots in one hit, because when a snapshot is removed, its
1174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// neighbours immediately cover greater timespans.  So it's O(N^2), but N is
1175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// small, and it's not done very often.
1176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
1177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Once we're done, we return the new smallest interval between snapshots.
1178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// That becomes our minimum time interval.
1179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt cull_snapshots(void)
1180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int  i, jp, j, jn, min_timespan_i;
1182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int  n_deleted = 0;
1183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Time min_timespan;
1184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_cullings++;
1186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Sets j to the index of the first not-yet-removed snapshot at or after i
1188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   #define FIND_SNAPSHOT(i, j) \
1189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (j = i; \
1190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           j < clo_max_snapshots && !is_snapshot_in_use(&snapshots[j]); \
1191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           j++) { }
1192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VERB(2, "Culling...\n");
1194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // First we remove enough snapshots by clearing them in-place.  Once
1196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // that's done, we can slide the remaining ones down.
1197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < clo_max_snapshots/2; i++) {
1198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Find the snapshot representing the smallest timespan.  The timespan
1199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // for snapshot n = d(N-1,N)+d(N,N+1), where d(A,B) is the time between
1200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // snapshot A and B.  We don't consider the first and last snapshots for
1201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // removal.
1202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Snapshot* min_snapshot;
1203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int min_j;
1204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Initial triple: (prev, curr, next) == (jp, j, jn)
1206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Initial min_timespan is the first one.
1207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jp = 0;
1208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FIND_SNAPSHOT(1,   j);
1209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FIND_SNAPSHOT(j+1, jn);
1210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      min_timespan = 0x7fffffffffffffffLL;
1211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      min_j        = -1;
1212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      while (jn < clo_max_snapshots) {
1213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Time timespan = snapshots[jn].time - snapshots[jp].time;
1214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(timespan >= 0);
1215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Nb: We never cull the peak snapshot.
1216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (Peak != snapshots[j].kind && timespan < min_timespan) {
1217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            min_timespan = timespan;
1218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            min_j        = j;
1219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Move on to next triple
1221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         jp = j;
1222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         j  = jn;
1223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         FIND_SNAPSHOT(jn+1, jn);
1224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // We've found the least important snapshot, now delete it.  First
1226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // print it if necessary.
1227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(-1 != min_j);    // Check we found a minimum.
1228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      min_snapshot = & snapshots[ min_j ];
1229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(clo_verbosity) > 1) {
1230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Char buf[64];
1231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(snprintf)(buf, 64, " %3d (t-span = %lld)", i, min_timespan);
1232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VERB_snapshot(2, buf, min_j);
1233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delete_snapshot(min_snapshot);
1235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_deleted++;
1236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Slide down the remaining snapshots over the removed ones.  First set i
1239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // to point to the first empty slot, and j to the first full slot after
1240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // i.  Then slide everything down.
1241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0;  is_snapshot_in_use( &snapshots[i] ); i++) { }
1242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (j = i; !is_snapshot_in_use( &snapshots[j] ); j++) { }
1243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (  ; j < clo_max_snapshots; j++) {
1244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (is_snapshot_in_use( &snapshots[j] )) {
1245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         snapshots[i++] = snapshots[j];
1246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         clear_snapshot(&snapshots[j], /*do_sanity_check*/True);
1247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   next_snapshot_i = i;
1250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Check snapshots array looks ok after changes.
1252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sanity_check_snapshots_array();
1253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Find the minimum timespan remaining;  that will be our new minimum
1255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // time interval.  Note that above we were finding timespans by measuring
1256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // two intervals around a snapshot that was under consideration for
1257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // deletion.  Here we only measure single intervals because all the
1258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // deletions have occurred.
1259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //
1260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // But we have to be careful -- some snapshots (eg. snapshot 0, and the
1261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // peak snapshot) are uncullable.  If two uncullable snapshots end up
1262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // next to each other, they'll never be culled (assuming the peak doesn't
1263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // change), and the time gap between them will not change.  However, the
1264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // time between the remaining cullable snapshots will grow ever larger.
1265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // This means that the min_timespan found will always be that between the
1266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // two uncullable snapshots, and it will be much smaller than it should
1267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // be.  To avoid this problem, when computing the minimum timespan, we
1268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // ignore any timespans between two uncullable snapshots.
1269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(next_snapshot_i > 1);
1270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   min_timespan = 0x7fffffffffffffffLL;
1271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   min_timespan_i = -1;
1272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 1; i < next_snapshot_i; i++) {
1273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (is_uncullable_snapshot(&snapshots[i]) &&
1274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          is_uncullable_snapshot(&snapshots[i-1]))
1275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      {
1276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VERB(2, "(Ignoring interval %d--%d when computing minimum)\n", i-1, i);
1277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Time timespan = snapshots[i].time - snapshots[i-1].time;
1279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(timespan >= 0);
1280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (timespan < min_timespan) {
1281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            min_timespan = timespan;
1282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            min_timespan_i = i;
1283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(-1 != min_timespan_i);    // Check we found a minimum.
1287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Print remaining snapshots, if necessary.
1289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_verbosity) > 1) {
1290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VERB(2, "Finished culling (%3d of %3d deleted)\n",
1291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         n_deleted, clo_max_snapshots);
1292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < next_snapshot_i; i++) {
1293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VERB_snapshot(2, "  post-cull", i);
1294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VERB(2, "New time interval = %lld (between snapshots %d and %d)\n",
1296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         min_timespan, min_timespan_i-1, min_timespan_i);
1297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return min_timespan;
1300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Time get_time(void)
1303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Get current time, in whatever time unit we're using.
1305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (clo_time_unit == TimeI) {
1306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return guest_instrs_executed;
1307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else if (clo_time_unit == TimeMS) {
1308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Some stuff happens between the millisecond timer being initialised
1309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // to zero and us taking our first snapshot.  We determine that time
1310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // gap so we can subtract it from all subsequent times so that our
1311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // first snapshot is considered to be at t = 0ms.  Unfortunately, a
1312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // bunch of symbols get read after the first snapshot is taken but
1313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // before the second one (which is triggered by the first allocation),
1314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // so when the time-unit is 'ms' we always have a big gap between the
1315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // first two snapshots.  But at least users won't have to wonder why
1316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // the first snapshot isn't at t=0.
1317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      static Bool is_first_get_time = True;
1318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      static Time start_time_ms;
1319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (is_first_get_time) {
1320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         start_time_ms = VG_(read_millisecond_timer)();
1321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         is_first_get_time = False;
1322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return 0;
1323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return VG_(read_millisecond_timer)() - start_time_ms;
1325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else if (clo_time_unit == TimeB) {
1327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return total_allocs_deallocs_szB;
1328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert2(0, "bad --time-unit value");
1330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Take a snapshot, and only that -- decisions on whether to take a
1334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// snapshot, or what kind of snapshot, are made elsewhere.
1335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Nb: we call the arg "my_time" because "time" shadows a global declaration
1336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// in /usr/include/time.h on Darwin.
1337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void
1338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntake_snapshot(Snapshot* snapshot, SnapshotKind kind, Time my_time,
1339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              Bool is_detailed)
1340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(!is_snapshot_in_use(snapshot));
1342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!clo_pages_as_heap) {
1343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(have_started_executing_code);
1344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Heap and heap admin.
1347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (clo_heap) {
1348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      snapshot->heap_szB = heap_szB;
1349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (is_detailed) {
1350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         SizeT total_szB = heap_szB + heap_extra_szB + stacks_szB;
1351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         snapshot->alloc_sxpt = dup_XTree(alloc_xpt, total_szB);
1352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(           alloc_xpt->szB == heap_szB);
1353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(snapshot->alloc_sxpt->szB == heap_szB);
1354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      snapshot->heap_extra_szB = heap_extra_szB;
1356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Stack(s).
1359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (clo_stacks) {
1360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      snapshot->stacks_szB = stacks_szB;
1361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Rest of snapshot.
1364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   snapshot->kind = kind;
1365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   snapshot->time = my_time;
1366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sanity_check_snapshot(snapshot);
1367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Update stats.
1369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (Peak == kind) n_peak_snapshots++;
1370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (is_detailed)  n_detailed_snapshots++;
1371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_real_snapshots++;
1372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Take a snapshot, if it's time, or if we've hit a peak.
1376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void
1377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmaybe_take_snapshot(SnapshotKind kind, Char* what)
1378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // 'min_time_interval' is the minimum time interval between snapshots.
1380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // If we try to take a snapshot and less than this much time has passed,
1381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // we don't take it.  It gets larger as the program runs longer.  It's
1382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // initialised to zero so that we begin by taking snapshots as quickly as
1383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // possible.
1384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static Time min_time_interval = 0;
1385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Zero allows startup snapshot.
1386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static Time earliest_possible_time_of_next_snapshot = 0;
1387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static Int  n_snapshots_since_last_detailed         = 0;
1388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static Int  n_skipped_snapshots_since_last_snapshot = 0;
1389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Snapshot* snapshot;
1391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool      is_detailed;
1392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Nb: we call this variable "my_time" because "time" shadows a global
1393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // declaration in /usr/include/time.h on Darwin.
1394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Time      my_time = get_time();
1395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (kind) {
1397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    case Normal:
1398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Only do a snapshot if it's time.
1399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (my_time < earliest_possible_time_of_next_snapshot) {
1400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         n_skipped_snapshots++;
1401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         n_skipped_snapshots_since_last_snapshot++;
1402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return;
1403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      is_detailed = (clo_detailed_freq-1 == n_snapshots_since_last_detailed);
1405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
1406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    case Peak: {
1408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Because we're about to do a deallocation, we're coming down from a
1409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // local peak.  If it is (a) actually a global peak, and (b) a certain
1410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // amount bigger than the previous peak, then we take a peak snapshot.
1411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // By not taking a snapshot for every peak, we save a lot of effort --
1412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // because many peaks remain peak only for a short time.
1413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SizeT total_szB = heap_szB + heap_extra_szB + stacks_szB;
1414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SizeT excess_szB_for_new_peak =
1415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (SizeT)((peak_snapshot_total_szB * clo_peak_inaccuracy) / 100);
1416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (total_szB <= peak_snapshot_total_szB + excess_szB_for_new_peak) {
1417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return;
1418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      is_detailed = True;
1420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
1421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
1422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    default:
1424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert2(0, "maybe_take_snapshot: unrecognised snapshot kind");
1425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Take the snapshot.
1428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   snapshot = & snapshots[next_snapshot_i];
1429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   take_snapshot(snapshot, kind, my_time, is_detailed);
1430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Record if it was detailed.
1432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (is_detailed) {
1433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_snapshots_since_last_detailed = 0;
1434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_snapshots_since_last_detailed++;
1436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Update peak data, if it's a Peak snapshot.
1439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (Peak == kind) {
1440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int i, number_of_peaks_snapshots_found = 0;
1441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Sanity check the size, then update our recorded peak.
1443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SizeT snapshot_total_szB =
1444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         snapshot->heap_szB + snapshot->heap_extra_szB + snapshot->stacks_szB;
1445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert2(snapshot_total_szB > peak_snapshot_total_szB,
1446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "%ld, %ld\n", snapshot_total_szB, peak_snapshot_total_szB);
1447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      peak_snapshot_total_szB = snapshot_total_szB;
1448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Find the old peak snapshot, if it exists, and mark it as normal.
1450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < next_snapshot_i; i++) {
1451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (Peak == snapshots[i].kind) {
1452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            snapshots[i].kind = Normal;
1453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            number_of_peaks_snapshots_found++;
1454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(number_of_peaks_snapshots_found <= 1);
1457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Finish up verbosity and stats stuff.
1460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (n_skipped_snapshots_since_last_snapshot > 0) {
1461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VERB(2, "  (skipped %d snapshot%s)\n",
1462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         n_skipped_snapshots_since_last_snapshot,
1463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ( 1 == n_skipped_snapshots_since_last_snapshot ? "" : "s") );
1464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VERB_snapshot(2, what, next_snapshot_i);
1466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_skipped_snapshots_since_last_snapshot = 0;
1467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Cull the entries, if our snapshot table is full.
1469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   next_snapshot_i++;
1470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (clo_max_snapshots == next_snapshot_i) {
1471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      min_time_interval = cull_snapshots();
1472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Work out the earliest time when the next snapshot can happen.
1475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   earliest_possible_time_of_next_snapshot = my_time + min_time_interval;
1476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
1480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--- Sanity checking                                      ---//
1481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
1482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool ms_cheap_sanity_check ( void )
1484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;   // Nothing useful we can cheaply check.
1486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool ms_expensive_sanity_check ( void )
1489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sanity_check_XTree(alloc_xpt, /*parent*/NULL);
1491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sanity_check_snapshots_array();
1492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
1493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
1497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--- Heap management                                      ---//
1498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
1499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Metadata for heap blocks.  Each one contains a pointer to a bottom-XPt,
1501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// which is a foothold into the XCon at which it was allocated.  From
1502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// HP_Chunks, XPt 'space' fields are incremented (at allocation) and
1503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// decremented (at deallocation).
1504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
1505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Nb: first two fields must match core's VgHashNode.
1506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
1507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct _HP_Chunk {
1508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      struct _HP_Chunk* next;
1509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Addr              data;       // Ptr to actual block
1510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SizeT             req_szB;    // Size requested
1511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SizeT             slop_szB;   // Extra bytes given above those requested
1512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      XPt*              where;      // Where allocated; bottom-XPt
1513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HP_Chunk;
1515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic VgHashTable malloc_list  = NULL;   // HP_Chunks
1517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void update_alloc_stats(SSizeT szB_delta)
1519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Update total_allocs_deallocs_szB.
1521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (szB_delta < 0) szB_delta = -szB_delta;
1522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   total_allocs_deallocs_szB += szB_delta;
1523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void update_heap_stats(SSizeT heap_szB_delta, Int heap_extra_szB_delta)
1526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (heap_szB_delta < 0)
1528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(heap_szB >= -heap_szB_delta);
1529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (heap_extra_szB_delta < 0)
1530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(heap_extra_szB >= -heap_extra_szB_delta);
1531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   heap_extra_szB += heap_extra_szB_delta;
1533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   heap_szB       += heap_szB_delta;
1534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   update_alloc_stats(heap_szB_delta + heap_extra_szB_delta);
1536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid* record_block( ThreadId tid, void* p, SizeT req_szB, SizeT slop_szB,
1540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Bool exclude_first_entry, Bool maybe_snapshot )
1541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Make new HP_Chunk node, add to malloc_list
1543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HP_Chunk* hc = VG_(malloc)("ms.main.rb.1", sizeof(HP_Chunk));
1544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   hc->req_szB  = req_szB;
1545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   hc->slop_szB = slop_szB;
1546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   hc->data     = (Addr)p;
1547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   hc->where    = NULL;
1548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(HT_add_node)(malloc_list, hc);
1549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (clo_heap) {
1551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VERB(3, "<<< record_block (%lu, %lu)\n", req_szB, slop_szB);
1552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hc->where = get_XCon( tid, exclude_first_entry );
1554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (hc->where) {
1556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Update statistics.
1557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         n_heap_allocs++;
1558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Update heap stats.
1560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         update_heap_stats(req_szB, clo_heap_admin + slop_szB);
1561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Update XTree.
1563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         update_XCon(hc->where, req_szB);
1564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Maybe take a snapshot.
1566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (maybe_snapshot) {
1567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            maybe_take_snapshot(Normal, "  alloc");
1568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Ignored allocation.
1572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         n_ignored_heap_allocs++;
1573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VERB(3, "(ignored)\n");
1575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VERB(3, ">>>\n");
1578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return p;
1581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic __inline__
1584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid* alloc_and_record_block ( ThreadId tid, SizeT req_szB, SizeT req_alignB,
1585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               Bool is_zeroed )
1586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SizeT actual_szB, slop_szB;
1588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   void* p;
1589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((SSizeT)req_szB < 0) return NULL;
1591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Allocate and zero if necessary.
1593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p = VG_(cli_malloc)( req_alignB, req_szB );
1594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!p) {
1595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return NULL;
1596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (is_zeroed) VG_(memset)(p, 0, req_szB);
1598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   actual_szB = VG_(malloc_usable_size)(p);
1599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(actual_szB >= req_szB);
1600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   slop_szB = actual_szB - req_szB;
1601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Record block.
1603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   record_block(tid, p, req_szB, slop_szB, /*exclude_first_entry*/True,
1604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                /*maybe_snapshot*/True);
1605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return p;
1607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic __inline__
1610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid unrecord_block ( void* p, Bool maybe_snapshot )
1611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Remove HP_Chunk from malloc_list
1613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HP_Chunk* hc = VG_(HT_remove)(malloc_list, (UWord)p);
1614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (NULL == hc) {
1615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;   // must have been a bogus free()
1616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (clo_heap) {
1619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VERB(3, "<<< unrecord_block\n");
1620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (hc->where) {
1622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Update statistics.
1623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         n_heap_frees++;
1624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Maybe take a peak snapshot, since it's a deallocation.
1626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (maybe_snapshot) {
1627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            maybe_take_snapshot(Peak, "de-PEAK");
1628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Update heap stats.
1631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         update_heap_stats(-hc->req_szB, -clo_heap_admin - hc->slop_szB);
1632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Update XTree.
1634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         update_XCon(hc->where, -hc->req_szB);
1635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Maybe take a snapshot.
1637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (maybe_snapshot) {
1638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            maybe_take_snapshot(Normal, "dealloc");
1639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         n_ignored_heap_frees++;
1643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VERB(3, "(ignored)\n");
1645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VERB(3, ">>> (-%lu, -%lu)\n", hc->req_szB, hc->slop_szB);
1648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Actually free the chunk, and the heap block (if necessary)
1651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(free)( hc );  hc = NULL;
1652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Nb: --ignore-fn is tricky for realloc.  If the block's original alloc was
1655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// ignored, but the realloc is not requested to be ignored, and we are
1656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// shrinking the block, then we have to ignore the realloc -- otherwise we
1657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// could end up with negative heap sizes.  This isn't a danger if we are
1658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// growing such a block, but for consistency (it also simplifies things) we
1659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// ignore such reallocs as well.
1660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic __inline__
1661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid* realloc_block ( ThreadId tid, void* p_old, SizeT new_req_szB )
1662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HP_Chunk* hc;
1664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   void*     p_new;
1665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SizeT     old_req_szB, old_slop_szB, new_slop_szB, new_actual_szB;
1666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XPt      *old_where, *new_where;
1667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool      is_ignored = False;
1668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Remove the old block
1670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   hc = VG_(HT_remove)(malloc_list, (UWord)p_old);
1671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (hc == NULL) {
1672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return NULL;   // must have been a bogus realloc()
1673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   old_req_szB  = hc->req_szB;
1676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   old_slop_szB = hc->slop_szB;
1677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(!clo_pages_as_heap);  // Shouldn't be here if --pages-as-heap=yes.
1679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (clo_heap) {
1680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VERB(3, "<<< realloc_block (%lu)\n", new_req_szB);
1681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (hc->where) {
1683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Update statistics.
1684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         n_heap_reallocs++;
1685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Maybe take a peak snapshot, if it's (effectively) a deallocation.
1687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (new_req_szB < old_req_szB) {
1688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            maybe_take_snapshot(Peak, "re-PEAK");
1689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // The original malloc was ignored, so we have to ignore the
1692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // realloc as well.
1693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         is_ignored = True;
1694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Actually do the allocation, if necessary.
1698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (new_req_szB <= old_req_szB + old_slop_szB) {
1699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // New size is smaller or same;  block not moved.
1700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      p_new = p_old;
1701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      new_slop_szB = old_slop_szB + (old_req_szB - new_req_szB);
1702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // New size is bigger;  make new block, copy shared contents, free old.
1705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      p_new = VG_(cli_malloc)(VG_(clo_alignment), new_req_szB);
1706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!p_new) {
1707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Nb: if realloc fails, NULL is returned but the old block is not
1708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // touched.  What an awful function.
1709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return NULL;
1710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1711b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(memcpy)(p_new, p_old, old_req_szB + old_slop_szB);
1712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(cli_free)(p_old);
1713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      new_actual_szB = VG_(malloc_usable_size)(p_new);
1714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(new_actual_szB >= new_req_szB);
1715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      new_slop_szB = new_actual_szB - new_req_szB;
1716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (p_new) {
1719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Update HP_Chunk.
1720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hc->data     = (Addr)p_new;
1721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hc->req_szB  = new_req_szB;
1722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hc->slop_szB = new_slop_szB;
1723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      old_where    = hc->where;
1724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hc->where    = NULL;
1725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Update XTree.
1727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (clo_heap) {
1728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         new_where = get_XCon( tid, /*exclude_first_entry*/True);
1729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!is_ignored && new_where) {
1730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            hc->where = new_where;
1731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            update_XCon(old_where, -old_req_szB);
1732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            update_XCon(new_where,  new_req_szB);
1733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
1734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // The realloc itself is ignored.
1735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            is_ignored = True;
1736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // Update statistics.
1738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            n_ignored_heap_reallocs++;
1739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Now insert the new hc (with a possibly new 'data' field) into
1744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // malloc_list.  If this realloc() did not increase the memory size, we
1745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // will have removed and then re-added hc unnecessarily.  But that's ok
1746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // because shrinking a block with realloc() is (presumably) much rarer
1747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // than growing it, and this way simplifies the growing case.
1748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(HT_add_node)(malloc_list, hc);
1749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (clo_heap) {
1751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!is_ignored) {
1752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Update heap stats.
1753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         update_heap_stats(new_req_szB - old_req_szB,
1754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          new_slop_szB - old_slop_szB);
1755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Maybe take a snapshot.
1757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         maybe_take_snapshot(Normal, "realloc");
1758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VERB(3, "(ignored)\n");
1761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VERB(3, ">>> (%ld, %ld)\n",
1764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         new_req_szB - old_req_szB, new_slop_szB - old_slop_szB);
1765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return p_new;
1768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
1772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--- malloc() et al replacement wrappers                  ---//
1773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
1774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void* ms_malloc ( ThreadId tid, SizeT szB )
1776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return alloc_and_record_block( tid, szB, VG_(clo_alignment), /*is_zeroed*/False );
1778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void* ms___builtin_new ( ThreadId tid, SizeT szB )
1781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return alloc_and_record_block( tid, szB, VG_(clo_alignment), /*is_zeroed*/False );
1783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void* ms___builtin_vec_new ( ThreadId tid, SizeT szB )
1786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return alloc_and_record_block( tid, szB, VG_(clo_alignment), /*is_zeroed*/False );
1788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void* ms_calloc ( ThreadId tid, SizeT m, SizeT szB )
1791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return alloc_and_record_block( tid, m*szB, VG_(clo_alignment), /*is_zeroed*/True );
1793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void *ms_memalign ( ThreadId tid, SizeT alignB, SizeT szB )
1796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return alloc_and_record_block( tid, szB, alignB, False );
1798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void ms_free ( ThreadId tid __attribute__((unused)), void* p )
1801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   unrecord_block(p, /*maybe_snapshot*/True);
1803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(cli_free)(p);
1804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void ms___builtin_delete ( ThreadId tid, void* p )
1807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   unrecord_block(p, /*maybe_snapshot*/True);
1809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(cli_free)(p);
1810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void ms___builtin_vec_delete ( ThreadId tid, void* p )
1813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   unrecord_block(p, /*maybe_snapshot*/True);
1815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(cli_free)(p);
1816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void* ms_realloc ( ThreadId tid, void* p_old, SizeT new_szB )
1819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return realloc_block(tid, p_old, new_szB);
1821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic SizeT ms_malloc_usable_size ( ThreadId tid, void* p )
1824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HP_Chunk* hc = VG_(HT_lookup)( malloc_list, (UWord)p );
1826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return ( hc ? hc->req_szB + hc->slop_szB : 0 );
1828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
1831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--- Page handling                                        ---//
1832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
1833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid ms_record_page_mem ( Addr a, SizeT len )
1836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadId tid = VG_(get_running_tid)();
1838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr end;
1839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(VG_IS_PAGE_ALIGNED(len));
1840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(len >= VKI_PAGE_SIZE);
1841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Record the first N-1 pages as blocks, but don't do any snapshots.
1842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (end = a + len - VKI_PAGE_SIZE; a < end; a += VKI_PAGE_SIZE) {
1843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      record_block( tid, (void*)a, VKI_PAGE_SIZE, /*slop_szB*/0,
1844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    /*exclude_first_entry*/False, /*maybe_snapshot*/False );
1845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Record the last page as a block, and maybe do a snapshot afterwards.
1847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   record_block( tid, (void*)a, VKI_PAGE_SIZE, /*slop_szB*/0,
1848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 /*exclude_first_entry*/False, /*maybe_snapshot*/True );
1849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid ms_unrecord_page_mem( Addr a, SizeT len )
1853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr end;
1855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(VG_IS_PAGE_ALIGNED(len));
1856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(len >= VKI_PAGE_SIZE);
1857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (end = a + len - VKI_PAGE_SIZE; a < end; a += VKI_PAGE_SIZE) {
1858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      unrecord_block((void*)a, /*maybe_snapshot*/False);
1859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   unrecord_block((void*)a, /*maybe_snapshot*/True);
1861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
1864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid ms_new_mem_mmap ( Addr a, SizeT len,
1867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Bool rr, Bool ww, Bool xx, ULong di_handle )
1868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(VG_IS_PAGE_ALIGNED(len));
1870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ms_record_page_mem(a, len);
1871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid ms_new_mem_startup( Addr a, SizeT len,
1875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Bool rr, Bool ww, Bool xx, ULong di_handle )
1876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // startup maps are always be page-sized, except the trampoline page is
1878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // marked by the core as only being the size of the trampoline itself,
1879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // which is something like 57 bytes.  Round it up to page size.
1880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   len = VG_PGROUNDUP(len);
1881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ms_record_page_mem(a, len);
1882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid ms_new_mem_brk ( Addr a, SizeT len, ThreadId tid )
1886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(VG_IS_PAGE_ALIGNED(len));
1888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ms_record_page_mem(a, len);
1889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid ms_copy_mem_remap( Addr from, Addr to, SizeT len)
1893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(VG_IS_PAGE_ALIGNED(len));
1895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ms_unrecord_page_mem(from, len);
1896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ms_record_page_mem(to, len);
1897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid ms_die_mem_munmap( Addr a, SizeT len )
1901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(VG_IS_PAGE_ALIGNED(len));
1903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ms_unrecord_page_mem(a, len);
1904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid ms_die_mem_brk( Addr a, SizeT len )
1908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(VG_IS_PAGE_ALIGNED(len));
1910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ms_unrecord_page_mem(a, len);
1911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
1914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--- Stacks                                               ---//
1915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
1916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// We really want the inlining to occur...
1918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define INLINE    inline __attribute__((always_inline))
1919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void update_stack_stats(SSizeT stack_szB_delta)
1921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (stack_szB_delta < 0) tl_assert(stacks_szB >= -stack_szB_delta);
1923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stacks_szB += stack_szB_delta;
1924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   update_alloc_stats(stack_szB_delta);
1926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic INLINE void new_mem_stack_2(SizeT len, Char* what)
1929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have_started_executing_code) {
1931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VERB(3, "<<< new_mem_stack (%ld)\n", len);
1932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_stack_allocs++;
1933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      update_stack_stats(len);
1934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      maybe_take_snapshot(Normal, what);
1935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VERB(3, ">>>\n");
1936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic INLINE void die_mem_stack_2(SizeT len, Char* what)
1940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have_started_executing_code) {
1942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VERB(3, "<<< die_mem_stack (%ld)\n", -len);
1943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_stack_frees++;
1944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      maybe_take_snapshot(Peak,   "stkPEAK");
1945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      update_stack_stats(-len);
1946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      maybe_take_snapshot(Normal, what);
1947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VERB(3, ">>>\n");
1948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void new_mem_stack(Addr a, SizeT len)
1952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   new_mem_stack_2(len, "stk-new");
1954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void die_mem_stack(Addr a, SizeT len)
1957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   die_mem_stack_2(len, "stk-die");
1959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void new_mem_stack_signal(Addr a, SizeT len, ThreadId tid)
1962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   new_mem_stack_2(len, "sig-new");
1964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void die_mem_stack_signal(Addr a, SizeT len)
1967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   die_mem_stack_2(len, "sig-die");
1969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
1973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--- Client Requests                                      ---//
1974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
1975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1976b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic void print_monitor_help ( void )
1977b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
1978b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_(gdb_printf) ("\n");
1979b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_(gdb_printf) ("massif monitor commands:\n");
1980b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_(gdb_printf) ("  snapshot [<filename>]\n");
1981b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_(gdb_printf) ("  detailed_snapshot [<filename>]\n");
1982b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_(gdb_printf) ("       takes a snapshot (or a detailed snapshot)\n");
1983b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_(gdb_printf) ("       and saves it in <filename>\n");
1984b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_(gdb_printf) ("             default <filename> is massif.vgdb.out\n");
1985b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_(gdb_printf) ("\n");
1986b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
1987b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1988b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1989b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Forward declaration.
1990b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return True if request recognised, False otherwise */
1991b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic Bool handle_gdb_monitor_command (ThreadId tid, Char *req);
1992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool ms_handle_client_request ( ThreadId tid, UWord* argv, UWord* ret )
1993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (argv[0]) {
1995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case VG_USERREQ__MALLOCLIKE_BLOCK: {
1996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      void* p   = (void*)argv[1];
1997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SizeT szB =        argv[2];
1998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      record_block( tid, p, szB, /*slop_szB*/0, /*exclude_first_entry*/False,
1999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    /*maybe_snapshot*/True );
2000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *ret = 0;
2001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
2002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2003b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   case VG_USERREQ__RESIZEINPLACE_BLOCK: {
2004b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      void* p        = (void*)argv[1];
2005b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      SizeT newSizeB =       argv[3];
2006b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
2007b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      unrecord_block(p, /*maybe_snapshot*/True);
2008b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      record_block(tid, p, newSizeB, /*slop_szB*/0,
2009b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                   /*exclude_first_entry*/False, /*maybe_snapshot*/True);
2010b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return True;
2011b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
2012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case VG_USERREQ__FREELIKE_BLOCK: {
2013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      void* p = (void*)argv[1];
2014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      unrecord_block(p, /*maybe_snapshot*/True);
2015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *ret = 0;
2016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
2017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2018b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   case VG_USERREQ__GDB_MONITOR_COMMAND: {
2019b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     Bool handled = handle_gdb_monitor_command (tid, (Char*)argv[1]);
2020b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     if (handled)
2021b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       *ret = 1;
2022b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     else
2023b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       *ret = 0;
2024b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     return handled;
2025b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
2026b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
2027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   default:
2028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *ret = 0;
2029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
2030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
2034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--- Instrumentation                                      ---//
2035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
2036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void add_counter_update(IRSB* sbOut, Int n)
2038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   #if defined(VG_BIGENDIAN)
2040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   # define END Iend_BE
2041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   #elif defined(VG_LITTLEENDIAN)
2042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   # define END Iend_LE
2043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   #else
2044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   # error "Unknown endianness"
2045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   #endif
2046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Add code to increment 'guest_instrs_executed' by 'n', like this:
2047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //   WrTmp(t1, Load64(&guest_instrs_executed))
2048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //   WrTmp(t2, Add64(RdTmp(t1), Const(n)))
2049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //   Store(&guest_instrs_executed, t2)
2050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t1 = newIRTemp(sbOut->tyenv, Ity_I64);
2051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t2 = newIRTemp(sbOut->tyenv, Ity_I64);
2052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* counter_addr = mkIRExpr_HWord( (HWord)&guest_instrs_executed );
2053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRStmt* st1 = IRStmt_WrTmp(t1, IRExpr_Load(END, Ity_I64, counter_addr));
2055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRStmt* st2 =
2056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_WrTmp(t2,
2057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   IRExpr_Binop(Iop_Add64, IRExpr_RdTmp(t1),
2058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           IRExpr_Const(IRConst_U64(n))));
2059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRStmt* st3 = IRStmt_Store(END, counter_addr, IRExpr_RdTmp(t2));
2060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB( sbOut, st1 );
2062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB( sbOut, st2 );
2063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB( sbOut, st3 );
2064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRSB* ms_instrument2( IRSB* sbIn )
2067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int   i, n = 0;
2069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRSB* sbOut;
2070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // We increment the instruction count in two places:
2072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // - just before any Ist_Exit statements;
2073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // - just before the IRSB's end.
2074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // In the former case, we zero 'n' and then continue instrumenting.
2075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sbOut = deepCopyIRSBExceptStmts(sbIn);
2077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < sbIn->stmts_used; i++) {
2079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt* st = sbIn->stmts[i];
2080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!st || st->tag == Ist_NoOp) continue;
2082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (st->tag == Ist_IMark) {
2084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         n++;
2085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else if (st->tag == Ist_Exit) {
2086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (n > 0) {
2087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // Add an increment before the Exit statement, then reset 'n'.
2088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            add_counter_update(sbOut, n);
2089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            n = 0;
2090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addStmtToIRSB( sbOut, st );
2093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (n > 0) {
2096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Add an increment before the SB end.
2097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add_counter_update(sbOut, n);
2098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sbOut;
2100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownIRSB* ms_instrument ( VgCallbackClosure* closure,
2104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      IRSB* sbIn,
2105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      VexGuestLayout* layout,
2106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      VexGuestExtents* vge,
2107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      IRType gWordTy, IRType hWordTy )
2108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (! have_started_executing_code) {
2110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Do an initial sample to guarantee that we have at least one.
2111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // We use 'maybe_take_snapshot' instead of 'take_snapshot' to ensure
2112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // 'maybe_take_snapshot's internal static variables are initialised.
2113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      have_started_executing_code = True;
2114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      maybe_take_snapshot(Normal, "startup");
2115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if      (clo_time_unit == TimeI)  { return ms_instrument2(sbIn); }
2118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (clo_time_unit == TimeMS) { return sbIn; }
2119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (clo_time_unit == TimeB)  { return sbIn; }
2120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else                              { tl_assert2(0, "bad --time-unit value"); }
2121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
2125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--- Writing snapshots                                    ---//
2126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
2127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownChar FP_buf[BUF_LEN];
2129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// XXX: implement f{,n}printf in m_libcprint.c eventually, and use it here.
2131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Then change Cachegrind to use it too.
2132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define FP(format, args...) ({ \
2133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(snprintf)(FP_buf, BUF_LEN, format, ##args); \
2134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FP_buf[BUF_LEN-1] = '\0';  /* Make sure the string is terminated. */ \
2135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(write)(fd, (void*)FP_buf, VG_(strlen)(FP_buf)); \
2136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown})
2137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Nb: uses a static buffer, each call trashes the last string returned.
2139f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Rootstatic Char* make_perc(double x)
2140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static Char mbuf[32];
2142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2143f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   VG_(percentify)((ULong)(x * 100), 10000, 2, 6, mbuf);
2144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // XXX: this is bogus if the denominator was zero -- resulting string is
2145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // something like "0 --%")
2146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (' ' == mbuf[0]) mbuf[0] = '0';
2147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return mbuf;
2148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void pp_snapshot_SXPt(Int fd, SXPt* sxpt, Int depth, Char* depth_str,
2151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Int depth_str_len,
2152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            SizeT snapshot_heap_szB, SizeT snapshot_total_szB)
2153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int   i, j, n_insig_children_sxpts;
2155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SXPt* child = NULL;
2156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Used for printing function names.  Is made static to keep it out
2158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // of the stack frame -- this function is recursive.  Obviously this
2159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // now means its contents are trashed across the recursive call.
2160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static Char ip_desc_array[BUF_LEN];
2161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char* ip_desc = ip_desc_array;
2162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sxpt->tag) {
2164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    case SigSXPt:
2165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Print the SXPt itself.
2166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0 == depth) {
2167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (clo_heap) {
2168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ip_desc =
2169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               ( clo_pages_as_heap
2170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               ? "(page allocation syscalls) mmap/mremap/brk, --alloc-fns, etc."
2171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               : "(heap allocation functions) malloc/new/new[], --alloc-fns, etc."
2172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
2173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
2174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // XXX: --alloc-fns?
2175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // If it's main-or-below-main, we (if appropriate) ignore everything
2178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // below it by pretending it has no children.
2179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if ( ! VG_(clo_show_below_main) ) {
2180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Vg_FnNameKind kind = VG_(get_fnname_kind_from_IP)(sxpt->Sig.ip);
2181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (Vg_FnNameMain == kind || Vg_FnNameBelowMain == kind) {
2182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               sxpt->Sig.n_children = 0;
2183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
2184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // We need the -1 to get the line number right, But I'm not sure why.
2187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ip_desc = VG_(describe_IP)(sxpt->Sig.ip-1, ip_desc, BUF_LEN);
2188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Do the non-ip_desc part first...
2191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FP("%sn%d: %lu ", depth_str, sxpt->Sig.n_children, sxpt->szB);
2192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // For ip_descs beginning with "0xABCD...:" addresses, we first
2194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // measure the length of the "0xabcd: " address at the start of the
2195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // ip_desc.
2196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      j = 0;
2197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ('0' == ip_desc[0] && 'x' == ip_desc[1]) {
2198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         j = 2;
2199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         while (True) {
2200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (ip_desc[j]) {
2201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (':' == ip_desc[j]) break;
2202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               j++;
2203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
2204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tl_assert2(0, "ip_desc has unexpected form: %s\n", ip_desc);
2205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
2206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Nb: We treat this specially (ie. we don't use FP) so that if the
2209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // ip_desc is too long (eg. due to a long C++ function name), it'll
2210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // get truncated, but the '\n' is still there so its a valid file.
2211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // (At one point we were truncating without adding the '\n', which
2212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // caused bug #155929.)
2213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //
2214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Also, we account for the length of the address in ip_desc when
2215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // truncating.  (The longest address we could have is 18 chars:  "0x"
2216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // plus 16 address digits.)  This ensures that the truncated function
2217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // name always has the same length, which makes truncation
2218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // deterministic and thus makes testing easier.
2219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(j <= 18);
2220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(snprintf)(FP_buf, BUF_LEN, "%s\n", ip_desc);
2221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FP_buf[BUF_LEN-18+j-5] = '.';    // "..." at the end make the
2222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FP_buf[BUF_LEN-18+j-4] = '.';    //   truncation more obvious.
2223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FP_buf[BUF_LEN-18+j-3] = '.';
2224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FP_buf[BUF_LEN-18+j-2] = '\n';   // The last char is '\n'.
2225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FP_buf[BUF_LEN-18+j-1] = '\0';   // The string is terminated.
2226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(write)(fd, (void*)FP_buf, VG_(strlen)(FP_buf));
2227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Indent.
2229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(depth+1 < depth_str_len-1);    // -1 for end NUL char
2230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      depth_str[depth+0] = ' ';
2231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      depth_str[depth+1] = '\0';
2232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Sort SXPt's children by szB (reverse order:  biggest to smallest).
2234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Nb: we sort them here, rather than earlier (eg. in dup_XTree), for
2235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // two reasons.  First, if we do it during dup_XTree, it can get
2236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // expensive (eg. 15% of execution time for konqueror
2237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // startup/shutdown).  Second, this way we get the Insig SXPt (if one
2238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // is present) in its sorted position, not at the end.
2239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(ssort)(sxpt->Sig.children, sxpt->Sig.n_children, sizeof(SXPt*),
2240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 SXPt_revcmp_szB);
2241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Print the SXPt's children.  They should already be in sorted order.
2243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_insig_children_sxpts = 0;
2244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < sxpt->Sig.n_children; i++) {
2245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         child = sxpt->Sig.children[i];
2246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (InsigSXPt == child->tag)
2248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            n_insig_children_sxpts++;
2249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Ok, print the child.  NB: contents of ip_desc_array will be
2251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // trashed by this recursive call.  Doesn't matter currently,
2252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // but worth noting.
2253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         pp_snapshot_SXPt(fd, child, depth+1, depth_str, depth_str_len,
2254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            snapshot_heap_szB, snapshot_total_szB);
2255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Unindent.
2258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      depth_str[depth+0] = '\0';
2259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      depth_str[depth+1] = '\0';
2260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // There should be 0 or 1 Insig children SXPts.
2262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(n_insig_children_sxpts <= 1);
2263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
2264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    case InsigSXPt: {
2266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Char* s = ( 1 == sxpt->Insig.n_xpts ? "," : "s, all" );
2267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FP("%sn0: %lu in %d place%s below massif's threshold (%s)\n",
2268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         depth_str, sxpt->szB, sxpt->Insig.n_xpts, s,
2269f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         make_perc(clo_threshold));
2270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
2271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
2272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    default:
2274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert2(0, "pp_snapshot_SXPt: unrecognised SXPt tag");
2275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void pp_snapshot(Int fd, Snapshot* snapshot, Int snapshot_n)
2279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sanity_check_snapshot(snapshot);
2281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FP("#-----------\n");
2283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FP("snapshot=%d\n", snapshot_n);
2284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FP("#-----------\n");
2285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FP("time=%lld\n",            snapshot->time);
2286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FP("mem_heap_B=%lu\n",       snapshot->heap_szB);
2287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FP("mem_heap_extra_B=%lu\n", snapshot->heap_extra_szB);
2288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FP("mem_stacks_B=%lu\n",     snapshot->stacks_szB);
2289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (is_detailed_snapshot(snapshot)) {
2291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Detailed snapshot -- print heap tree.
2292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int   depth_str_len = clo_depth + 3;
2293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Char* depth_str = VG_(malloc)("ms.main.pps.1",
2294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    sizeof(Char) * depth_str_len);
2295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SizeT snapshot_total_szB =
2296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         snapshot->heap_szB + snapshot->heap_extra_szB + snapshot->stacks_szB;
2297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      depth_str[0] = '\0';   // Initialise depth_str to "".
2298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FP("heap_tree=%s\n", ( Peak == snapshot->kind ? "peak" : "detailed" ));
2300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      pp_snapshot_SXPt(fd, snapshot->alloc_sxpt, 0, depth_str,
2301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       depth_str_len, snapshot->heap_szB,
2302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       snapshot_total_szB);
2303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(free)(depth_str);
2305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FP("heap_tree=empty\n");
2308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2311b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic void write_snapshots_to_file(Char* massif_out_file,
2312b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                    Snapshot snapshots_array[],
2313b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                    Int nr_elements)
2314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i, fd;
2316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes sres;
2317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sres = VG_(open)(massif_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
2319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     VKI_S_IRUSR|VKI_S_IWUSR);
2320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(sres)) {
2321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // If the file can't be opened for whatever reason (conflict
2322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // between multiple cachegrinded processes?), give up now.
2323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(umsg)("error: can't open output file '%s'\n", massif_out_file );
2324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(umsg)("       ... so profiling results will be missing.\n");
2325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
2326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fd = sr_Res(sres);
2328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Print massif-specific options that were used.
2331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // XXX: is it worth having a "desc:" line?  Could just call it "options:"
2332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // -- this file format isn't as generic as Cachegrind's, so the
2333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // implied genericity of "desc:" is bogus.
2334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FP("desc:");
2335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < VG_(sizeXA)(args_for_massif); i++) {
2336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Char* arg = *(Char**)VG_(indexXA)(args_for_massif, i);
2337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FP(" %s", arg);
2338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0 == i) FP(" (none)");
2340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FP("\n");
2341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Print "cmd:" line.
2343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FP("cmd: ");
2344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(args_the_exename)) {
2345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FP("%s", VG_(args_the_exename));
2346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
2347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HChar* arg = * (HChar**) VG_(indexXA)( VG_(args_for_client), i );
2348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (arg)
2349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            FP(" %s", arg);
2350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FP(" ???");
2353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FP("\n");
2355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FP("time_unit: %s\n", TimeUnit_to_string(clo_time_unit));
2357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2358b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   for (i = 0; i < nr_elements; i++) {
2359b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      Snapshot* snapshot = & snapshots_array[i];
2360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      pp_snapshot(fd, snapshot, i);     // Detailed snapshot!
2361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2362b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_(close) (fd);
2363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2365b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic void write_snapshots_array_to_file(void)
2366b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
2367b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // Setup output filename.  Nb: it's important to do this now, ie. as late
2368b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // as possible.  If we do it at start-up and the program forks and the
2369b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // output file format string contains a %p (pid) specifier, both the
2370b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // parent and child will incorrectly write to the same file;  this
2371b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // happened in 3.3.0.
2372b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Char* massif_out_file =
2373b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(expand_file_name)("--massif-out-file", clo_massif_out_file);
2374b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   write_snapshots_to_file (massif_out_file, snapshots, next_snapshot_i);
2375b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_(free)(massif_out_file);
2376b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
2377b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
2378b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic void handle_snapshot_monitor_command (Char *filename, Bool detailed)
2379b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
2380b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Snapshot snapshot;
2381b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
2382b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   clear_snapshot(&snapshot, /* do_sanity_check */ False);
2383b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   take_snapshot(&snapshot, Normal, get_time(), detailed);
2384b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   write_snapshots_to_file ((filename == NULL) ? (Char*) "massif.vgdb.out" : filename,
2385b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                            &snapshot,
2386b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                            1);
2387b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   delete_snapshot(&snapshot);
2388b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
2389b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
2390b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic Bool handle_gdb_monitor_command (ThreadId tid, Char *req)
2391b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
2392b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Char* wcmd;
2393b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Char s[VG_(strlen(req))]; /* copy for strtok_r */
2394b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Char *ssaveptr;
2395b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
2396b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_(strcpy) (s, req);
2397b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
2398b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   wcmd = VG_(strtok_r) (s, " ", &ssaveptr);
2399b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   switch (VG_(keyword_id) ("help snapshot detailed_snapshot",
2400b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                            wcmd, kwd_report_duplicated_matches)) {
2401b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   case -2: /* multiple matches */
2402b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return True;
2403b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   case -1: /* not found */
2404b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return False;
2405b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   case  0: /* help */
2406b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      print_monitor_help();
2407b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return True;
2408b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   case  1: { /* snapshot */
2409b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      Char* filename;
2410b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      filename = VG_(strtok_r) (NULL, " ", &ssaveptr);
2411b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      handle_snapshot_monitor_command (filename, False /* detailed */);
2412b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return True;
2413b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
2414b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   case  2: { /* detailed_snapshot */
2415b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      Char* filename;
2416b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      filename = VG_(strtok_r) (NULL, " ", &ssaveptr);
2417b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      handle_snapshot_monitor_command (filename, True /* detailed */);
2418b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return True;
2419b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
2420b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   default:
2421b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      tl_assert(0);
2422b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return False;
2423b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
2424b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
2425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
2427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--- Finalisation                                         ---//
2428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
2429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void ms_fini(Int exit_status)
2431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Output.
2433b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   write_snapshots_array_to_file();
2434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Stats
2436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(n_xpts > 0);  // always have alloc_xpt
2437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   STATS("heap allocs:           %u\n", n_heap_allocs);
2438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   STATS("heap reallocs:         %u\n", n_heap_reallocs);
2439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   STATS("heap frees:            %u\n", n_heap_frees);
2440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   STATS("ignored heap allocs:   %u\n", n_ignored_heap_allocs);
2441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   STATS("ignored heap frees:    %u\n", n_ignored_heap_frees);
2442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   STATS("ignored heap reallocs: %u\n", n_ignored_heap_reallocs);
2443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   STATS("stack allocs:          %u\n", n_stack_allocs);
2444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   STATS("stack frees:           %u\n", n_stack_frees);
2445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   STATS("XPts:                  %u\n", n_xpts);
2446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   STATS("top-XPts:              %u (%d%%)\n",
2447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      alloc_xpt->n_children,
2448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ( n_xpts ? alloc_xpt->n_children * 100 / n_xpts : 0));
2449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   STATS("XPt init expansions:   %u\n", n_xpt_init_expansions);
2450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   STATS("XPt later expansions:  %u\n", n_xpt_later_expansions);
2451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   STATS("SXPt allocs:           %u\n", n_sxpt_allocs);
2452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   STATS("SXPt frees:            %u\n", n_sxpt_frees);
2453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   STATS("skipped snapshots:     %u\n", n_skipped_snapshots);
2454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   STATS("real snapshots:        %u\n", n_real_snapshots);
2455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   STATS("detailed snapshots:    %u\n", n_detailed_snapshots);
2456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   STATS("peak snapshots:        %u\n", n_peak_snapshots);
2457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   STATS("cullings:              %u\n", n_cullings);
2458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   STATS("XCon redos:            %u\n", n_XCon_redos);
2459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
2463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--- Initialisation                                       ---//
2464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------//
2465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void ms_post_clo_init(void)
2467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
2469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char* LD_PRELOAD_val;
2470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char* s;
2471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char* s2;
2472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Check options.
2474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (clo_pages_as_heap) {
2475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (clo_stacks) {
2476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(fmsg_bad_option)(
2477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            "--pages-as-heap=yes together with --stacks=yes", "");
2478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!clo_heap) {
2481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      clo_pages_as_heap = False;
2482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // If --pages-as-heap=yes we don't want malloc replacement to occur.  So we
2485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // disable vgpreload_massif-$PLATFORM.so by removing it from LD_PRELOAD (or
2486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // platform-equivalent).  We replace it entirely with spaces because then
2487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // the linker doesn't complain (it does complain if we just change the name
2488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // to a bogus file).  This is a bit of a hack, but LD_PRELOAD is setup well
2489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // before tool initialisation, so this seems the best way to do it.
2490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (clo_pages_as_heap) {
2491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      clo_heap_admin = 0;     // No heap admin on pages.
2492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      LD_PRELOAD_val = VG_(getenv)( (Char*)VG_(LD_PRELOAD_var_name) );
2494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(LD_PRELOAD_val);
2495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Make sure the vgpreload_core-$PLATFORM entry is there, for sanity.
2497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s2 = VG_(strstr)(LD_PRELOAD_val, "vgpreload_core");
2498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(s2);
2499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Now find the vgpreload_massif-$PLATFORM entry.
2501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s2 = VG_(strstr)(LD_PRELOAD_val, "vgpreload_massif");
2502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(s2);
2503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Blank out everything to the previous ':', which must be there because
2505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // of the preceding vgpreload_core-$PLATFORM entry.
2506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (s = s2; *s != ':'; s--) {
2507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *s = ' ';
2508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Blank out everything to the end of the entry, which will be '\0' if
2511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // LD_PRELOAD was empty before Valgrind started, or ':' otherwise.
2512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (s = s2; *s != ':' && *s != '\0'; s++) {
2513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *s = ' ';
2514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Print alloc-fns and ignore-fns, if necessary.
2518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_verbosity) > 1) {
2519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VERB(1, "alloc-fns:\n");
2520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < VG_(sizeXA)(alloc_fns); i++) {
2521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Char** fn_ptr = VG_(indexXA)(alloc_fns, i);
2522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VERB(1, "  %s\n", *fn_ptr);
2523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VERB(1, "ignore-fns:\n");
2526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0 == VG_(sizeXA)(ignore_fns)) {
2527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VERB(1, "  <empty>\n");
2528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < VG_(sizeXA)(ignore_fns); i++) {
2530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Char** fn_ptr = VG_(indexXA)(ignore_fns, i);
2531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VERB(1, "  %d: %s\n", i, *fn_ptr);
2532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Events to track.
2536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (clo_stacks) {
2537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(track_new_mem_stack)        ( new_mem_stack        );
2538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(track_die_mem_stack)        ( die_mem_stack        );
2539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(track_new_mem_stack_signal) ( new_mem_stack_signal );
2540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(track_die_mem_stack_signal) ( die_mem_stack_signal );
2541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (clo_pages_as_heap) {
2544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(track_new_mem_startup) ( ms_new_mem_startup );
2545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(track_new_mem_brk)     ( ms_new_mem_brk     );
2546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(track_new_mem_mmap)    ( ms_new_mem_mmap    );
2547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(track_copy_mem_remap)  ( ms_copy_mem_remap  );
2549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(track_die_mem_brk)     ( ms_die_mem_brk     );
2551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(track_die_mem_munmap)  ( ms_die_mem_munmap  );
2552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Initialise snapshot array, and sanity-check it.
2555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   snapshots = VG_(malloc)("ms.main.mpoci.1",
2556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           sizeof(Snapshot) * clo_max_snapshots);
2557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // We don't want to do snapshot sanity checks here, because they're
2558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // currently uninitialised.
2559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < clo_max_snapshots; i++) {
2560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      clear_snapshot( & snapshots[i], /*do_sanity_check*/False );
2561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sanity_check_snapshots_array();
2563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void ms_pre_clo_init(void)
2566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(details_name)            ("Massif");
2568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(details_version)         (NULL);
2569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(details_description)     ("a heap profiler");
2570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(details_copyright_author)(
2571b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      "Copyright (C) 2003-2011, and GNU GPL'd, by Nicholas Nethercote");
2572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(details_bug_reports_to)  (VG_BUGS_TO);
2573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2574b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_(details_avg_translation_sizeB) ( 330 );
2575b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
2576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Basic functions.
2577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(basic_tool_funcs)          (ms_post_clo_init,
2578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   ms_instrument,
2579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   ms_fini);
2580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Needs.
2582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(needs_libc_freeres)();
2583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(needs_command_line_options)(ms_process_cmd_line_option,
2584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   ms_print_usage,
2585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   ms_print_debug_usage);
2586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(needs_client_requests)     (ms_handle_client_request);
2587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(needs_sanity_checks)       (ms_cheap_sanity_check,
2588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   ms_expensive_sanity_check);
2589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(needs_malloc_replacement)  (ms_malloc,
2590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   ms___builtin_new,
2591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   ms___builtin_vec_new,
2592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   ms_memalign,
2593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   ms_calloc,
2594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   ms_free,
2595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   ms___builtin_delete,
2596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   ms___builtin_vec_delete,
2597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   ms_realloc,
2598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   ms_malloc_usable_size,
2599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   0 );
2600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // HP_Chunks.
2602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   malloc_list = VG_(HT_construct)( "Massif's malloc list" );
2603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Dummy node at top of the context structure.
2605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   alloc_xpt = new_XPt(/*ip*/0, /*parent*/NULL);
2606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Initialise alloc_fns and ignore_fns.
2608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   init_alloc_fns();
2609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   init_ignore_fns();
2610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Initialise args_for_massif.
2612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args_for_massif = VG_(newXA)(VG_(malloc), "ms.main.mprci.1",
2613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                VG_(free), sizeof(HChar*));
2614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownVG_DETERMINE_INTERFACE_VERSION(ms_pre_clo_init)
2617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--------------------------------------------------------------------//
2619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--- end                                                          ---//
2620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//--------------------------------------------------------------------//
2621