-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add benchmarks for new RPS2 type. This type uses a geometrically-grow…
…ing (but currently never shrinking flat memory buffer. Benchmark times are better-but-similar (33% faster) to RPA for push, ~200x better than RPA for pop.
- Loading branch information
1 parent
cd30749
commit 4861ec0
Showing
4 changed files
with
362 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
#! parrot-nqp | ||
our @ARGS; | ||
MAIN(); | ||
|
||
sub MAIN () { | ||
load_test_more(); | ||
plan(1); | ||
|
||
load_linalg_group(); | ||
RPS2_push_pop_10000_items(); | ||
RPA_push_pop_10000_items(); | ||
} | ||
|
||
sub load_test_more() { | ||
Q:PIR { | ||
.local pmc c | ||
load_language 'parrot' | ||
c = compreg 'parrot' | ||
c.'import'('Test::More') | ||
}; | ||
} | ||
|
||
sub load_linalg_group() { | ||
Q:PIR { | ||
.local pmc pds | ||
pds = loadlib "./dynext/pds_group" | ||
if pds goto has_pds_group | ||
exit 1 | ||
has_pds_group: | ||
}; | ||
} | ||
|
||
sub RPS2_push_pop_10000_items() { | ||
Q:PIR { | ||
$P0 = new ['ResizablePMCStack2'] | ||
$P1 = new ['Integer'] | ||
$P1 = 5 | ||
$I0 = 10000 | ||
$N0 = time | ||
push_loop_top: | ||
push $P0, $P1 | ||
$I0 = $I0 - 1 | ||
if $I0 == 0 goto push_loop_bottom | ||
goto push_loop_top | ||
push_loop_bottom: | ||
$N1 = time | ||
$I0 = 10000 | ||
shift_loop_top: | ||
$P2 = pop $P0 | ||
$I0 = $I0 - 1 | ||
if $I0 == 0 goto shift_loop_bottom | ||
goto shift_loop_top | ||
shift_loop_bottom: | ||
$N2 = time | ||
$N3 = $N1 - $N0 | ||
$N4 = $N2 - $N1 | ||
$N5 = $N2 - $N0 | ||
print "(RPS2) Time for 10000 pushes: " | ||
say $N3 | ||
print "(RPS2) Time for 10000 pops: " | ||
say $N4 | ||
print "(RPS2) Total time: " | ||
say $N5 | ||
} | ||
} | ||
|
||
sub RPA_push_pop_10000_items() { | ||
Q:PIR { | ||
$P0 = new ['ResizablePMCArray'] | ||
$P1 = new ['Integer'] | ||
$P1 = 5 | ||
$I0 = 10000 | ||
$N0 = time | ||
push_loop_top: | ||
push $P0, $P1 | ||
$I0 = $I0 - 1 | ||
if $I0 == 0 goto push_loop_bottom | ||
goto push_loop_top | ||
push_loop_bottom: | ||
$N1 = time | ||
$I0 = 10000 | ||
shift_loop_top: | ||
$P2 = shift $P0 | ||
$I0 = $I0 - 1 | ||
if $I0 == 0 goto shift_loop_bottom | ||
goto shift_loop_top | ||
shift_loop_bottom: | ||
$N2 = time | ||
$N3 = $N1 - $N0 | ||
$N4 = $N2 - $N1 | ||
$N5 = $N2 - $N0 | ||
print "(RPA) Time for 10000 pushes: " | ||
say $N3 | ||
print "(RPA) Time for 10000 shifts: " | ||
say $N4 | ||
print "(RPA) Total time: " | ||
say $N5 | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
#include "parrot/parrot.h" | ||
#define RPS_POINTERS_PER_CHUNK 16 | ||
#define RPS_ATTRS_CONST(x) Parrot_ResizablePMCStack2_attributes * const (x) | ||
#define RPS_GET_ATTRS(x) PARROT_RESIZABLEPMCSTACK2(x) | ||
#define RPS_INITIAL_BUFFER_SIZE 16 | ||
#define RPS_GROW_FACTOR 2 | ||
#define RPS_NEXT_SIZE_GROW(s) ((s) * RPS_GROW_FACTOR) | ||
#define RPS_NEXT_SIZE_SHRINK(s) ((s) / RPS_GROW_FACTOR) | ||
#define RPS_ALLOCATE(s) (PMC **)mem_sys_allocate(s * sizeof(PMC *)) | ||
#define RPS_REALLOCATE(s, x) (PMC **)mem_sys_realloc((s), (x) * sizeof(PMC*)) | ||
#define RPS_GET_STORAGE(a) ((a)->storage) | ||
|
||
/* ResizablePMCStack2 is a dynamically-growing First-In-Last-Out stack structure. | ||
It is optimized for high-throughput push/pop access. It uses a geometrically | ||
growing flat memory buffer to hold data. */ | ||
pmclass ResizablePMCStack2 dynpmc auto_attrs provides stack { | ||
ATTR PMC **storage; | ||
ATTR INTVAL items; | ||
ATTR INTVAL size; | ||
|
||
/* Initialize the PMC and allocate the first chunk */ | ||
VTABLE void init() { | ||
RPS_ATTRS_CONST(attrs) = RPS_GET_ATTRS(SELF); | ||
attrs->storage = RPS_ALLOCATE(RPS_INITIAL_BUFFER_SIZE); | ||
attrs->size = RPS_INITIAL_BUFFER_SIZE; | ||
/* ->items already zeroed */ | ||
} | ||
|
||
/* Destroy the PMC and free all allocated storage */ | ||
VTABLE void destroy() { | ||
RPS_ATTRS_CONST(attrs) = RPS_GET_ATTRS(SELF); | ||
PMC ** const s = attrs->storage; | ||
if (s) | ||
mem_sys_free(s); | ||
} | ||
|
||
/* Mark the stack for GC */ | ||
VTABLE void mark() { | ||
RPS_ATTRS_CONST(attrs) = RPS_GET_ATTRS(SELF); | ||
PMC ** const s = RPS_GET_STORAGE(attrs); | ||
if (s) { | ||
INTVAL i = 0; | ||
const INTVAL items = attrs->items; | ||
for (i = 0; i < items; i++) | ||
Parrot_gc_mark_PMC_alive(INTERP, s[i]); | ||
} | ||
} | ||
|
||
VTABLE void freeze(PMC *info) { | ||
} | ||
|
||
VTABLE void thaw(PMC *info) { | ||
} | ||
|
||
VTABLE void visit(PMC *info) { | ||
} | ||
|
||
/* Push a PMC onto the stack */ | ||
VTABLE void push_pmc(PMC *item) { | ||
RPS_ATTRS_CONST(attrs) = RPS_GET_ATTRS(SELF); | ||
const INTVAL items = attrs->items; | ||
const INTVAL size = attrs->size; | ||
PMC ** s = attrs->storage; | ||
if (items == size) { | ||
const INTVAL newsize = RPS_NEXT_SIZE_GROW(size); | ||
s = RPS_REALLOCATE(s, newsize); | ||
attrs->storage = s; | ||
attrs->size = newsize; | ||
} | ||
s[items] = item; | ||
attrs->items = items + 1; | ||
} | ||
|
||
/* Pop a PMC off the stack */ | ||
VTABLE PMC* pop_pmc() { | ||
RPS_ATTRS_CONST(attrs) = RPS_GET_ATTRS(SELF); | ||
const INTVAL items = attrs->items - 1; | ||
//const INTVAL size = attrs->size; | ||
PMC ** const s = attrs->storage; | ||
PMC * item; | ||
if (items == -1) | ||
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS, | ||
"ResizablePMCStack: Pop from empty stack"); | ||
item = s[items]; | ||
attrs->items = items; | ||
return item; | ||
} | ||
|
||
/* Get the total number of elements. WARNING: O(N) */ | ||
VTABLE INTVAL elements() { | ||
RPS_ATTRS_CONST(attrs) = RPS_GET_ATTRS(SELF); | ||
const INTVAL items = attrs->items; | ||
return items; | ||
} | ||
|
||
/* Get a ResizablePMCArray containing the contents of the stack */ | ||
METHOD to_array() { | ||
RPS_ATTRS_CONST(attrs) = RPS_GET_ATTRS(SELF); | ||
const INTVAL items = attrs->items; | ||
PMC ** const s = attrs->storage; | ||
PMC * const newarray = pmc_new(INTERP, enum_class_ResizablePMCArray); | ||
INTVAL i = 0; | ||
for (i = 0; i < items; i++) | ||
VTABLE_set_pmc_keyed_int(INTERP, newarray, i, s[i]); | ||
RETURN(PMC *newarray); | ||
} | ||
|
||
/* Get the total allocated memory size, in bytes. Includes the size of the | ||
PMC structure and attribute structure */ | ||
METHOD total_mem_size() { | ||
RPS_ATTRS_CONST(attrs) = RPS_GET_ATTRS(SELF); | ||
const INTVAL size = attrs->size; | ||
INTVAL total = sizeof(PMC) + sizeof(Parrot_ResizablePMCStack2_attributes); | ||
total += size * sizeof(PMC *); | ||
RETURN(INTVAL total); | ||
} | ||
|
||
METHOD clear() { | ||
RPS_ATTRS_CONST(attrs) = RPS_GET_ATTRS(SELF); | ||
PMC ** const s = attrs->storage; | ||
if (s) | ||
mem_sys_free(s); | ||
attrs->storage = RPS_ALLOCATE(RPS_INITIAL_BUFFER_SIZE); | ||
attrs->size = RPS_INITIAL_BUFFER_SIZE; | ||
attrs->items = 0; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
#! parrot-nqp | ||
our @ARGS; | ||
MAIN(); | ||
|
||
sub MAIN () { | ||
load_test_more(); | ||
plan(1); | ||
ok(1); | ||
|
||
load_pds_group(); | ||
op_new(); | ||
op_does(); | ||
op_typeof(); | ||
vtable_push_pmc(); | ||
vtable_pop_pmc(); | ||
vtable_elements(); | ||
method_to_array(); | ||
method_total_mem_size(); | ||
method_clear(); | ||
} | ||
|
||
sub load_test_more() { | ||
Q:PIR { | ||
.local pmc c | ||
load_language 'parrot' | ||
c = compreg 'parrot' | ||
c.'import'('Test::More') | ||
}; | ||
} | ||
|
||
sub load_pds_group() { | ||
Q:PIR { | ||
.local pmc pds | ||
pds = loadlib "./dynext/pds_group" | ||
if pds goto has_pds_group | ||
exit 1 | ||
has_pds_group: | ||
}; | ||
} | ||
|
||
sub op_new() { | ||
Q:PIR { | ||
push_eh op_new_sanity_error | ||
$P0 = new ['ResizablePMCStack2'] | ||
ok(1) | ||
goto op_new_sanity_end | ||
op_new_sanity_error: | ||
ok(0) | ||
op_new_sanity_end: | ||
pop_eh | ||
|
||
$I0 = isnull $P0 | ||
is($I0, 0) | ||
} | ||
} | ||
|
||
sub op_does() { | ||
Q:PIR { | ||
$P0 = new ['ResizablePMCStack2'] | ||
$I0 = does $P0, "stack" | ||
is($I0, 1) | ||
$I0 = does $P0, "jibbajabba" | ||
is($I0, 0) | ||
} | ||
} | ||
sub op_typeof() { | ||
Q:PIR { | ||
$P0 = new ['ResizablePMCStack2'] | ||
$S0 = typeof $P0 | ||
is($S0, 'ResizablePMCStack2') | ||
} | ||
} | ||
|
||
sub vtable_push_pmc() { | ||
Q:PIR { | ||
$P0 = new ['ResizablePMCStack2'] | ||
$P1 = box 1 | ||
push_eh push_pmc_sanity_error | ||
push $P0, $P1 | ||
ok(1) | ||
goto push_pmc_sanity_end | ||
push_pmc_sanity_error: | ||
ok(0) | ||
push_pmc_sanity_end: | ||
pop_eh | ||
} | ||
} | ||
|
||
sub vtable_pop_pmc() { | ||
Q:PIR { | ||
$P0 = new ['ResizablePMCStack2'] | ||
$P1 = box 1 | ||
push $P0, $P1 | ||
$P2 = pop $P0 | ||
is($P1, $P2) | ||
} | ||
} | ||
sub vtable_elements() { | ||
Q:PIR { | ||
$P0 = new ['ResizablePMCStack2'] | ||
$I0 = elements $P0 | ||
is($I0, 0) | ||
|
||
$P1 = box 1 | ||
push $P0, $P1 | ||
$I0 = elements $P0 | ||
is($I0, 1) | ||
|
||
$P2 = pop $P0 | ||
$I0 = elements $P0 | ||
is($I0, 0) | ||
} | ||
} | ||
|
||
sub method_to_array() { | ||
Q:PIR { | ||
# TODO: This! | ||
} | ||
} | ||
|
||
sub method_total_mem_size() { | ||
Q:PIR { | ||
# TODO: This! | ||
} | ||
} | ||
|
||
sub method_clear() { | ||
Q:PIR { | ||
# TODO: This! | ||
} | ||
} | ||
|