#726: [PATCH] Reduce calls to mem_sys_allocate() when creating a Hash
----------------------+-----------------------------------------------------
Reporter: Infinoid | Owner:
Type: patch | Status: new
Priority: normal | Milestone:
Component: none | Version: 1.2.0
Severity: medium | Keywords:
Lang: | Patch: new
Platform: |
----------------------+-----------------------------------------------------
parrot_create_hash calls the allocator twice; once when allocating the
Hash structure, and one when allocating the array of HashBuckets.
Consolidating this saves us a lot of time.
One problem I ran into is reallocation. I chose not to realloc the
original buffer, because the pointer to it may have changed, and this code
is not able to find and fix up the caller's pointer(s). Since the pointer
to the top level Hash structure cannot change, this code just leaves that
buffer alone, and allocates a secondary one as necessary when expanding
the HashBucket array.
The patch works by modifying the creation function, consolidating the two
allocations (hash-struct and buckets) into a single buffer. There are two
additional places the patch touches; expand_hash and parrot_hash_destroy.
Both of these functions check whether the HashBucket pointer is at a
static offset from the Hash pointer or not, in determining whether a
separate buffer is used. If the destruction function detects a separate
buffer, it makes a separate call to free(). If the expansion function
detects a separate buffer, it realloc()s it, otherwise it allocates a new
buffer and copies the old data into it. The extra space after the end of
the Hash structure is unused in this case, so this patch will hurt memory
performance slightly in the case where we have lots of long-standing and
large hashes (with more than the default number of buckets).
Anyway, this patch saves about 10% of the total processing time in a
simple while-loop benchmark in rakudo. Unfortunately, it does make the
allocation model rather more complicated. Anyone have any suggestions for
how to make it simpler/nicer/more efficient?
Here's the results of a microbenchmark (both sides of this comparison also
have the TT #725 patch applied).
Before:
{{{
./perl6 -e 'my $i = 0; while ( $i < 100000) { $i++ }' 38.54s user 1.40s
system 99% cpu 40.211 total
./perl6 -e 'my $i = 0; while ( $i < 100000) { $i++ }' 37.98s user 1.49s
system 98% cpu 40.193 total
./perl6 -e 'my $i = 0; while ( $i < 100000) { $i++ }' 38.57s user 1.46s
system 99% cpu 40.349 total
./perl6 -e 'my $i = 0; while ( $i < 100000) { $i++ }' 39.16s user 1.33s
system 99% cpu 40.864 total
./perl6 -e 'my $i = 0; while ( $i < 100000) { $i++ }' 37.91s user 1.53s
system 98% cpu 40.064 total
}}}
After:
{{{
./perl6 -e 'my $i = 0; while ( $i < 100000) { $i++ }' 34.90s user 1.47s
system 99% cpu 36.682 total
./perl6 -e 'my $i = 0; while ( $i < 100000) { $i++ }' 34.52s user 1.40s
system 98% cpu 36.293 total
./perl6 -e 'my $i = 0; while ( $i < 100000) { $i++ }' 33.76s user 1.53s
system 97% cpu 36.036 total
./perl6 -e 'my $i = 0; while ( $i < 100000) { $i++ }' 34.33s user 1.39s
system 99% cpu 36.007 total
./perl6 -e 'my $i = 0; while ( $i < 100000) { $i++ }' 34.64s user 1.36s
system 99% cpu 36.293 total
}}}
--
Ticket URL: <https://trac.parrot.org/parrot/ticket/726>
Parrot <https://trac.parrot.org/parrot/>
Parrot Development
_______________________________________________
parrot-tickets mailing list
[email protected]
http://lists.parrot.org/mailman/listinfo/parrot-tickets