[comp.lang.c] funcsize: determine size cost of a C function

tchrist@convex.com (Tom Christiansen) (10/14/90)

I was wondering how much certain C functions cost in terms of executable
size, so I wrote this quick little script and got some interesting results.
cuserid() ended up costing the most in my libc, since it calls getpw*() and
ends up sucking in all the YP foo).  Some of the graphics stuff was
staggering: the XmCommandError example listed below yielded 1.4 *megabytes*!

--tom

#!/usr/bin/perl
#
# funcsize - find a function's size overhead
# tom christiansen, 13-oct-90
#
# USAGE: funcsize [-lxxx ...] [function ...]
#
# default library is libc
# default function is all in first library
#
# functions that say they're size 0 got included by crt0,
# or you've got shared libraries.
#
# EXAMPLES:
#	funcsize 		
#	funcsize gethostbyaddr getuid printf scanf
#	funcsize -lX11
#	funcsize -lm cos atan2 gamma
#	funcsize -lXm -lXt -lMrm -lX11 XmCommandError
#
# PORTING CAVEATS:
#	knows what nm output looks like
#	knows where libraries live
#
##################################################################

printf $mask = "%-30s %8d\n", "main", $main_size = &compile_size("");

push(@Libraries, shift) 	while $ARGV[0] =~ /^-l/;

(@Functions = @ARGV) || &load_library();

for $fun (@Functions) {
    next unless $bytes = &compile_size($fun);
    printf $mask, $fun, $bytes - $main_size;
}

exit 0;

# ------------------------------------------------------------------------

sub load_library {
    local($lib) = ($Libraries[0] =~ /^-l(\w+)/)
		    ? "/usr/lib/lib$1.a"
		    : "/lib/libc.a";

    open(LIB, "nm $lib|");
    while (<LIB>) {
	# skip _ident functions, allow $ in idents
	next unless /\s+T\s+_([^_][\w\$]+)/;
	push(@Functions, $1);
    }
    close LIB;
    die "bad close on nm $lib (status $?)" if $?;
}

# ------------------------------------------------------------------------

sub compile_size {
    local($fun)  = @_;
    local($size) = 0;
    local($TMP)  = "/tmp/cc-$$";

    open (TMP, ">$TMP.c") 	|| die "can't open $TMP.c: $!";
    print TMP "main() {";
    print TMP "int i = $fun();"    if $fun;
    print TMP "}\n";
    close TMP 			|| die "can't close $TMP: $!";

    print `cc $TMP.c -o $TMP @Libraries`;

    unless ($?) {
	(($size) = (stat($TMP))[7]) || warn "can't stat: $TMP: $!\n";
    }

    unlink "$TMP.c", "$TMP.o", $TMP;
    return $size;
}