15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/bin/sh
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2005, Google Inc.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# All rights reserved.
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Redistribution and use in source and binary forms, with or without
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# modification, are permitted provided that the following conditions are
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# met:
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#     * Redistributions of source code must retain the above copyright
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# notice, this list of conditions and the following disclaimer.
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#     * Redistributions in binary form must reproduce the above
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# copyright notice, this list of conditions and the following disclaimer
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# in the documentation and/or other materials provided with the
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# distribution.
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#     * Neither the name of Google Inc. nor the names of its
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# contributors may be used to endorse or promote products derived from
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# this software without specific prior written permission.
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# ---
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Author: Craig Silverstein
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Runs the heap-profiler unittest and makes sure the profile looks appropriate.
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# We run under the assumption that if $HEAP_PROFILER is run with --help,
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# it prints a usage line of the form
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   USAGE: <actual executable being run> [...]
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# This is because libtool sometimes turns the 'executable' into a
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# shell script which runs an actual binary somewhere else.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# We expect BINDIR and PPROF_PATH to be set in the environment.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# If not, we set them to some reasonable values
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BINDIR="${BINDIR:-.}"
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PPROF_PATH="${PPROF_PATH:-$BINDIR/src/pprof}"
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if [ "x$1" = "x-h" -o "x$1" = "x--help" ]; then
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo "USAGE: $0 [unittest dir] [path to pprof]"
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo "       By default, unittest_dir=$BINDIR, pprof_path=$PPROF_PATH"
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  exit 1
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)fi
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HEAP_PROFILER="${1:-$BINDIR}/heap-profiler_unittest"
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PPROF="${2:-$PPROF_PATH}"
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_TMPDIR=/tmp/heap_profile_info
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# It's meaningful to the profiler, so make sure we know its state
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)unset HEAPPROFILE
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)rm -rf "$TEST_TMPDIR"
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)mkdir "$TEST_TMPDIR" || exit 2
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)num_failures=0
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Given one profile (to check the contents of that profile) or two
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# profiles (to check the diff between the profiles), and a function
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# name, verify that the function name takes up at least 90% of the
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# allocated memory.  The function name is actually specified first.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VerifyMemFunction() {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  function="$1"
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shift
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # get program name.  Note we have to unset HEAPPROFILE so running
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # help doesn't overwrite existing profiles.
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  exec=`unset HEAPPROFILE; $HEAP_PROFILER --help | awk '{print $2; exit;}'`
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if [ $# = 2 ]; then
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    [ -f "$1" ] || { echo "Profile not found: $1"; exit 1; }
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    [ -f "$2" ] || { echo "Profile not found: $2"; exit 1; }
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    $PPROF --base="$1" $exec "$2" >"$TEST_TMPDIR/output.pprof" 2>&1
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    [ -f "$1" ] || { echo "Profile not found: $1"; exit 1; }
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    $PPROF $exec "$1" >"$TEST_TMPDIR/output.pprof" 2>&1
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fi
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cat "$TEST_TMPDIR/output.pprof" \
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      | tr -d % | awk '$6 ~ /^'$function'$/ && $2 > 90 {exit 1;}'
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if [ $? != 1 ]; then
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    echo
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    echo "--- Test failed for $function: didn't account for 90% of executable memory"
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    echo "--- Program output:"
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cat "$TEST_TMPDIR/output"
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    echo "--- pprof output:"
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cat "$TEST_TMPDIR/output.pprof"
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    echo "---"
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    num_failures=`expr $num_failures + 1`
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fi
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VerifyOutputContains() {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  text="$1"
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ! grep "$text" "$TEST_TMPDIR/output" >/dev/null 2>&1; then
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    echo "--- Test failed: output does not contain '$text'"
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    echo "--- Program output:"
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cat "$TEST_TMPDIR/output"
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    echo "---"
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    num_failures=`expr $num_failures + 1`
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fi
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HEAPPROFILE="$TEST_TMPDIR/test"
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HEAP_PROFILE_INUSE_INTERVAL="10240"   # need this to be 10Kb
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HEAP_PROFILE_ALLOCATION_INTERVAL="$HEAP_PROFILE_INUSE_INTERVAL"
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HEAP_PROFILE_DEALLOCATION_INTERVAL="$HEAP_PROFILE_INUSE_INTERVAL"
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)export HEAPPROFILE
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)export HEAP_PROFILE_INUSE_INTERVAL
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)export HEAP_PROFILE_ALLOCATION_INTERVAL
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)export HEAP_PROFILE_DEALLOCATION_INTERVAL
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# We make the unittest run a child process, to test that the child
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# process doesn't try to write a heap profile as well and step on the
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# parent's toes.  If it does, we expect the parent-test to fail.
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$HEAP_PROFILER 1 >$TEST_TMPDIR/output 2>&1     # run program, with 1 child proc
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VerifyMemFunction Allocate2 "$HEAPPROFILE.1329.heap"
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VerifyMemFunction Allocate "$HEAPPROFILE.1448.heap" "$HEAPPROFILE.1548.heap"
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Check the child process got to emit its own profile as well.
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VerifyMemFunction Allocate2 "$HEAPPROFILE"_*.1329.heap
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VerifyMemFunction Allocate "$HEAPPROFILE"_*.1448.heap "$HEAPPROFILE"_*.1548.heap
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Make sure we logged both about allocating and deallocating memory
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VerifyOutputContains "62 MB allocated"
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VerifyOutputContains "62 MB freed"
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Now try running without --heap_profile specified, to allow
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# testing of the HeapProfileStart/Stop functionality.
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$HEAP_PROFILER >"$TEST_TMPDIR/output2" 2>&1
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)rm -rf $TMPDIR      # clean up
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if [ $num_failures = 0 ]; then
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo "PASS"
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)else
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  echo "Tests finished with $num_failures failures"
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)fi
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)exit $num_failures
151