#!/usr/local/bin/perl # cache-compare.pl # # Duane Wessels, Dec 1995 # # A simple perl script to compare how long it takes to fetch an object # from a number of different caches. # # stdin is a list of URLs. Set the @getfrom array to a list of caches # to fetch each URL from. Include 'SOURCE' in @getfrom to fetch from # the source host also. For each URL, print the byte count, elapsed # time and average data rate. At the end print out some averages. # # NOTE: uses the Perl function syscall() to implement gettimeofday(2). # Assumes that gettimeofday is syscall #116 on the system # (see /usr/include/sys/syscall.h). # # BUGS: # Should probably cache the gethostbyname() calls. @getfrom = ('SOURCE', 'localhost:3128'); require 'sys/socket.ph'; $gettimeofday = 116; # cheating, should use require syscall.ph while (<>) { chop ($url = $_); print "$url:\n"; foreach $k (@getfrom) { printf "%30.30s:\t", $k; if ($k eq 'SOURCE') { ($b_sec,$b_usec) = &gettimeofday; $n = &get_from_source($url); ($e_sec,$e_usec) = &gettimeofday; } else { ($host,$port) = split (':', $k); ($b_sec,$b_usec) = &gettimeofday; $n = &get_from_cache($host,$port,$url); ($e_sec,$e_usec) = &gettimeofday; } next unless ($n > 0); $d = ($e_sec - $b_sec) * 1000000 + ($e_usec - $b_usec); $d /= 1000000; $r = $n / $d; printf "%8.1f b/s (%7d bytes, %7.3f sec)\n", $r, $n, $d; $bps_sum{$k} += $r; $bps_n{$k}++; $bytes_sum{$k} += $n; $sec_sum{$k} += $d; } } print "AVERAGE b/s rates:\n"; foreach $k (@getfrom) { printf "%30.30s:\t%8.1f b/s (Alt: %8.1f b/s)\n", $k, $bps_sum{$k} / $bps_n{$k}, $bytes_sum{$k} / $sec_sum{$k}; } exit 0; sub get_from_source { local($url) = @_; local($bytes) = 0; unless ($url =~ m!([a-z]+)://([^/]+)(.*)$!) { printf "get_from_source: bad URL\n"; return 0; } $proto = $1; $host = $2; $url_path = $3; unless ($proto eq 'http') { printf "get_from_source: I only do HTTP\n"; return 0; } $port = 80; if ($host =~ /([^:]+):(\d+)/) { $host = $1; $port = $2; } return 0 unless ($SOCK = &client_socket($host,$port)); print $SOCK "GET $url_path HTTP/1.0\r\nAccept */*\r\n\r\n"; $bytes += $n while (($n = read(SOCK,$_,4096)) > 0); close $SOCK; return $bytes; } sub get_from_cache { local($host,$port,$url) = @_; local($bytes) = 0; return 0 unless ($SOCK = &client_socket($host,$port)); print $SOCK "GET $url HTTP/1.0\r\nAccept */*\r\n\r\n"; $bytes += $n while (($n = read(SOCK,$_,4096)) > 0); close $SOCK; return $bytes; } sub client_socket { local ($host, $port) = @_; local ($sockaddr) = 'S n a4 x8'; local ($name, $aliases, $proto) = getprotobyname('tcp'); local ($connected) = 0; # Lookup addresses for remote hostname # local($w,$x,$y,$z,@thataddrs) = gethostbyname($host); unless (@thataddrs) { printf "Unknown Host: $host\n"; return (); } # bind local socket to INADDR_ANY # local ($thissock) = pack($sockaddr, &AF_INET, 0, "\0\0\0\0"); unless (socket (SOCK, &AF_INET, &SOCK_STREAM, $proto)) { printf "socket: $!\n"; return (); } unless (bind (SOCK, $thissock)) { printf "bind: $!\n"; return (); } # Try all addresses # foreach $thataddr (@thataddrs) { local ($that) = pack($sockaddr, &AF_INET, $port, $thataddr); if (connect (SOCK, $that)) { $connected = 1; last; } } unless ($connected) { printf "$host:$port: $!\n"; return (); } # Set socket to flush-after-write and return it # select (SOCK); $| = 1; select (STDOUT); return (SOCK); } sub gettimeofday { $tvp="\0\0\0\0\0\0\0\0"; syscall($gettimeofday, $tvp, $tz); return unpack('ll', $tvp); }