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