Author: Remi Meier
Branch: c7
Changeset: r673:31b7b6a45064
Date: 2014-01-24 15:46 +0100
http://bitbucket.org/pypy/stmgc/changeset/31b7b6a45064/
Log: use only largemalloc to allocate old objects
diff --git a/c7/core.c b/c7/core.c
--- a/c7/core.c
+++ b/c7/core.c
@@ -68,11 +68,9 @@
uintptr_t lock_idx = (((uintptr_t)item) >> 4) - READMARKER_START;
assert(write_locks[lock_idx]);
write_locks[lock_idx] = 0;
-
- char *src = REAL_ADDRESS(local_base, item);
- char *dst = REAL_ADDRESS(remote_base, item);
- size_t size = stmcb_size((struct object_s*)src);
- memcpy(dst, src, size);
+
+ _stm_move_object(REAL_ADDRESS(local_base, item),
+ REAL_ADDRESS(remote_base, item));
}));
if (conflicted) {
@@ -88,23 +86,24 @@
{
uintptr_t pagenum = ((uintptr_t)obj) / 4096;
assert(pagenum < NB_PAGES);
+ assert(!_stm_is_young(obj));
LIST_APPEND(_STM_TL->old_objects_to_trace, obj);
/* for old objects from the same transaction we don't need
- to privatize the page */
- if ((stm_get_page_flag(pagenum) == UNCOMMITTED_SHARED_PAGE)
- || (obj->stm_flags & GCFLAG_NOT_COMMITTED)) {
+ to privatize the pages */
+ if (obj->stm_flags & GCFLAG_NOT_COMMITTED) {
obj->stm_flags &= ~GCFLAG_WRITE_BARRIER;
return;
}
/* privatize if SHARED_PAGE */
- /* xxx stmcb_size() is probably too slow, maybe add a GCFLAG_LARGE for
- objs with more than 1 page */
- int pages = stmcb_size(real_address(obj)) / 4096;
- for (; pages >= 0; pages--)
- stm_pages_privatize(pagenum + pages);
+ uintptr_t pagenum2, pages;
+ _stm_chunk_pages((struct object_s*)REAL_ADDRESS(get_thread_base(0), obj),
+ &pagenum2, &pages);
+ assert(pagenum == pagenum2);
+ for (pagenum2 += pages - 1; pagenum2 >= pagenum; pagenum2--)
+ stm_pages_privatize(pagenum2);
/* claim the write-lock for this object */
uintptr_t lock_idx = (((uintptr_t)obj) >> 4) - READMARKER_START;
@@ -226,7 +225,6 @@
_STM_TL->shadow_stack_base = _STM_TL->shadow_stack;
_STM_TL->old_objects_to_trace = stm_list_create();
- _STM_TL->uncommitted_pages = stm_list_create();
_STM_TL->modified_objects = stm_list_create();
_STM_TL->uncommitted_objects = stm_list_create();
@@ -247,7 +245,6 @@
assert(stm_list_is_empty(_STM_TL->uncommitted_objects));
stm_list_free(_STM_TL->uncommitted_objects);
- _STM_TL->uncommitted_objects = NULL;
assert(_STM_TL->shadow_stack == _STM_TL->shadow_stack_base);
free(_STM_TL->shadow_stack);
@@ -255,9 +252,6 @@
assert(_STM_TL->old_objects_to_trace->count == 0);
stm_list_free(_STM_TL->old_objects_to_trace);
- assert(_STM_TL->uncommitted_pages->count == 0);
- stm_list_free(_STM_TL->uncommitted_pages);
-
set_gs_register(INVALID_GS_VALUE);
}
@@ -341,9 +335,7 @@
_STM_TL->jmpbufptr = NULL; /* cannot abort any more */
- /* push uncommitted objects to other threads,
- make completely uncommitted pages SHARED,
- */
+ /* push uncommitted objects to other threads */
nursery_on_commit();
/* copy modified object versions to other threads */
diff --git a/c7/core.h b/c7/core.h
--- a/c7/core.h
+++ b/c7/core.h
@@ -49,7 +49,6 @@
typedef TLPREFIX struct object_s object_t;
typedef TLPREFIX struct read_marker_s read_marker_t;
typedef TLPREFIX char localchar_t;
-typedef TLPREFIX struct alloc_for_size_s alloc_for_size_t;
typedef void* jmpbufptr_t[5]; /* for use with __builtin_setjmp() */
/* Structure of objects
@@ -80,12 +79,6 @@
uint8_t rm;
};
-struct alloc_for_size_s {
- localchar_t *next;
- uint16_t start, stop;
- bool flag_partial_page;
-};
-
struct _thread_local1_s {
jmpbufptr_t *jmpbufptr;
@@ -101,13 +94,8 @@
object_t **shadow_stack;
object_t **shadow_stack_base;
- struct alloc_for_size_s alloc[LARGE_OBJECT_WORDS];
struct stm_list_s *uncommitted_objects;
- /* pages newly allocated in the current transaction only containing
- uncommitted objects */
- struct stm_list_s *uncommitted_pages;
-
localchar_t *nursery_current;
struct stm_list_s *old_objects_to_trace;
};
diff --git a/c7/largemalloc.c b/c7/largemalloc.c
--- a/c7/largemalloc.c
+++ b/c7/largemalloc.c
@@ -5,11 +5,13 @@
or medium-block support that are also present in the GNU C Library.
*/
+#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include <assert.h>
#include "largemalloc.h"
-
+#include "pages.h"
+#include "pagecopy.h"
#define MMAP_LIMIT (1280*1024)
@@ -89,20 +91,45 @@
static dlist_t largebins[N_BINS];
static mchunk_t *first_chunk, *last_chunk;
-void _stm_chunk_pages(object_t *tldata, intptr_t *start, intptr_t *num)
+void _stm_chunk_pages(struct object_s *data, uintptr_t *start, uintptr_t *num)
{
- char *data = _stm_real_address(tldata);
- mchunk_t *chunk = data2chunk(data);
- *start = (((char*)chunk) - get_thread_base(0)) / 4096UL;
- size_t offset_into_page = ((uintptr_t)chunk) & 4095UL; // % 4096
- *num = ((chunk->size & ~CHUNK_HEADER_SIZE) + CHUNK_HEADER_SIZE +
offset_into_page + 4095) / 4096UL;
+ /* returns the start page and number of pages that the *payload*
+ spans over. the CHUNK_HEADER is not included in the calculations */
+ mchunk_t *chunk = data2chunk((char*)data);
+ *start = (((char*)data) - get_thread_base(0)) / 4096UL;
+ size_t offset_into_page = ((uintptr_t)data) & 4095UL; // % 4096
+ *num = ((chunk->size & ~FLAG_SORTED) + offset_into_page + 4095) / 4096UL;
}
-size_t _stm_data_size(object_t *tldata)
+size_t _stm_data_size(struct object_s *data)
{
- char *data = _stm_real_address(tldata);
- mchunk_t *chunk = data2chunk(data);
- return chunk->size & ~CHUNK_HEADER_SIZE;
+ mchunk_t *chunk = data2chunk((char*)data);
+ return chunk->size & ~FLAG_SORTED;
+}
+
+void _stm_move_object(char *src, char *dst)
+{
+ /* only copies if page is PRIVATE
+ XXX: various optimizations for objects with
+ multiple pages. E.g. using pagecopy or
+ memcpy over multiple PRIVATE pages. */
+ char *end = src + _stm_data_size((struct object_s*)src);
+ uintptr_t pagenum, num;
+ struct object_s *t0_obj = (struct
object_s*)REAL_ADDRESS(get_thread_base(0), _stm_tl_address(src));
+ _stm_chunk_pages(t0_obj, &pagenum, &num);
+
+ while (src < end) {
+ size_t to_copy = 4096UL - ((uintptr_t)src & 4095UL);
+ if (to_copy > end - src)
+ to_copy = end - src;
+ if (stm_get_page_flag(pagenum) == PRIVATE_PAGE) {
+ memcpy(dst, src, to_copy);
+ }
+
+ pagenum++;
+ src += to_copy;
+ dst += to_copy;
+ }
}
static void insert_unsorted(mchunk_t *new)
diff --git a/c7/largemalloc.h b/c7/largemalloc.h
--- a/c7/largemalloc.h
+++ b/c7/largemalloc.h
@@ -8,6 +8,10 @@
void stm_large_free(object_t *data);
void _stm_large_dump(void);
-void _stm_chunk_pages(object_t *tldata, intptr_t *start, intptr_t *num);
-size_t _stm_data_size(object_t *tldata);
char *_stm_largemalloc_data_start(void);
+
+void _stm_move_object(char *src, char *dst);
+size_t _stm_data_size(struct object_s *data);
+void _stm_chunk_pages(struct object_s *data, uintptr_t *start, uintptr_t *num);
+
+
diff --git a/c7/nursery.c b/c7/nursery.c
--- a/c7/nursery.c
+++ b/c7/nursery.c
@@ -15,6 +15,7 @@
#include "nursery.h"
#include "pages.h"
#include "stmsync.h"
+#include "largemalloc.h"
void stm_major_collection(void)
{
@@ -30,18 +31,9 @@
}
-void mark_page_as_uncommitted(uintptr_t pagenum)
-{
- stm_set_page_flag(pagenum, UNCOMMITTED_SHARED_PAGE);
- LIST_APPEND(_STM_TL->uncommitted_pages, (object_t*)pagenum);
-}
-
object_t *_stm_allocate_old(size_t size)
{
- int pages = (size + 4095) / 4096;
- localchar_t* addr = (localchar_t*)(stm_pages_reserve(pages) * 4096);
-
- object_t* o = (object_t*)addr;
+ object_t* o = stm_large_malloc(size);
o->stm_flags |= GCFLAG_WRITE_BARRIER;
return o;
}
@@ -51,84 +43,6 @@
return _stm_allocate_old(size); /* XXX */
}
-localchar_t *_stm_alloc_next_page(size_t size_class)
-{
- /* may return uninitialized pages */
-
- /* 'alloc->next' points to where the next allocation should go. The
- present function is called instead when this next allocation is
- equal to 'alloc->stop'. As we know that 'start', 'next' and
- 'stop' are always nearby pointers, we play tricks and only store
- the lower 16 bits of 'start' and 'stop', so that the three
- variables plus some flags fit in 16 bytes.
- */
- uintptr_t page;
- localchar_t *result;
- alloc_for_size_t *alloc = &_STM_TL->alloc[size_class];
- size_t size = size_class * 8;
-
- /* reserve a fresh new page */
- page = stm_pages_reserve(1);
-
- /* mark as UNCOMMITTED_... */
- mark_page_as_uncommitted(page);
-
- result = (localchar_t *)(page * 4096UL);
- alloc->start = (uintptr_t)result;
- alloc->stop = alloc->start + (4096 / size) * size;
- alloc->next = result + size;
- alloc->flag_partial_page = false;
- return result;
-}
-
-
-
-
-object_t *_stm_alloc_old(size_t size)
-{
- /* may return uninitialized objects. except for the
- GCFLAG_NOT_COMMITTED, it is set exactly if
- we allocated the object in a SHARED and partially
- committed page. (XXX: add the flag in some other place)
- */
- object_t *result;
- size_t size_class = size / 8;
- assert(size_class >= 2);
-
- if (size_class >= LARGE_OBJECT_WORDS) {
- result = _stm_allocate_old(size);
- result->stm_flags &= ~GCFLAG_NOT_COMMITTED; /* page may be non-zeroed
*/
-
- int page = ((uintptr_t)result) / 4096;
- int pages = (size + 4095) / 4096;
- int i;
- for (i = 0; i < pages; i++) {
- mark_page_as_uncommitted(page + i);
- }
- /* make sure the flag is not set (page is not zeroed!) */
- result->stm_flags &= ~GCFLAG_NOT_COMMITTED;
- } else {
- alloc_for_size_t *alloc = &_STM_TL->alloc[size_class];
-
- if ((uint16_t)((uintptr_t)alloc->next) == alloc->stop) {
- result = (object_t *)_stm_alloc_next_page(size_class);
- } else {
- result = (object_t *)alloc->next;
- alloc->next += size;
- if (alloc->flag_partial_page) {
- LIST_APPEND(_STM_TL->uncommitted_objects, result);
- result->stm_flags |= GCFLAG_NOT_COMMITTED;
- } else {
- /* make sure the flag is not set (page is not zeroed!) */
- result->stm_flags &= ~GCFLAG_NOT_COMMITTED;
- }
- }
- }
- return result;
-}
-
-
-
void trace_if_young(object_t **pobj)
{
@@ -147,16 +61,16 @@
/* move obj to somewhere else */
size_t size = stmcb_size(real_address(*pobj));
- object_t *moved = (object_t*)_stm_alloc_old(size);
+ object_t *moved = stm_large_malloc(size);
- if (moved->stm_flags & GCFLAG_NOT_COMMITTED)
- (*pobj)->stm_flags |= GCFLAG_NOT_COMMITTED; /* XXX: memcpy below
overwrites this otherwise.
- find better solution.*/
-
memcpy((void*)real_address(moved),
(void*)real_address(*pobj),
size);
+ /* object is not committed yet */
+ moved->stm_flags |= GCFLAG_NOT_COMMITTED;
+ LIST_APPEND(_STM_TL->uncommitted_objects, moved);
+
(*pobj)->stm_flags |= GCFLAG_MOVED;
*pforwarded = moved;
*pobj = moved;
@@ -251,22 +165,15 @@
/* remove the flag (they are now committed) */
item->stm_flags &= ~GCFLAG_NOT_COMMITTED;
-
- uintptr_t pagenum = ((uintptr_t)item) / 4096UL;
- if (stm_get_page_flag(pagenum) == PRIVATE_PAGE) {
- /* page was privatized... */
- char *src = REAL_ADDRESS(local_base, item);
- char *dst = REAL_ADDRESS(remote_base, item);
- size_t size = stmcb_size((struct object_s*)src);
- memcpy(dst, src, size);
- }
+
+ _stm_move_object(REAL_ADDRESS(local_base, item),
+ REAL_ADDRESS(remote_base, item));
}));
}
void nursery_on_start()
{
assert(stm_list_is_empty(_STM_TL->old_objects_to_trace));
- stm_list_clear(_STM_TL->uncommitted_pages);
_STM_TL->old_shadow_stack = _STM_TL->shadow_stack;
}
@@ -277,37 +184,9 @@
the caller (optimization) */
/* minor_collect(); */
- /* uncommitted objects / partially COMMITTED pages */
+ /* uncommitted objects */
push_uncommitted_to_other_threads();
stm_list_clear(_STM_TL->uncommitted_objects);
-
- /* uncommitted_pages */
- long j;
- for (j = 2; j < LARGE_OBJECT_WORDS; j++) {
- alloc_for_size_t *alloc = &_STM_TL->alloc[j];
- uint16_t start = alloc->start;
- uint16_t cur = (uintptr_t)alloc->next;
-
- if (start == cur)
- continue; /* page full -> will be replaced automatically
*/
-
- alloc->start = cur; /* next transaction has different 'start' to
- reset in case of an abort */
-
- uintptr_t pagenum = ((uintptr_t)(alloc->next - 1)) / 4096UL;
- if (stm_get_page_flag(pagenum) == UNCOMMITTED_SHARED_PAGE) {
- /* becomes a SHARED (done below) partially used page */
- alloc->flag_partial_page = 1;
- }
- }
-
- STM_LIST_FOREACH(
- _STM_TL->uncommitted_pages,
- ({
- uintptr_t pagenum = (uintptr_t)item;
- stm_set_page_flag(pagenum, SHARED_PAGE);
- }));
- stm_list_clear(_STM_TL->uncommitted_pages);
}
void nursery_on_abort()
@@ -324,36 +203,16 @@
_STM_TL->nursery_current = nursery_base;
- /* forget about GCFLAG_NOT_COMMITTED objects by
- resetting alloc-pages */
- long j;
- for (j = 2; j < LARGE_OBJECT_WORDS; j++) {
- alloc_for_size_t *alloc = &_STM_TL->alloc[j];
- uint16_t num_allocated = ((uintptr_t)alloc->next) - alloc->start;
- uintptr_t next = (uintptr_t)alloc->next;
-
- if (num_allocated) {
- /* forget about all non-committed objects */
- alloc->next -= num_allocated;
-
- uintptr_t pagenum = ((uintptr_t)(next - 1)) / 4096UL;
- if (stm_get_page_flag(pagenum) == UNCOMMITTED_SHARED_PAGE) {
- /* the page will be freed below, we need a new one for the
- next allocation */
- alloc->next = 0;
- alloc->stop = 0;
- alloc->start = 0;
- }
- }
- }
+ /* free uncommitted objects */
+ struct stm_list_s *uncommitted = _STM_TL->uncommitted_objects;
- /* unreserve uncommitted_pages and mark them as SHARED again
- IFF they are not in alloc[] */
- STM_LIST_FOREACH(_STM_TL->uncommitted_pages, ({
- stm_pages_unreserve((uintptr_t)item);
- }));
- stm_list_clear(_STM_TL->uncommitted_pages);
-
+ STM_LIST_FOREACH(
+ uncommitted,
+ ({
+ stm_large_free(item);
+ }));
+
+ stm_list_clear(uncommitted);
}
diff --git a/c7/pages.h b/c7/pages.h
--- a/c7/pages.h
+++ b/c7/pages.h
@@ -7,11 +7,6 @@
/* page private for each thread */
PRIVATE_PAGE,
-
- /* set for SHARED pages that only contain objects belonging
- to the current transaction, so the whole page is not
- visible yet for other threads */
- UNCOMMITTED_SHARED_PAGE,
}; /* flag_page_private */
diff --git a/c7/test/support.py b/c7/test/support.py
--- a/c7/test/support.py
+++ b/c7/test/support.py
@@ -86,7 +86,6 @@
SHARED_PAGE=0,
REMAPPING_PAGE,
PRIVATE_PAGE,
- UNCOMMITTED_SHARED_PAGE,
}; /* flag_page_private */
enum {
@@ -103,10 +102,12 @@
void stm_large_free(object_t *data);
void _stm_large_dump(void);
-void _stm_chunk_pages(object_t *tldata, intptr_t *start, intptr_t *num);
-size_t _stm_data_size(object_t *tldata);
char *_stm_largemalloc_data_start(void);
+void _stm_move_object(char *src, char *dst);
+size_t _stm_data_size(struct object_s *data);
+void _stm_chunk_pages(struct object_s *data, uintptr_t *start, uintptr_t *num);
+
""")
lib = ffi.verify('''
diff --git a/c7/test/test_basic.py b/c7/test/test_basic.py
--- a/c7/test/test_basic.py
+++ b/c7/test/test_basic.py
@@ -353,8 +353,8 @@
new = stm_pop_root()
assert len(stm_get_obj_pages(new)) == 2
- assert ([stm_get_page_flag(p) for p in stm_get_obj_pages(new)]
- == [lib.UNCOMMITTED_SHARED_PAGE]*2)
+ # assert ([stm_get_page_flag(p) for p in stm_get_obj_pages(new)]
+ # == [lib.UNCOMMITTED_SHARED_PAGE]*2)
assert not is_in_nursery(new)
@@ -397,8 +397,8 @@
stm_push_root(new)
stm_minor_collect()
new = stm_pop_root()
- assert stm_get_page_flag(stm_get_obj_pages(new)[0]) ==
lib.UNCOMMITTED_SHARED_PAGE
- assert not (stm_get_flags(new) & lib.GCFLAG_NOT_COMMITTED)
+ # assert stm_get_page_flag(stm_get_obj_pages(new)[0]) ==
lib.UNCOMMITTED_SHARED_PAGE
+ # assert not (stm_get_flags(new) & lib.GCFLAG_NOT_COMMITTED)
stm_stop_transaction()
assert stm_get_page_flag(stm_get_obj_pages(new)[0]) == lib.SHARED_PAGE
@@ -446,7 +446,7 @@
stm_push_root(new)
stm_minor_collect()
new = stm_pop_root()
- assert stm_get_page_flag(stm_get_obj_pages(new)[0]) ==
lib.UNCOMMITTED_SHARED_PAGE
+ # assert stm_get_page_flag(stm_get_obj_pages(new)[0]) ==
lib.UNCOMMITTED_SHARED_PAGE
stm_abort_transaction()
stm_start_transaction()
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit