This change adds simple memory profiling using tcmalloc [1].

The ubuntu still offers to process the data using the
perl version of pprof [2] (called pprof-symbolize) on Ubuntu-24.

At this point we want to collect just memory usage data
for every test we run. The plan is to start collecting those
data so we can observe how memory usage changes between the builds.

To collect the data just do:
	DO_MPROFILE=1 \
	LIBMPROFILE=/path/to/tcmalloc.so \
	make test
the tcmalloc library on Ubuntu-24 is installed at
	/usr/lib/x86_64-linux-gnu/libtcmalloc_and_profiler.so

The 'make test' command processes collected data and stores
results in test-run directory. For example the result for
test_errstr test number 48 is found in file:
	test-runs/test_errstr/test_errstr_48.result
the .result file reads as follows:
../../apps/openssl errstr 80000030
Total: 262707 B

I'm still not clear on what 'Total' means here. I need to better understand
what profile sample data conatin and when the sample is created. My assumption
is the sample is saved when application exits.

[1] https://github.com/gperftools/gperftools

[2] https://gperftools.github.io/gperftools/heapprofile.html
This commit is contained in:
sashan 2025-03-27 11:03:18 +01:00
parent 064bb16454
commit 7a47104f07
3 changed files with 62 additions and 0 deletions

View File

@ -13,6 +13,9 @@ use warnings;
use Carp;
use Test::More 0.96;
use File::Basename;
use File::Spec::Functions 'catfile';
use Exporter;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
$VERSION = "1.0";
@ -1294,6 +1297,45 @@ sub __decorate_cmd {
unless $stderr || !$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE};
}
if ($ENV{DO_MPROFILE}) {
my $file_name;
my $glob_pattern = catfile(result_dir(), "$test_name"."*.result");
my $index = 0;
#
# some tests execute more than one command, we need to capture
# data for each command invocation.
#
# loop here finds the next index to continue.
#
foreach $file_name ( glob($glob_pattern) ) {
$file_name = basename($file_name);
if ($file_name =~ m/.*_(\d+).result/) {
if ($index < $1) {
$index = $1;
}
}
}
$index = $index + 1;
$file_name = "$test_name"."_"."$index".".result";
open(MARKER, ">$file_name");
close(MARKER);
# the result is collected in shlib_wrap.sh
$ENV{MPROFILE_RESULT}=$file_name;
#
# tcmalloc collecta at least one profile record
# saved to test_name-xx.yyyy.heap
# By default tcmalloc creates such profile for every
# GB of memory program allocates. More details
# on how to control the collection of data can
# be found here:
# https://gperftools.github.io/gperftools/heapprofile.html
#
$file_name = "$test_name"."_"."$index";
$ENV{HEAPPROFILE}=$file_name;
}
$cmdstr .= "$stdin$stdout$stderr";
if ($debug) {

View File

@ -105,6 +105,9 @@ NONSTOP_KERNEL)
if [ "$OSTYPE" != msdosdjgpp ]; then
PATH="${THERE}:$PATH"; export PATH
fi
if [ "${DO_MPROFILE}" -eq 1 ] ; then
export LD_PRELOAD="${LIBMPROFILE}"
fi
;;
esac
@ -129,7 +132,13 @@ fi
cmd="$1"; [ -x "$cmd" ] || cmd="$cmd${EXE_EXT}"
shift
if [ $# -eq 0 ]; then
if [ "${DO_MPROFILE}" -eq 1 ] ; then
echo "$cmd" > ${MPROFILE_RESULT}
fi
exec "$cmd" # old sh, such as Tru64 4.x, fails to expand empty "$@"
else
if [ "${DO_MPROFILE}" -eq 1 ] ; then
echo "$cmd" "$@" > ${MPROFILE_RESULT}
fi
exec "$cmd" "$@"
fi

View File

@ -92,6 +92,17 @@ if ($^O eq 'VMS') {
# from the call, so we resort to using system() instead.
my $waitcode = system @cmd;
if ( $ENV{DO_MPROFILE} ) {
my $prof = "$ENV{HEAPPROFILE}".".0001.heap";
my $result = "$ENV{MPROFILE_RESULT}";
my $pprof_cmd = "pprof-symbolize --text --show_bytes --alloc_space";
$pprof_cmd = "$pprof_cmd "."$cmd[1]"." $prof"." |grep '^Total' >>";
$pprof_cmd = "$pprof_cmd"." $result";
system $pprof_cmd;
unlink( ( $prof ) );
}
# According to documentation, -1 means that system() couldn't run the command,
# otherwise, the value is similar to the Unix wait() status value
# (exitcode << 8 | signalcode)