Test::ZeroCopy - Test that two strings share the same memory
use Test::ZeroCopy; is_zerocopy($str1, $str2); isnt_zerocopy($str3, $str4);
In applications that attempt to handle large strings efficiently, it can often be a huge win to avoid copying strings.
However, unless you are super careful, it's easy to write perl code that copies strings without realising it:
my $str = "long string goes here"; sub getstring { my $arg = shift; # this is a copy return $arg; } my $ret = getstring($str); # this is another copy
One solution is to pass references to the string around. Another is to use Data::Alias.
Unfortunately, neither of these approaches help when you want to take a substring of the large string: substr always copies the contents of the string. In C we could avoid copying and instead pass around pointers that point into the string.
substr
Although perl doesn't directly support pointers, it is still possible to take a zero-copy substring by creating a scalar with a SvPV pointing into the large string and a SvLEN set to 0 to indicate that the memory is "owned" by the large string. Also, the reference counts of the two strings are linked so that the large buffer will only be reclaimed once all substrings go out of scope.
SvPV
SvLEN
String::Slice is an example of a module that can create zero-copy sub-strings or "slices" in this way.
This module came about because I got tired of sprinkling Devel::Peek Dump statements around my code to confirm no copying occurred. Here is an example of how to do that:
Dump
use String::Slice; use Devel::Peek; my $buf = "ABCDEF"; my $slice = ""; slice($slice, $buf, 1, 3); Dump($buf); Dump($slice);
And the (abridged) output:
SV = PV(0x14e0c20) at 0x1501270 PV = 0x14fa1f0 "ABCDEF"\0 CUR = 6 LEN = 16 SV = PVMG(0x1528db0) at 0x150d678 PV = 0x14fa1f1 "BCD" CUR = 3 LEN = 0
Notice how the PV values point into the same buffer.
Instead of manual inspection, this module lets you add these assertions to your test-suites to ensure that you (or future maintainers) don't accidentally add wasteful copy operations.
This module provides two Test::More-compatible testing functions: is_zerocopy and isnt_zerocopy.
is_zerocopy
isnt_zerocopy
Each of these functions should be passed two strings. is_zerocopy will assert that the backing memory is shared between the two strings. This is assumed to be the case when any portions of their PV buffers overlap.
The backing memory is trivially shared in the case where the two strings are the same (ie is_zerocopy($str, $str)), but is much more interesting when one is a substring or "slice" of the other and they happen to use the same backing memory (see above).
is_zerocopy($str, $str)
isnt_zerocopy is the opposite and it will assert that the backing memory is not shared between the two strings.
You can also use this module to get the PV address from a perl program (which I couldn't figure out how to do with B):
require Test::ZeroCopy; my $addr = Test::ZeroCopy::get_pv_address($string);
Test-ZeroCopy github repo
Data::Alias - Sometimes more convenient to use this module than to use references
String::Slice - Simple module that can make zero-copy substrings
File::Map - Interface to mmap() that lets you "read in" a whole file into a string suitable for performing zero-copy substring operations
mmap()
LMDB_File - In-process database that supports zero-copy reads
Doug Hoyte, <doug@hcsw.org>
<doug@hcsw.org>
Copyright 2014 Doug Hoyte.
This module is licensed under the same terms as perl itself.
To install Test::ZeroCopy, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Test::ZeroCopy
CPAN shell
perl -MCPAN -e shell install Test::ZeroCopy
For more information on module installation, please visit the detailed CPAN module installation guide.