Memory savings with cperl and AvSTATIC

B::C and cperl has now proper support for copy-on-grow (COG) and copy-on-write (COW) arrays.

COG means that the array of SV* pointers is allocated by the compiler statically, not dynamically, and that the cperl runtime creates a new array whenever the array is extended (copy-on-grow).

COW means that the array of SV* pointers is allocated by the compiler constant and static in the .rodata segment, and that the cperl runtime creates a new array whenever an element of the arrays is changed (copy-on-write).

With a typical example of a medium sized module, Net::DNS::Resolver, the memory usage is as follows:

pcc -O0 -S -e'use Net::DNS::Resolver; my $res = Net::DNS::Resolver->new;
  $res->send("www.google.com"); print `ps -p $$ -O rss,vsz`'

            rss
with avcow: 12720
without   : 13456

5.8% percent win.

The numbers with a small example are as follows:

                        rss  vsz
cperl5.22.2-nt-avcow    2536 2438744
                   -O3  2532 2438740
cperl5.22.2d-nt-avcog   3516 2451728
perl5.22.1-nt           3316 2438912
perl5.20.3-nt           3264 2438696
perl5.18.2-nt           3036 2438468
perl5.18.4d             4276 2450540
perl5.18.4d-nt          4120 2451332
perl5.16.3              4072 2458904
perl5.16.3-nt           3008 2438420
perl5.14.4              3168 2447764
perl5.14.4-nt           2944 2447540
perl5.14.4-nt -O3       2852 2447472
perl5.12.5              3440 2449964
perl5.12.5-nt           3244 2447716
perl5.10.1-nt           3172 2456836
perl5.8.9               3176 2465976
perl5.8.9d-nt           3096 2438400
perl5.8.5d-nt           3228 2456836
perl5.8.4d-nt           3176 2457792

Here you see that the previously useful perl version perl5.14.4-nt with 2852 kB is now finally made obsolete by cperl with an RSS of 2532 kB.

5.16 introduced binary symbols, and 5.18 added a completely broken implementation of COW strings, which forced all previously statically allocated strings to be allocated dynamically. This caused a 20% memory increase in 5.22, which we could only overcome with cperl, and some tricks in the compiler to disable COW strings at all.

Theoretically I can set all arrays as COW to get the biggest memory win, but at run-time all writes need to copy those arrays to the heap, which is a performance and memory loss. So I cow only the arrays which are very likely to be not changed at all. I.e. all @ISA arrays, the @INC and all READONLY arrays.

The current distribution with this example is as follows:

24 COW arrays of size 1, 2x 2, 1x 3, 1x 9. 28 COW arrays at all.

11 COG arrays of size 1, overall 90 COG array sizes with max 169 elements, 89 COG arrays at all.

1338 arrays and 16562 SVs at all.

I haven't measured the hit and miss rate yet, and I haven't fixed COW or COG for other data types, such as strings or hashes. A big improvement would be proper COW or COG for strings of course, with an expected memory win of 10-20%.

1 Comment

Good memory usage in cperl!