# 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 +