Skip to content

Instantly share code, notes, and snippets.

@trwyant

trwyant/state Secret

Created February 4, 2016 23:22
Show Gist options
  • Select an option

  • Save trwyant/d96fb327b6fe08f774e0 to your computer and use it in GitHub Desktop.

Select an option

Save trwyant/d96fb327b6fe08f774e0 to your computer and use it in GitHub Desktop.
Stupid state trick

TITLE

state - Demonstrate and time various Perl module loading algorithms

SYNOPSIS

state
state -algorithm null -algorithm state
state -iterations 100000000
state -help
state -version

OPTIONS

-algorithm

-algorithm null

This option specifies what module loading algorithm to benchmark. It can be specified more than once. The valid algorithm names are documented under ALGORITHMS

The default is to benchmark all programmed algorithms, in ASCIIbetical order.

-help

This option displays the documentation for this script. The script then exits.

-iterations

-iterations 100000000

This option specifies how many times the tested subroutine is called.

The default is -iterations 10 which is sufficient for demonstration purposes, but grossly insufficient for benchmarking.

-version

This option displays the version of this script. The script then exits.

DETAILS

This Perl script is used to explore the magnitude of the time saving (if any) involved in various approaches to loading Perl modules at execution time. It was originally written to investigate the behavior of the state algorithm.

This code contains a commented-out override of the core require() subroutine, which can be uncommented to demonstrate how often require() is called by each algorithm. You do not want this override enabled if you are doing large numbers of iterations, because of the volume of output that can be generated, and because of the extra overhead imposed on algorithms that call require once for each invocation.

ALGORITHMS

The following algorithms for run-time module loading are supported. For narrative convenience the algorithms are documented below as though they were normal subroutines, but they are actually implemented as anonymous subroutines in a hash keyed by algorithm name.

conditional

my $conditional;
 
sub test_conditional {
        $conditional
            or require YAML;
        $conditional = 1;
        return;
}

Something like this is the way to explicitly ensure require YAML is executed only once in pre-5.10 Perl.

null

sub test_null {
        return;
}

This is included to give an estimate of the amount of time spent simply calling the code being tested.

require

sub test_require {
        require YAML;
        return;
}

The require() built-in is idempotent, so the YAML module is only loaded once however many times this code is executed. But require() is executed at every call.

state

sub test_state {
        state $dummy = require YAML;
        return;
}

THe state() built-in was introduced in Perl 5.10. It creates a lexical variable, but the assignment is only done the first time it is encountered. It occurred to me that if the right-hand side of the assignment were a require(), then it would only be executed the first time it was encountered.

RESULTS

Running 10**9 iterations of all four algorithms on a system with no other user-requested load produced the following results:

Benchmark: timing 1000000000 iterations of conditional, null, require, state...
conditional: 48 wallclock secs (48.04 usr +  0.00 sys = 48.04 CPU) @ 20815986.68/s (n=1000000000)
      null:  9 wallclock secs ( 8.45 usr +  0.01 sys =  8.46 CPU) @ 118203309.69/s (n=1000000000)
   require: 70 wallclock secs (70.41 usr + -0.03 sys = 70.38 CPU) @ 14208581.98/s (n=1000000000)
     state: 24 wallclock secs (22.92 usr + -0.01 sys = 22.91 CPU) @ 43649061.55/s (n=1000000000)

Deducting the time of the null algorithm from each of the others produces:

require: 61 wallclock secs @ 16393442.62/s
 conditional: 39 wallclock secs @ 25641025.64/s
  state: 15 wallclock secs @ 66666666.67/s

Two conclusions appear to be reasonable:

  • Under the test conditions the state algorithm is significantly faster than just making use of require's idempotence. If that is unavailable, an explicit conditional is still a win.

  • Unless you anticipate truly staggering numbers of iterations, the difference is probably not worth worrying about.

AUTHOR

Thomas R. Wyant, III wyant at cpan dot org

COPYRIGHT AND LICENSE

Copyright (C) 2016 by Thomas R. Wyant, III

This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the Artistic License 1.0 at http://www.perlfoundation.org/artistic_license_1_0, and/or the Gnu GPL at http://www.gnu.org/licenses/old-licenses/gpl-1.0.txt.

This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment