# New Ticket Created by Leopold Toetsch
# Please include the string: [perl #17549]
# in the subject line of all future correspondence about this issue.
# <URL: http://rt.perl.org/rt2/Ticket/Display.html?id=17549 >
Attached patch
- corrects a bug in int_list_assign 1)
- makes direct access fly
intlist_3.pbc is with 1) already 10 times faster then the same test with
PerlArray (ok, that's not fair, .PerlArray has to new_pmc, which
accounts for ~40% difference).
With the patch there is another factor 10 speed gain.
So I think, we should make intlist the base class for our array class(es).
Please apply,
leo
-- attachment 1 ------------------------------------------------------
url: http://rt.perl.org/rt2/attach/38478/31277/a15b0f/intlist.patch
--- parrot/intlist.c Mon Sep 9 07:47:48 2002
+++ parrot-leo/intlist.c Tue Sep 24 06:44:44 2002
@@ -77,8 +77,10 @@
#include "parrot/parrot.h"
#include "parrot/intlist.h"
+static size_t rebuild_chunk_list(Interp *interpreter, IntList *list);
+
IntList*
-intlist_new(Interp *interpreter)
+intlist_new(Interp *interpreter, int initial)
{
IntList* list;
@@ -93,6 +95,13 @@
interpreter->GC_block_level++;
Parrot_allocate(interpreter, (Buffer*) list,
INTLIST_CHUNK_SIZE * sizeof(INTVAL));
+ if (initial) {
+ /* XXX managed memory or custom destroy? */
+ list->chunk_list = mem_sys_allocate(sizeof(IntList_Chunk *));
+ list->n_chunks = 1;
+ list->collect_runs = interpreter->collect_runs;
+ list->chunk_list[0] = (IntList_Chunk*) list;
+ }
interpreter->DOD_block_level--;
interpreter->GC_block_level--;
return list;
@@ -136,6 +145,25 @@
fprintf(fp, "\n");
}
+static size_t
+rebuild_chunk_list(Interp *interpreter, IntList *list)
+{
+ IntList_Chunk* chunk = (IntList_Chunk*) list;
+ IntList_Chunk* lastChunk = list->prev;
+ size_t len = 0;
+ while (1) {
+ if (len >= list->n_chunks)
+ list->chunk_list = mem_sys_realloc(list->chunk_list,
+ (len + 1)* sizeof(IntList*));
+ list->chunk_list[len] = chunk;
+ len++;
+ if (chunk == lastChunk) break;
+ chunk = chunk->next;
+ }
+ list->collect_runs = interpreter->collect_runs;
+ return len;
+}
+
static void
add_chunk(Interp* interpreter, IntList* list)
{
@@ -143,7 +171,7 @@
if (chunk->next == list) {
/* Need to add a new chunk */
- IntList_Chunk* new_chunk = intlist_new(interpreter);
+ IntList_Chunk* new_chunk = intlist_new(interpreter, 0);
new_chunk->next = list;
new_chunk->prev = chunk;
chunk->next = new_chunk;
@@ -161,6 +189,7 @@
add_chunk(interpreter, list);
list->prev->start = 0;
list->prev->end = 0;
+ list->n_chunks = rebuild_chunk_list(interpreter, list);
}
static void
@@ -198,6 +227,10 @@
unshift_chunk(interpreter, *list);
chunk = chunk->prev;
*list = chunk;
+ (*list)->chunk_list = chunk->chunk_list;
+ (*list)->n_chunks = chunk->n_chunks;
+ chunk->chunk_list = 0;
+ (*list)->n_chunks = rebuild_chunk_list(interpreter, *list);
}
((INTVAL*)chunk->buffer.bufstart)[--chunk->start] = data;
@@ -225,6 +258,10 @@
chunk->next->prev = chunk->prev;
chunk->prev->next = chunk;
*list = chunk->next;
+ (*list)->chunk_list = chunk->chunk_list;
+ (*list)->n_chunks = chunk->n_chunks;
+ chunk->chunk_list = 0;
+ (*list)->n_chunks = rebuild_chunk_list(interpreter, *list);
}
(*list)->length = length;
@@ -245,6 +282,7 @@
chunk->next = list;
list->prev = chunk->prev;
chunk = chunk->prev;
+ list->n_chunks--;
}
/* Quick sanity check */
@@ -265,6 +303,12 @@
IntList_Chunk* chunk = list;
UNUSED(interpreter);
+ /* XXX do we need this? */
+ if (list->collect_runs != interpreter->collect_runs)
+ rebuild_chunk_list(interpreter, list);
+
+ return list->chunk_list[idx / INTLIST_CHUNK_SIZE];
+#if 0
/* Possible optimization: start from the closer end of the chunk list */
/* Find the chunk containing the requested element */
@@ -274,6 +318,7 @@
}
return chunk;
+#endif
}
INTVAL
@@ -347,7 +392,9 @@
chunk = find_chunk(interpreter, list, idx);
- ((INTVAL*)chunk->buffer.bufstart)[idx] = val;
+ if (idx >= list->end - list->start) idx -= list->end - list->start;
+ idx = idx % INTLIST_CHUNK_SIZE;
+ ((INTVAL*)chunk->buffer.bufstart)[idx + chunk->start] = val;
}
/*
--- parrot/include/parrot/intlist.h Mon Sep 9 07:49:08 2002
+++ parrot-leo/include/parrot/intlist.h Tue Sep 24 06:32:06 2002
@@ -24,7 +24,10 @@
struct IntList_chunk_t {
Buffer buffer; /* This struct is a Buffer header subclass! */
- INTVAL length; /* Only valid for the "head" chunk */
+ INTVAL length; /* Only valid for the "head" chunk (1) */
+ size_t collect_runs; /* when chunklist was built (1) */
+ IntList_Chunk ** chunk_list; /* list of chunks for fast access (1) */
+ size_t n_chunks; /* number of chunks in chunk_list */
INTVAL start;
INTVAL end;
IntList_Chunk* next;
@@ -35,7 +38,7 @@
PMC* intlist_mark(Interp*, IntList*, PMC* last);
-IntList *intlist_new(Interp*);
+IntList *intlist_new(Interp*, int initial);
static INTVAL intlist_length(Interp* interpreter, IntList* list)
{
--- parrot/classes/intlist.pmc Mon Sep 9 07:48:15 2002
+++ parrot-leo/classes/intlist.pmc Tue Sep 24 06:31:38 2002
@@ -30,7 +30,7 @@
}
void init () {
- SELF->data = intlist_new(INTERP);
+ SELF->data = intlist_new(INTERP, 1);
SELF->cache.int_val = 0;
SELF->flags |= PMC_custom_mark_FLAG;
}
--- parrot/t/pmc/intlist.t Mon Sep 9 07:49:35 2002
+++ parrot-leo/t/pmc/intlist.t Tue Sep 24 06:30:07 2002
@@ -1,6 +1,6 @@
#! perl -w
-use Parrot::Test tests => 2;
+use Parrot::Test tests => 3;
use Test::More;
output_is(<<'CODE', <<'OUTPUT', "creation");
@@ -145,3 +145,38 @@
CODE
I need a shower.
OUTPUT
+
+output_is(<<'CODE', <<'OUTPUT', "direct access");
+ new P0, .IntList
+ set I10, 100000
+ set I0, 0
+lp:
+ set P0[I0], I0
+ inc I0
+ mod I9, I0, 100
+ ne I9, 0, lp1
+ # force GC => 142 DOD + 142 collects / 10^5 accesses
+ new P1, .PerlArray
+ set P1[I0], I0
+lp1:
+ le I0, I10, lp
+
+ set I0, 0
+lp2:
+ set I1, P0[I0]
+ ne I0, I1, err
+ inc I0
+ le I0, I10, lp2
+ print "ok\n"
+ end
+err:
+ print "err: wanted "
+ print I0
+ print " got "
+ print I1
+ print "\n"
+ end
+CODE
+ok
+OUTPUT
+