[pypy-commit] pypy stmgc-c8: add missing files from last commit
Raemi
noreply at buildbot.pypy.org
Thu Jan 22 11:37:54 CET 2015
Author: Remi Meier <remi.meier at inf.ethz.ch>
Branch: stmgc-c8
Changeset: r75479:acf538f01489
Date: 2015-01-22 10:59 +0100
http://bitbucket.org/pypy/pypy/changeset/acf538f01489/
Log: add missing files from last commit
diff --git a/rpython/translator/stm/src_stm/stm/smallmalloc.c b/rpython/translator/stm/src_stm/stm/smallmalloc.c
new file mode 100644
--- /dev/null
+++ b/rpython/translator/stm/src_stm/stm/smallmalloc.c
@@ -0,0 +1,366 @@
+/* Imported by rpython/translator/stm/import_stmgc.py */
+#ifndef _STM_CORE_H_
+# error "must be compiled via stmgc.c"
+#endif
+
+
+#define PAGE_SMSIZE_START 0
+#define PAGE_SMSIZE_END NB_SHARED_PAGES
+
+typedef struct {
+ uint8_t sz;
+} fpsz_t;
+
+static fpsz_t full_pages_object_size[PAGE_SMSIZE_END - PAGE_SMSIZE_START];
+/* ^^^ This array contains the size (in number of words) of the objects
+ in the given page, provided it's a "full page of small objects". It
+ is 0 if it's not such a page, if it's fully free, or if it's in
+ small_page_lists. It is not 0 as soon as the page enters the
+ segment's 'small_malloc_data.loc_free' (even if the page is not
+ technically full yet, it will be very soon in this case).
+*/
+
+static fpsz_t *get_fpsz(char *smallpage)
+{
+ uintptr_t pagenum = (((char *)smallpage) - END_NURSERY_PAGE * 4096UL - stm_object_pages) / 4096;
+ /* <= PAGE_SMSIZE_END because we may ask for it when there is no
+ page with smallobjs yet and uninit_page_stop == NB_PAGES... */
+ assert(PAGE_SMSIZE_START <= pagenum && pagenum <= PAGE_SMSIZE_END);
+ return &full_pages_object_size[pagenum - PAGE_SMSIZE_START];
+}
+
+
+#ifdef STM_TESTS
+bool (*_stm_smallmalloc_keep)(char *data); /* a hook for tests */
+#endif
+
+static void teardown_smallmalloc(void)
+{
+ memset(small_page_lists, 0, sizeof(small_page_lists));
+ assert(free_uniform_pages == NULL); /* done by the previous line */
+ first_small_uniform_loc = (uintptr_t) -1;
+#ifdef STM_TESTS
+ _stm_smallmalloc_keep = NULL;
+#endif
+ memset(full_pages_object_size, 0, sizeof(full_pages_object_size));
+}
+
+static int gmfp_lock = 0;
+
+static void grab_more_free_pages_for_small_allocations(void)
+{
+ dprintf(("grab_more_free_pages_for_small_allocation()\n"));
+ /* Grab GCPAGE_NUM_PAGES pages out of the top addresses. Use the
+ lock of pages.c to prevent any remapping from occurring under our
+ feet.
+ */
+ spinlock_acquire(gmfp_lock);
+
+ if (free_uniform_pages == NULL) {
+
+ uintptr_t decrease_by = GCPAGE_NUM_PAGES * 4096;
+ if (uninitialized_page_stop - uninitialized_page_start < decrease_by)
+ goto out_of_memory;
+
+ uninitialized_page_stop -= decrease_by;
+ first_small_uniform_loc = uninitialized_page_stop - stm_object_pages;
+
+ if (!_stm_largemalloc_resize_arena(uninitialized_page_stop - uninitialized_page_start))
+ goto out_of_memory;
+
+ /* make writable in sharing seg */
+ setup_N_pages(uninitialized_page_stop, GCPAGE_NUM_PAGES);
+
+ char *p = uninitialized_page_stop;
+ long i;
+ for (i = 0; i < GCPAGE_NUM_PAGES; i++) {
+ /* add to free_uniform_pages list */
+ struct small_free_loc_s *to_add = (struct small_free_loc_s *)p;
+
+ retry:
+ to_add->nextpage = free_uniform_pages;
+ if (UNLIKELY(!__sync_bool_compare_and_swap(
+ &free_uniform_pages,
+ to_add->nextpage,
+ to_add))) {
+ goto retry;
+ }
+
+ p += 4096;
+ }
+ }
+
+ spinlock_release(gmfp_lock);
+ return;
+
+ out_of_memory:
+ stm_fatalerror("out of memory!\n"); /* XXX */
+}
+
+static char *_allocate_small_slowpath(uint64_t size)
+{
+ dprintf(("_allocate_small_slowpath(%lu)\n", size));
+ long n = size / 8;
+ struct small_free_loc_s *smallpage;
+ struct small_free_loc_s *TLPREFIX *fl =
+ &STM_PSEGMENT->small_malloc_data.loc_free[n];
+ assert(*fl == NULL);
+
+ retry:
+ /* First try to grab the next page from the global 'small_page_list'
+ */
+ smallpage = small_page_lists[n];
+ if (smallpage != NULL) {
+ if (UNLIKELY(!__sync_bool_compare_and_swap(&small_page_lists[n],
+ smallpage,
+ smallpage->nextpage)))
+ goto retry;
+
+ /* Succeeded: we have a page in 'smallpage' */
+ *fl = smallpage->next;
+ get_fpsz((char *)smallpage)->sz = n;
+ return (char *)smallpage;
+ }
+
+ /* There is no more page waiting for the correct size of objects.
+ Maybe we can pick one from free_uniform_pages.
+ */
+ smallpage = free_uniform_pages;
+ if (smallpage != NULL) {
+ if (UNLIKELY(!__sync_bool_compare_and_swap(&free_uniform_pages,
+ smallpage,
+ smallpage->nextpage)))
+ goto retry;
+
+ /* Succeeded: we have a page in 'smallpage', which is not
+ initialized so far, apart from the 'nextpage' field read
+ above. Initialize it.
+ */
+ struct small_free_loc_s *p, **previous;
+ assert(!(((uintptr_t)smallpage) & 4095));
+ previous = (struct small_free_loc_s **)
+ REAL_ADDRESS(STM_SEGMENT->segment_base, fl);
+
+ /* Initialize all slots from the second one to the last one to
+ contain a chained list */
+ uintptr_t i = size;
+ while (i <= 4096 - size) {
+ p = (struct small_free_loc_s *)(((char *)smallpage) + i);
+ *previous = p;
+ previous = &p->next;
+ i += size;
+ }
+ *previous = NULL;
+
+ /* The first slot is immediately returned */
+ get_fpsz((char *)smallpage)->sz = n;
+ return (char *)smallpage;
+ }
+
+ /* Not a single free page left. Grab some more free pages and retry.
+ */
+ grab_more_free_pages_for_small_allocations();
+ goto retry;
+}
+
+__attribute__((always_inline))
+static inline stm_char *allocate_outside_nursery_small(uint64_t size)
+{
+ OPT_ASSERT((size & 7) == 0);
+ OPT_ASSERT(16 <= size && size <= GC_LAST_SMALL_SIZE);
+
+ struct small_free_loc_s *TLPREFIX *fl =
+ &STM_PSEGMENT->small_malloc_data.loc_free[size / 8];
+
+ struct small_free_loc_s *result = *fl;
+
+ increment_total_allocated(size);
+
+ if (UNLIKELY(result == NULL))
+ return (stm_char*)
+ (_allocate_small_slowpath(size) - stm_object_pages);
+
+ *fl = result->next;
+ dprintf(("allocate_outside_nursery_small(%lu): %p\n",
+ size, (char*)((char *)result - stm_object_pages)));
+ return (stm_char*)
+ ((char *)result - stm_object_pages);
+}
+
+object_t *_stm_allocate_old_small(ssize_t size_rounded_up)
+{
+ stm_char *p = allocate_outside_nursery_small(size_rounded_up);
+ object_t *o = (object_t *)p;
+
+ // sharing seg0 needs to be current:
+ assert(STM_SEGMENT->segment_num == 0);
+ memset(REAL_ADDRESS(STM_SEGMENT->segment_base, o), 0, size_rounded_up);
+ o->stm_flags = GCFLAG_WRITE_BARRIER;
+
+ dprintf(("_stm_allocate_old_small(%lu): %p, seg=%d, page=%lu\n",
+ size_rounded_up, p,
+ get_segment_of_linear_address(stm_object_pages + (uintptr_t)p),
+ (uintptr_t)p / 4096UL));
+
+ return o;
+}
+
+/************************************************************/
+
+static inline bool _smallmalloc_sweep_keep(char *p)
+{
+#ifdef STM_TESTS
+ if (_stm_smallmalloc_keep != NULL) {
+ // test wants a TLPREFIXd address
+ return _stm_smallmalloc_keep((char*)(p - stm_object_pages));
+ }
+#endif
+ return smallmalloc_keep_object_at(p);
+}
+
+void check_order_inside_small_page(struct small_free_loc_s *page)
+{
+#ifndef NDEBUG
+ /* the free locations are supposed to be in increasing order */
+ while (page->next != NULL) {
+ assert(page->next > page);
+ page = page->next;
+ }
+#endif
+}
+
+static char *getbaseptr(struct small_free_loc_s *fl)
+{
+ return (char *)(((uintptr_t)fl) & ~4095);
+}
+
+void sweep_small_page(char *baseptr, struct small_free_loc_s *page_free,
+ long szword)
+{
+ if (page_free != NULL)
+ check_order_inside_small_page(page_free);
+
+ /* for every non-free location, ask if we must free it */
+ uintptr_t i, size = szword * 8;
+ bool any_object_remaining = false, any_object_dying = false;
+ struct small_free_loc_s *fl = page_free;
+ struct small_free_loc_s *flprev = NULL;
+
+ /* XXX could optimize for the case where all objects die: we don't
+ need to painfully rebuild the free list in the whole page, just
+ to have it ignored in the end because we put the page into
+ 'free_uniform_pages' */
+
+ for (i = 0; i <= 4096 - size; i += size) {
+ char *p = baseptr + i;
+ if (p == (char *)fl) {
+ /* location is already free */
+ flprev = fl;
+ fl = fl->next;
+ any_object_dying = true;
+ }
+ else if (!_smallmalloc_sweep_keep(p)) {
+ /* the location should be freed now */
+ increment_total_allocated(-szword*8);
+#ifdef STM_TESTS
+ /* fill location with 0xdd in all segs except seg0 */
+ int j;
+ object_t *obj = (object_t*)(p - stm_object_pages);
+ uintptr_t page = (baseptr - stm_object_pages) / 4096UL;
+ for (j = 1; j < NB_SEGMENTS; j++)
+ if (get_page_status_in(j, page) == PAGE_ACCESSIBLE)
+ memset(get_virtual_address(j, obj), 0xdd, szword*8);
+#endif
+ //dprintf(("free small %p : %lu\n", (char*)(p - stm_object_pages), szword*8));
+
+ if (flprev == NULL) {
+ flprev = (struct small_free_loc_s *)p;
+ flprev->next = fl;
+ page_free = flprev;
+ }
+ else {
+ assert(flprev->next == fl);
+ flprev->next = (struct small_free_loc_s *)p;
+ flprev = (struct small_free_loc_s *)p;
+ flprev->next = fl;
+ }
+ any_object_dying = true;
+ }
+ else {
+ //dprintf(("keep small %p : %lu\n", (char*)(p - stm_object_pages), szword*8));
+ any_object_remaining = true;
+ }
+ }
+ if (!any_object_remaining) {
+ /* give page back to free_uniform_pages and thus make it
+ inaccessible from all other segments again (except seg0) */
+ uintptr_t page = (baseptr - stm_object_pages) / 4096UL;
+ for (i = 1; i < NB_SEGMENTS; i++) {
+ if (get_page_status_in(i, page) == PAGE_ACCESSIBLE)
+ page_mark_inaccessible(i, page);
+ }
+
+ ((struct small_free_loc_s *)baseptr)->nextpage = free_uniform_pages;
+ free_uniform_pages = (struct small_free_loc_s *)baseptr;
+ }
+ else if (!any_object_dying) {
+ get_fpsz(baseptr)->sz = szword;
+ }
+ else {
+ check_order_inside_small_page(page_free);
+ page_free->nextpage = small_page_lists[szword];
+ small_page_lists[szword] = page_free;
+ }
+}
+
+void _stm_smallmalloc_sweep(void)
+{
+ long i, szword;
+ for (szword = 2; szword < GC_N_SMALL_REQUESTS; szword++) {
+ struct small_free_loc_s *page = small_page_lists[szword];
+ struct small_free_loc_s *nextpage;
+ small_page_lists[szword] = NULL;
+
+ /* process the pages that the various segments are busy filling */
+ /* including sharing seg0 for old-malloced things */
+ for (i = 0; i < NB_SEGMENTS; i++) {
+ struct stm_priv_segment_info_s *pseg = get_priv_segment(i);
+ struct small_free_loc_s **fl =
+ &pseg->small_malloc_data.loc_free[szword];
+ if (*fl != NULL) {
+ /* the entry in full_pages_object_size[] should already be
+ szword. We reset it to 0. */
+ fpsz_t *fpsz = get_fpsz((char *)*fl);
+ assert(fpsz->sz == szword);
+ fpsz->sz = 0;
+ sweep_small_page(getbaseptr(*fl), *fl, szword);
+ *fl = NULL;
+ }
+ }
+
+ /* process all the other partially-filled pages */
+ while (page != NULL) {
+ /* for every page in small_page_lists: assert that the
+ corresponding full_pages_object_size[] entry is 0 */
+ assert(get_fpsz((char *)page)->sz == 0);
+ nextpage = page->nextpage;
+ sweep_small_page(getbaseptr(page), page, szword);
+ page = nextpage;
+ }
+ }
+
+ /* process the really full pages, which are the ones which still
+ have a non-zero full_pages_object_size[] entry */
+ char *pageptr = uninitialized_page_stop;
+ fpsz_t *fpsz_start = get_fpsz(pageptr);
+ fpsz_t *fpsz_end = &full_pages_object_size[PAGE_SMSIZE_END -
+ PAGE_SMSIZE_START];
+ fpsz_t *fpsz;
+ for (fpsz = fpsz_start; fpsz < fpsz_end; fpsz++, pageptr += 4096) {
+ uint8_t sz = fpsz->sz;
+ if (sz != 0) {
+ fpsz->sz = 0;
+ sweep_small_page(pageptr, NULL, sz);
+ }
+ }
+}
diff --git a/rpython/translator/stm/src_stm/stm/smallmalloc.h b/rpython/translator/stm/src_stm/stm/smallmalloc.h
new file mode 100644
--- /dev/null
+++ b/rpython/translator/stm/src_stm/stm/smallmalloc.h
@@ -0,0 +1,67 @@
+/* Imported by rpython/translator/stm/import_stmgc.py */
+
+/* Outside the nursery, we are taking from the highest addresses
+ complete pages, one at a time, which uniformly contain objects of
+ size "8 * N" for some N in range(2, GC_N_SMALL_REQUESTS). We are
+ taking from the lowest addresses "large" objects, which are at least
+ 288 bytes long, allocated by largemalloc.c. The limit is the same
+ as used in PyPy's default GC.
+*/
+
+#define GC_N_SMALL_REQUESTS 36
+#define GC_LAST_SMALL_SIZE (8 * (GC_N_SMALL_REQUESTS - 1))
+
+
+struct small_free_loc_s {
+ /* A chained list of locations within the same page which are
+ free. */
+ struct small_free_loc_s *next;
+
+ /* A chained list of all small pages containing objects of a given
+ small size, and that have at least one free object. It points
+ *inside* the next page, to another struct small_free_loc_s. This
+ field is only meaningful on the first small_free_loc_s of a given
+ page! */
+ struct small_free_loc_s *nextpage;
+
+ /* This structure is only two words, so it always fits inside one
+ free slot inside the page. */
+};
+
+
+/* For every size from 16 bytes to 8*(GC_N_SMALL_REQUESTS-1), this is
+ a list of pages that contain objects of that size and have at least
+ one free location. Additionally, the item 0 in the following list
+ is a chained list of fully-free pages (which can be reused for a
+ different size than the one they originally contained).
+*/
+static struct small_free_loc_s *small_page_lists[GC_N_SMALL_REQUESTS];
+
+#define free_uniform_pages (small_page_lists[0])
+
+
+/* For is_small_uniform(). */
+static uintptr_t first_small_uniform_loc = (uintptr_t) -1;
+
+
+/* This is a definition for 'STM_PSEGMENT->small_malloc_data'. Each
+ segment grabs one page at a time from the global list, and then
+ requests for data are answered locally.
+*/
+struct small_malloc_data_s {
+ struct small_free_loc_s *loc_free[GC_N_SMALL_REQUESTS];
+};
+
+
+/* Functions
+ */
+static inline stm_char *allocate_outside_nursery_small(uint64_t size)
+ __attribute__((always_inline));
+
+void _stm_smallmalloc_sweep(void);
+
+static void teardown_smallmalloc(void);
+
+static inline bool is_small_uniform(object_t *obj) {
+ return ((uintptr_t)obj) >= first_small_uniform_loc;
+}
More information about the pypy-commit
mailing list