2014-07-04

Benchmarking Perl Code

(Up-to-date source of this post.)

Sometimes my code takes a really long time to run and I'd like to know which of the alternatives runs faster.

In this example I compare two sorting subroutines; a "naive" approach and "The Schwartzian Transform". The former subroutine just compares all files' sizes to each other while the latter first precomputes the size of each file and then does the comparisons.

use Benchmark qw(timethese);

chdir;    # change to my home directory
my @files = glob '*';

timethese(
    -2,
    {
        naive => sub {
            my @sorted = sort { -s $a <=> -s $b } @files;
        },
        schwartzian => sub {
            my @sorted =
              map  { $_->[0] }
              sort { $a->[1] <=> $b->[1] }
              map  { [ $_, -s $_ ] } @files;
        },
    }
);

The program's output:

Benchmark: running naive, schwartzian for at least 2 CPU seconds...
     naive:  2 wallclock secs ( 0.58 usr +  1.49 sys =  2.07 CPU) @ 11661.84/s (n=24140)
schwartzian:  2 wallclock secs ( 1.57 usr +  0.59 sys =  2.16 CPU) @ 21200.00/s (n=45792)

The output says that the Schwartzian Transform is much faster (the function ran more times in 2 seconds). The reason is that we don't ask for the file size each time we want to compare two files sizes; we ask just once for each file size.

See Also

  • http://perldoc.perl.org/Benchmark.html
  • Intermediate Perl, 2nd, p. 144
  • http://www.perlmonks.com/?node_id=393128

2014-07-03

SSH Tunnel

(Up-to-date source of this post.)

Forwarding remote port (firewall tunneling via SSH)

We want to allow the tech access the incomp (intranet) host from the outcomp.sk (Internet) host:

1) Redirect the port 2222 on outcomp.sk to port 22 on incomp:

incomp:~$ ssh -R 2222:localhost:22 user@outcomp.sk
outcomp.sk:~$ while [ 1 ]; do date; sleep 300; done  # to keep the connection open

2) Connect to intranet host:

outcomp.sk:~$ ssh -p 2222 root@localhost

We want to connect to router web interface (to make some configuration changes) which is not accessible from Internet. However we can connect to a Linux server behind the router.

1) /etc/ssh/sshd_config of host.in.internet.com has to contain:

GatewayPorts yes

2) LAN (intranet) host:

ssh -R "*:3333:192.168.1.1:443" host.in.internet.com

3) Web browser somewhere in Internet:

https://host.in.internet.com:3333

Forwarding local port

We want to connect to a remote database running on dbserver but it is configured to allow connections only from localhost (127.0.0.1). We use port 3307 on the client because the default 3306 port is already being used (e.g. you are running MySQL server on the client).

client:~$ ssh -L 3307:localhost:3306 root@dbserver
client:~$ mysql -u root -p dbname -P 3307

See also