Skip to content

Commit

Permalink
Add benchmarks for new RPS2 type. This type uses a geometrically-grow…
Browse files Browse the repository at this point in the history
…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
Whiteknight committed Feb 6, 2010
1 parent cd30749 commit 4861ec0
Show file tree
Hide file tree
Showing 4 changed files with 362 additions and 0 deletions.
100 changes: 100 additions & 0 deletions benchmarks/resizablepmcstack2.nqp
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
}
}

1 change: 1 addition & 0 deletions setup.pir
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ See F<runtime/library/distutils.pir>.
$P2 = new 'Hash'
$P3 = split "\n", <<'SOURCES'
src/pmc/resizablepmcstack.pmc
src/pmc/resizablepmcstack2.pmc
src/pmc/fixedpmcstack.pmc
src/pmc/resizablepmcqueue.pmc
src/pmc/fixedpmcqueue.pmc
Expand Down
127 changes: 127 additions & 0 deletions src/pmc/resizablepmcstack2.pmc
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;
}
}
134 changes: 134 additions & 0 deletions t/pmc/resizablepmcstack2.t
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!
}
}

0 comments on commit 4861ec0

Please sign in to comment.