[pypy-commit] stmgc c5: fix fix fix

arigo noreply at buildbot.pypy.org
Fri Dec 20 11:55:15 CET 2013


Author: Armin Rigo <arigo at tunes.org>
Branch: c5
Changeset: r570:87e71aeae74c
Date: 2013-12-20 11:54 +0100
http://bitbucket.org/pypy/stmgc/changeset/87e71aeae74c/

Log:	fix fix fix

diff --git a/c5/demo2.c b/c5/demo2.c
--- a/c5/demo2.c
+++ b/c5/demo2.c
@@ -5,10 +5,24 @@
 char *stm_large_malloc(size_t request_size);
 
 
+static void dump(char *data)
+{
+    fprintf(stderr, "[ %p: %zu\n", data - 16, *(size_t*)(data - 16));
+    fprintf(stderr, "  %p: %zu\n", data - 8, *(size_t*)(data - 8));
+    size_t n = (*(size_t*)(data - 8)) & ~1;
+    fprintf(stderr, "  %p: %zu ]\n", data + n, *(size_t*)(data + n));
+}
+
 int main()
 {
-    printf("%p\n", stm_large_malloc(10000));
-    printf("%p\n", stm_large_malloc(10000));
-    printf("%p\n", stm_large_malloc(10000));
+    char *d1 = stm_large_malloc(10000);
+    char *d2 = stm_large_malloc(10000);
+    char *d3 = stm_large_malloc(10000);
+
+    dump(d1);
+    dump(d2);
+    dump(d3);
+    dump(d3 + 10016);
+
     return 0;
 }
diff --git a/c5/largemalloc.c b/c5/largemalloc.c
--- a/c5/largemalloc.c
+++ b/c5/largemalloc.c
@@ -11,14 +11,15 @@
 
 #define MMAP_LIMIT    (1280*1024)
 
-#define largebin_index(sz)                                       \
-    ((((sz) >>  6) <= 47) ?      ((sz) >>  6):  /*  0 - 47 */    \
-     (((sz) >>  9) <= 23) ? 42 + ((sz) >>  9):  /* 48 - 65 */    \
-     (((sz) >> 12) <= 11) ? 63 + ((sz) >> 12):  /* 66 - 74 */    \
-     (((sz) >> 15) <=  5) ? 74 + ((sz) >> 15):  /* 75 - 79 */    \
-     (((sz) >> 18) <=  2) ? 80 + ((sz) >> 18):  /* 80 - 82 */    \
-                            83)
-#define N_BINS              84
+#define largebin_index(sz)                                      \
+    (((sz) < (48 <<  6)) ?      ((sz) >>  6):  /*  0 - 47 */    \
+     ((sz) < (24 <<  9)) ? 42 + ((sz) >>  9):  /* 48 - 65 */    \
+     ((sz) < (12 << 12)) ? 63 + ((sz) >> 12):  /* 66 - 74 */    \
+     ((sz) < (6  << 15)) ? 74 + ((sz) >> 15):  /* 75 - 79 */    \
+     ((sz) < (3  << 18)) ? 80 + ((sz) >> 18):  /* 80 - 82 */    \
+                           83)
+#define N_BINS             84
+#define LAST_BIN_INDEX(sz) ((sz) >= (3 << 18))
 
 typedef struct dlist_s {
     struct dlist_s *next;   /* a doubly-linked list */
@@ -29,7 +30,8 @@
     size_t prev_size;     /* - if the previous chunk is free: size of its data
                              - otherwise, if this chunk is free: 1
                              - otherwise, 0. */
-    size_t size;          /* size of the data in this chunk */
+    size_t size;          /* size of the data in this chunk,
+                             plus optionally the FLAG_UNSORTED */
 
     dlist_t d;            /* if free: a doubly-linked list */
                           /* if not free: the user data starts here */
@@ -41,6 +43,7 @@
        considered "not free". */
 } mchunk_t;
 
+#define FLAG_UNSORTED        1
 #define THIS_CHUNK_FREE      1
 #define BOTH_CHUNKS_USED     0
 #define CHUNK_HEADER_SIZE    offsetof(struct malloc_chunk, d)
@@ -60,12 +63,14 @@
    neighbors to ensure this.
 
    In each bin's doubly-linked list, chunks are sorted by their size in
-   decreasing order (if you start from 'd.next').
+   decreasing order (if you start from 'd.next').  At the end of this
+   list are some unsorted chunks (with FLAG_UNSORTED).  All unsorted
+   chunks are after all sorted chunks.
 */
 
-static struct { dlist_t d; dlist_t *unsorted; } largebins[N_BINS] = {
+static dlist_t largebins[N_BINS] = {
 
-#define INIT(num)   { { &largebins[num].d, &largebins[num].d }, NULL }
+#define INIT(num)   { largebins + num, largebins + num }
     INIT(0),  INIT(1),  INIT(2),  INIT(3),  INIT(4),
     INIT(5),  INIT(6),  INIT(7),  INIT(8),  INIT(9),
     INIT(10), INIT(11), INIT(12), INIT(13), INIT(14),
@@ -90,59 +95,67 @@
 
 static void insert_unsorted(mchunk_t *new)
 {
-    size_t index = largebin_index(new->size);
-    new->d.next = largebins[index].unsorted;
-    largebins[index].unsorted = &new->d;
+    size_t index = LAST_BIN_INDEX(new->size) ? N_BINS - 1
+                                             : largebin_index(new->size);
+    new->d.next = &largebins[index];
+    new->d.prev = largebins[index].prev;
+    new->d.prev->next = &new->d;
+    largebins[index].prev = &new->d;
+    new->size |= FLAG_UNSORTED;
 }
 
 static int compare_chunks(const void *vchunk1, const void *vchunk2)
 {
-    /* sort by decreasing size */
+    /* sort by size */
     const mchunk_t *chunk1 = (const mchunk_t *)vchunk1;
     const mchunk_t *chunk2 = (const mchunk_t *)vchunk2;
     if (chunk1->size < chunk2->size)
-        return 1;
+        return -1;
     if (chunk1->size == chunk2->size)
         return 0;
     else
-        return -1;
+        return +1;
 }
 
 static void really_sort_bin(size_t index)
 {
-    dlist_t *unsorted = largebins[index].unsorted;
-    largebins[index].unsorted = NULL;
-
-    dlist_t *scan = unsorted->next;
+    dlist_t *unsorted = largebins[index].prev;
+    dlist_t *end = &largebins[index];
+    dlist_t *scan = unsorted->prev;
     size_t count = 1;
-    while (scan != NULL) {
-        scan = scan->next;
+    while (scan != end && (data2chunk(scan)->size & FLAG_UNSORTED)) {
+        scan = scan->prev;
         ++count;
     }
+    end->prev = scan;
+    scan->next = end;
 
     mchunk_t *chunks[count];
     size_t i;
     for (i = 0; i < count; i++) {
         chunks[i] = data2chunk(unsorted);
-        unsorted = unsorted->next;
+        unsorted = unsorted->prev;
     }
+    assert(unsorted == scan);
     qsort(chunks, count, sizeof(mchunk_t *), compare_chunks);
 
-    dlist_t *head = largebins[index].d.next;
-    dlist_t *end = &largebins[index].d;
-    size_t search_size = chunks[0]->size;
-    i = 0;
+    --count;
+    chunks[count]->size &= ~FLAG_UNSORTED;
+    size_t search_size = chunks[count]->size;
+    dlist_t *head = largebins[index].next;
 
     while (1) {
         if (head == end || search_size >= data2chunk(head)->size) {
-            /* insert 'chunks[i]' here, before the current head */
-            head->prev->next = &chunks[i]->d;
-            chunks[i]->d.prev = head->prev;
-            head->prev = &chunks[i]->d;
-            chunks[i]->d.next = head;
-            if (++i == count)
+            /* insert 'chunks[count]' here, before the current head */
+            head->prev->next = &chunks[count]->d;
+            chunks[count]->d.prev = head->prev;
+            head->prev = &chunks[count]->d;
+            chunks[count]->d.next = head;
+            if (count == 0)
                 break;    /* all done */
-            search_size = chunks[i]->size;
+            --count;
+            chunks[count]->size &= ~FLAG_UNSORTED;
+            search_size = chunks[count]->size;
         }
         else {
             head = head->next;
@@ -152,7 +165,8 @@
 
 static void sort_bin(size_t index)
 {
-    if (largebins[index].unsorted != NULL)
+    dlist_t *last = largebins[index].prev;
+    if (last != &largebins[index] && (data2chunk(last)->size & FLAG_UNSORTED))
         really_sort_bin(index);
 }
 
@@ -166,40 +180,16 @@
 
     /* scan through the chunks of current bin in reverse order
        to find the smallest that fits. */
-    dlist_t *scan = largebins[index].d.prev;
-    dlist_t *head = largebins[index].d.next;
+    dlist_t *scan = largebins[index].prev;
+    dlist_t *end = &largebins[index];
     mchunk_t *mscan;
-    while (scan != head) {
+    while (scan != end) {
         mscan = data2chunk(scan);
         assert(mscan->prev_size == THIS_CHUNK_FREE);
         assert(next_chunk(mscan)->prev_size == mscan->size);
 
-        if (mscan->size >= request_size) {
-            /* found! */
-         found:
-            /* unlink mscan from the doubly-linked list */
-            mscan->d.next->prev = mscan->d.prev;
-            mscan->d.prev->next = mscan->d.next;
-
-            size_t remaining_size = mscan->size - request_size;
-            if (remaining_size < sizeof(struct malloc_chunk)) {
-                next_chunk(mscan)->prev_size = BOTH_CHUNKS_USED;
-            }
-            else {
-                /* only part of the chunk is being used; reduce the size
-                   of 'mscan' down to 'request_size', and create a new
-                   chunk of the 'remaining_size' afterwards */
-                mchunk_t *new = chunk_at_offset(mscan, CHUNK_HEADER_SIZE +
-                                                       request_size);
-                new->prev_size = THIS_CHUNK_FREE;
-                new->size = remaining_size - CHUNK_HEADER_SIZE;
-                next_chunk(new)->prev_size = remaining_size;
-                insert_unsorted(new);
-                mscan->size = request_size;
-            }
-            mscan->prev_size = BOTH_CHUNKS_USED;
-            return (char *)&mscan->d;
-        }
+        if (mscan->size >= request_size)
+            goto found;
         scan = mscan->d.prev;
     }
 
@@ -208,8 +198,9 @@
        enough.  xxx use a bitmap to speed this up */
     while (++index < N_BINS) {
         sort_bin(index);
-        scan = largebins[index].d.prev;
-        if (scan != &largebins[index].d) {
+        scan = largebins[index].prev;
+        end = &largebins[index];
+        if (scan != end) {
             mscan = data2chunk(scan);
             assert(mscan->size >= request_size);
             goto found;
@@ -218,6 +209,31 @@
 
     /* not enough free memory.  We need to allocate more. */
     return allocate_more(request_size);
+
+ found:
+    /* unlink mscan from the doubly-linked list */
+    mscan->d.next->prev = mscan->d.prev;
+    mscan->d.prev->next = mscan->d.next;
+
+    size_t remaining_size = mscan->size - request_size;
+    if (remaining_size < sizeof(struct malloc_chunk)) {
+        next_chunk(mscan)->prev_size = BOTH_CHUNKS_USED;
+    }
+    else {
+        /* only part of the chunk is being used; reduce the size
+           of 'mscan' down to 'request_size', and create a new
+           chunk of the 'remaining_size' afterwards */
+        mchunk_t *new = chunk_at_offset(mscan, CHUNK_HEADER_SIZE +
+                                               request_size);
+        new->prev_size = THIS_CHUNK_FREE;
+        remaining_size -= CHUNK_HEADER_SIZE;
+        new->size = remaining_size;
+        next_chunk(new)->prev_size = remaining_size;
+        insert_unsorted(new);
+        mscan->size = request_size;
+    }
+    mscan->prev_size = BOTH_CHUNKS_USED;
+    return (char *)&mscan->d;
 }
 
 static char *allocate_more(size_t request_size)
@@ -233,8 +249,30 @@
 
     big_chunk->prev_size = THIS_CHUNK_FREE;
     big_chunk->size = big_size - CHUNK_HEADER_SIZE - sizeof(size_t);
+
+    assert((char *)&next_chunk(big_chunk)->prev_size ==
+           ((char *)big_chunk) + big_size - sizeof(size_t));
     next_chunk(big_chunk)->prev_size = big_chunk->size;
+
     insert_unsorted(big_chunk);
 
     return stm_large_malloc(request_size);
 }
+
+void stm_large_free(char *data)
+{
+#if 0
+    mchunk_t *chunk = data2chunk(data);
+    assert(chunk->prev_size != THIS_CHUNK_FREE);
+
+    if (chunk->prev_size == BOTH_CHUNKS_USED) {
+        chunk->prev_size = THIS_CHUNK_FREE;
+    }
+    else {
+        assert((chunk->prev_size & (sizeof(char *) - 1)) == 0);
+
+        /* merge with the previous chunk */
+        ...
+    }
+#endif
+}


More information about the pypy-commit mailing list