Robert Acock 🤞🌏💯
and 1 contributors

NAME

Benchmark::Thread::Size - report size of threads for different code approaches

SYNOPSIS

  use Benchmark::Thread::Size times => 5, noexport => <<'E1', export => <<'E2';
  use threads::shared ();
  E1
  use threads::shared;
  E2

  use Benchmark::Thread::Size 'refonly';    # do reference run only

  perl -MBenchmark::Thread::Size=times,100  # as a one-liner for developers

DESCRIPTION

                  *** A note of CAUTION ***

 This module only functions on Perl versions 5.8.0 and later.
 And then only when threads are enabled with -Dusethreads.  It
 is of no use with any version of Perl before 5.8.0 or without
 threads enabled.

                  *************************

The Benchmark::Thread::Size module reports how much memory is used by different pieces of source code within a threaded application. This allows you to test different approaches to coding a specific threaded application or to find ways how to reduce memory usage of threads in general.

It achieves this goal by running the indicated code with a varying number of threads and asking the operating system how much memory is in use. This is an empirical process that may take quite some time on slower machines.

One or more approaches can be checked at a time, each tested 10 times by default. Each approach is compared to an empty piece of code (the reference) to allow you to easily determine how much memory each different approach has taken. Testing is done for 0, 1, 2, 5, 10, 20, 50 and 100 threads. The code you specify is only entered once in the main thread and consequently cloned to all threads when they are created (which is where it becomes very important to reduce as much as possible.

The final report is sent to STDOUT. This is an example report:

   #   (ref)        bare        full        vars         our      unique
   0    2172          +0          +0          +0          +0          +0    
   1    2624 ± 4      +4 ± 4      +4 ± 4     +27          +4 ± 4     +27    
   2    3004 ± 4      +2 ± 6      +2 ± 6     +33 ± 4      +8         +36 ± 6
   5    4126 ± 6      -2 ± 6      -3 ± 8     +29 ± 4     +10 ± 2     +27 ± 4
  10    5984 ± 8      -1 ± 8      +0 ± 4      +0 ± 6     +17 ± 4     +43 ± 6
  20    9694 ± 4     +15 ± 4     +15 ± 2     +13 ± 6     +32 ± 6     +58 ± 6
  50   20832 ± 4     +51 ±10     +50 ± 8     +50 ± 8     +68 ±12     +96 ± 6
 100   39392 ± 8    +106 ±10    +156 ±12    +108 ±10    +131 ±10    +155 ±12
 
 ==== bare ========================================================
 $VERSION = '0.01';
 
 ==== full ========================================================
 $main::VERSION = '0.01';
 
 ==== vars ========================================================
 use vars qw($VERSION);
 $VERSION = '0.01';
 
 ==== our =========================================================
 our $VERSION = '0.01';
 
 ==== unique ======================================================
 our $VERSION : unique = '0.01';
 
 ==================================================================

The first column shows the reference amount (the amount of memory used without adding any specific code). All other columns show the difference with the amounts from the first column.

The sizes given are the numbers that were obtained from the system for the size of the process. This is usually in Kbytes but could be anything, depending on how the information about the memory usage is obtained.

Since starting threads can have non-deterministic effects on the amount of memory used, each number of threads is tried 10 times by default. The average of the amount of memory used is shown. If the amount was not always the same for the same piece of code and number of threads, a deviation (in the form ±10) is also shown.

So, what does this report tell us? That it seems that it is better to use a bare $VERSION in a module in a Perl module that is going to be used with threads. And that contrary from what you would like to believe, the ":unique" attribute does not save any memory: it even causes threads to use more memory. And that strangely enough using a fully qualified $module::VERSION seems to be equivalent to using a bare $VERSION upto 50 threads. At 100 threads however, the fully qualified $module::VERSION seems to use as much as with the ":unique" attribute. Who knows what's going on there.

PARAMETERS

You can specify the following parameters with the use command.

times => 5

The word 'times' followed by a numeric value, indicates how many times each run will be executed. The default is 10.

'refonly'

The word 'refonly' indicates that the reference runs will be executed even if there is no further code specified. This is important mostly when trying different approaches to the Perl core modules or when benchmarking different versions of Perl. This is the default if the module is loaded as a one-liner.

identifier => 'code'

Any other string followed by Perl code (as a string) indicates a set of runs to be executed.

SUBROUTINES

There are no subroutines to call: all values need to be specified with the use command in source, or as parameters on the command line.

REQUIRED MODULES

 Devel::Required (any)

CALLING FROM THE COMMAND LINE

For developers of Perl and/or threads.pm alternatives, it is also possible to only have the "reference" run be done by simply calling Benchmark::Thread::Size from the command line. For example:

  perl.21116-threaded -MBenchmark::Thread::Size

will do the reference run 10 times using the "perl.21116-threaded" Perl executable. If you want to change the number of times the reference run is done, you can specify that also on the command line as you would normally specify any parameters for the import() subroutine on the command line:

  perl5.8.0-threaded -MBenchmark::Thread::Size=times,50

will execute the reference run 50 times using the "per5.8.0-threaded" Perl executable.

Since the Benchmark::Thread::Size is a Pure Perl module, it is technically possible to use the module from anywhere on your system, even when it is installed in another Perl's tree. This can be achieved by specifying the -I/other/directory parameter in which "/other/directory" points to the directory where the "Benchmark" directory is located.

WHAT IT DOES

This module started life as just a number of scripts. In order to facilitate distribution I decided to bundle them together into this module. So, what does happen exactly when you execute this module?

create ramthread

This is the main script that does the testing. It collects the data that is written out to STDOUT by ramthread1.

create ramthread1

This is the script that gets called for each seperate test. It creates a special test-script "_test_ramthread" for each test and each number of threads to be checked (to avoid artefacts from previous runs in the same interpreter), then measures the size of memory for each number of threads running simultaneously and writes out the result to STDOUT.

create files for each piece of code

For several (historical) reasons, a seperate file is created for each piece of code given. These files are used by ramthread1 to measure the amount of memory used. The identification of the code is used as the filename, so be sure that this will not overwrite stuff you might need later.

The actual code is functionally equivalent to:

 use threads ();
 # your code comes here
 for ($i = 0; $i < (number of threads to test) ; $i++) {
   threads->new( sub {sleep( 86400 )} );
 }
run ramthread

The ramthread script is then run with the appropriate parameters. The output is sent to STDERR (progress indication) and STDOUT (final report).

remove all files that were created

Then all of the files (including the ramthread and ramthread1 script) are removed, so that no files are left behind.

All files are created in the current directory. This may not be the best place, but it was the easiest thing to code.

HOW TO MEASURE SIZE?

Currently the size of the process is measured by doing a:

  ps -o rss= -p $pid

on non-Windows systems. On Windows systems, this is done by:

  (Win32::Process::Info->new)->GetProcInfo( $pid ))[0]->{'WorkingSetSize'}/1024
  

If you feel that the process size measurement can be done more accurately in a different way for you favourite Operating System, please let me know.

AUTHOR

Elizabeth Mattijsen, <liz@dijkmat.nl>.

maintained by LNATION, <thisusedtobeanemail@gmail.com>

Please report bugs to <perlbugs@dijkmat.nl>.

ACKNOWLEDGEMENTS

Frank Tolstrup for supplying the magic incantation for getting process size measurement going on Windows.

James FitzGibbon for pointing out a more portable "ps" string and the fact that "ps" on Mac OS X has a bug in it.

COPYRIGHT

Copyright (c) 2002-2003 Elizabeth Mattijsen <liz@dijkmat.nl>. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

SEE ALSO

Benchmark.

1 POD Error

The following errors were encountered while parsing the POD:

Around line 408:

Non-ASCII character seen before =encoding in '±'. Assuming ISO8859-1