Author: Nicolas Truessel <[email protected]>
Branch: quad-color-gc
Changeset: r86977:e2e9fdac5cf3
Date: 2016-09-09 18:01 +0200
http://bitbucket.org/pypy/pypy/changeset/e2e9fdac5cf3/
Log: Update qcgc codebase
diff --git a/rpython/translator/c/src/qcgc/allocator.c
b/rpython/translator/c/src/qcgc/allocator.c
--- a/rpython/translator/c/src/qcgc/allocator.c
+++ b/rpython/translator/c/src/qcgc/allocator.c
@@ -29,6 +29,8 @@
qcgc_arena_bag_create(QCGC_ARENA_BAG_INIT_SIZE);
qcgc_allocator_state.free_arenas = qcgc_arena_bag_create(4); // XXX
+ qcgc_allocator_state.use_bump_allocator = true;
+
// Bump Allocator
qcgc_allocator_state.bump_state.bump_ptr = NULL;
qcgc_allocator_state.bump_state.remaining_cells = 0;
@@ -254,17 +256,22 @@
#endif
cell_t *result = NULL;
for ( ; index < QCGC_SMALL_FREE_LISTS; index++) {
- linear_free_list_t *free_list =
- qcgc_allocator_state.fit_state.small_free_list[index];
size_t list_cell_size = small_index_to_cells(index);
- while (free_list->count > 0) {
- result = free_list->items[free_list->count - 1];
- free_list =
qcgc_linear_free_list_remove_index(free_list,
- free_list->count - 1);
+ while
(qcgc_allocator_state.fit_state.small_free_list[index]->count
+ > 0) {
+ result =
qcgc_allocator_state.fit_state.small_free_list[index]->
+
items[qcgc_allocator_state.fit_state.small_free_list[index]
+ ->count - 1];
+ qcgc_allocator_state.fit_state.small_free_list[index] =
+ qcgc_linear_free_list_remove_index(
+
qcgc_allocator_state.fit_state.small_free_list[index],
+
qcgc_allocator_state.fit_state.small_free_list[index]->
+ count - 1);
// Check whether block is still valid
if (valid_block(result, list_cell_size)) {
+ // The next call might invalidate free_list,
reload!
qcgc_fit_allocator_add(result + cells,
list_cell_size - cells);
break;
} else {
@@ -272,7 +279,6 @@
}
}
- qcgc_allocator_state.fit_state.small_free_list[index] =
free_list;
if (result != NULL) {
return result;
}
@@ -285,24 +291,32 @@
assert(1u<<(index + QCGC_LARGE_FREE_LIST_FIRST_EXP) <= cells);
assert(1u<<(index + QCGC_LARGE_FREE_LIST_FIRST_EXP + 1) > cells);
#endif
- exp_free_list_t *free_list =
- qcgc_allocator_state.fit_state.large_free_list[index];
- size_t best_fit_index = free_list->count;
+ size_t best_fit_index = qcgc_allocator_state.fit_state.
+ large_free_list[index]->count;
cell_t *result = NULL;
size_t best_fit_cells = SIZE_MAX;
size_t i = 0;
- while (i < free_list->count) {
- if (valid_block(free_list->items[i].ptr,
free_list->items[i].size)) {
- if (free_list->items[i].size >= cells &&
- free_list->items[i].size <
best_fit_cells) {
- result = free_list->items[i].ptr;
- best_fit_cells = free_list->items[i].size;
+ while (i <
qcgc_allocator_state.fit_state.large_free_list[index]->count) {
+ if
(valid_block(qcgc_allocator_state.fit_state.large_free_list[index] ->
+ items[i].ptr,
+
qcgc_allocator_state.fit_state.large_free_list[index]->
+ items[i].size)) {
+ if
(qcgc_allocator_state.fit_state.large_free_list[index]->
+ items[i].size >= cells &&
+
qcgc_allocator_state.fit_state.large_free_list[index]->
+ items[i].size < best_fit_cells) {
+ result =
qcgc_allocator_state.fit_state.large_free_list[index]->
+ items[i].ptr;
+ best_fit_cells = qcgc_allocator_state.fit_state.
+ large_free_list[index]->items[i].size;
best_fit_index = i;
}
i++;
} else {
- free_list = qcgc_exp_free_list_remove_index(free_list,
i);
+ qcgc_allocator_state.fit_state.large_free_list[index] =
+
qcgc_exp_free_list_remove_index(qcgc_allocator_state.fit_state.
+ large_free_list[index], i);
// NO i++ !
}
@@ -313,14 +327,16 @@
if (result != NULL) {
// Best fit was found
- assert(best_fit_index < free_list->count);
- free_list = qcgc_exp_free_list_remove_index(free_list,
best_fit_index);
+ assert(best_fit_index < qcgc_allocator_state.fit_state.
+ large_free_list[index]->count);
+ qcgc_allocator_state.fit_state.large_free_list[index] =
+
qcgc_exp_free_list_remove_index(qcgc_allocator_state.fit_state.
+ large_free_list[index], best_fit_index);
qcgc_fit_allocator_add(result + cells, best_fit_cells - cells);
} else {
// No best fit, go for first fit
result = fit_allocator_large_first_fit(index + 1, cells);
}
- qcgc_allocator_state.fit_state.large_free_list[index] = free_list;
return result;
}
@@ -330,13 +346,17 @@
#endif
cell_t *result = NULL;
for ( ; index < QCGC_LARGE_FREE_LISTS; index++) {
- exp_free_list_t *free_list =
- qcgc_allocator_state.fit_state.large_free_list[index];
- while(free_list->count > 0) {
+
while(qcgc_allocator_state.fit_state.large_free_list[index]->count
+ > 0) {
struct exp_free_list_item_s item =
- free_list->items[free_list->count - 1];
- free_list = qcgc_exp_free_list_remove_index(free_list,
- free_list->count - 1);
+
qcgc_allocator_state.fit_state.large_free_list[index]->items[
+
qcgc_allocator_state.fit_state.large_free_list[index]->count - 1
+ ];
+ qcgc_allocator_state.fit_state.large_free_list[index] =
+ qcgc_exp_free_list_remove_index(
+
qcgc_allocator_state.fit_state.large_free_list[index],
+
qcgc_allocator_state.fit_state.large_free_list[index]->
+ count - 1);
// Check whether block is still valid
if (valid_block(item.ptr, item.size)) {
@@ -345,7 +365,6 @@
break;
}
}
- qcgc_allocator_state.fit_state.large_free_list[index] =
free_list;
if (result != NULL) {
return result;
}
diff --git a/rpython/translator/c/src/qcgc/allocator.h
b/rpython/translator/c/src/qcgc/allocator.h
--- a/rpython/translator/c/src/qcgc/allocator.h
+++ b/rpython/translator/c/src/qcgc/allocator.h
@@ -48,6 +48,7 @@
linear_free_list_t *small_free_list[QCGC_SMALL_FREE_LISTS];
exp_free_list_t *large_free_list[QCGC_LARGE_FREE_LISTS];
} fit_state;
+ bool use_bump_allocator;
} qcgc_allocator_state;
/**
diff --git a/rpython/translator/c/src/qcgc/arena.c
b/rpython/translator/c/src/qcgc/arena.c
--- a/rpython/translator/c/src/qcgc/arena.c
+++ b/rpython/translator/c/src/qcgc/arena.c
@@ -11,6 +11,7 @@
#include "allocator.h"
#include "event_logger.h"
+#include "gc_state.h"
/**
* Internal functions
@@ -178,85 +179,124 @@
// No coalescing, collector will do this
}
+bool qcgc_arena_pseudo_sweep(arena_t *arena) {
+#if CHECKED
+ assert(arena != NULL);
+ assert(qcgc_arena_is_coalesced(arena));
+ assert(qcgc_arena_addr(qcgc_allocator_state.bump_state.bump_ptr) ==
arena);
+#endif
+ // XXX: Maybe ignore free cell / largest block counting here?
+ size_t last_free_cell = 0;
+ for (size_t cell = QCGC_ARENA_FIRST_CELL_INDEX;
+ cell < QCGC_ARENA_CELLS_COUNT;
+ cell++) {
+ switch (get_blocktype(arena, cell)) {
+ case BLOCK_FREE:
+ last_free_cell = cell;
+ case BLOCK_EXTENT: // Fall through
+ break;
+ case BLOCK_BLACK:
+ set_blocktype(arena, cell, BLOCK_WHITE);
+ case BLOCK_WHITE: // Fall through
+ if (last_free_cell != 0) {
+ qcgc_state.free_cells += cell -
last_free_cell;
+ qcgc_state.largest_free_block = MAX(
+
qcgc_state.largest_free_block,
+ cell - last_free_cell);
+ last_free_cell = 0;
+ }
+ break;
+ }
+ }
+ if (last_free_cell != 0) {
+ qcgc_state.free_cells += QCGC_ARENA_CELLS_COUNT -
last_free_cell;
+ qcgc_state.largest_free_block = MAX(
+ qcgc_state.largest_free_block,
+ QCGC_ARENA_CELLS_COUNT - last_free_cell);
+ last_free_cell = 0;
+ }
+#if CHECKED
+ assert(qcgc_arena_is_coalesced(arena));
+#endif
+ return false;
+}
+
bool qcgc_arena_sweep(arena_t *arena) {
#if CHECKED
assert(arena != NULL);
assert(qcgc_arena_is_coalesced(arena));
+ //assert(qcgc_arena_addr(qcgc_allocator_state.bump_state.bump_ptr) !=
arena);
#endif
-#if DEBUG_ZERO_ON_SWEEP
- bool zero = true;
-#endif
- bool free = true;
- bool coalesce = false;
- bool add_to_free_list = false;
- size_t last_free_cell = QCGC_ARENA_FIRST_CELL_INDEX;
-
if (qcgc_arena_addr(qcgc_allocator_state.bump_state.bump_ptr) == arena)
{
- for (size_t cell = QCGC_ARENA_FIRST_CELL_INDEX;
- cell < QCGC_ARENA_CELLS_COUNT;
- cell++) {
- if (get_blocktype(arena, cell) == BLOCK_BLACK) {
- set_blocktype(arena, cell, BLOCK_WHITE);
- }
- }
- return false;
+ return qcgc_arena_pseudo_sweep(arena);
}
+ size_t last_free_cell = 0;
+ bool register_free_block = false;
+ bool free = true;
for (size_t cell = QCGC_ARENA_FIRST_CELL_INDEX;
cell < QCGC_ARENA_CELLS_COUNT;
cell++) {
switch (get_blocktype(arena, cell)) {
case BLOCK_EXTENT:
-#if DEBUG_ZERO_ON_SWEEP
- if (zero) {
- memset(&arena->cells[cell], 0,
sizeof(cell_t));
- }
-#endif
break;
case BLOCK_FREE:
- if (coalesce) {
+ if (last_free_cell != 0) {
+ // Coalesce
set_blocktype(arena, cell,
BLOCK_EXTENT);
} else {
last_free_cell = cell;
}
- coalesce = true;
-#if DEBUG_ZERO_ON_SWEEP
- zero = true;
- memset(&arena->cells[cell], 0, sizeof(cell_t));
-#endif
+ // ==> last_free_cell != 0
break;
case BLOCK_WHITE:
- if (coalesce) {
+ if (last_free_cell != 0) {
+ // Coalesce
set_blocktype(arena, cell,
BLOCK_EXTENT);
} else {
set_blocktype(arena, cell, BLOCK_FREE);
last_free_cell = cell;
}
- coalesce = true;
- add_to_free_list = true;
-#if DEBUG_ZERO_ON_SWEEP
- zero = true;
- memset(&arena->cells[cell], 0, sizeof(cell_t));
-#endif
+ // ==> last_free_cell != 0
+ register_free_block = true;
break;
case BLOCK_BLACK:
set_blocktype(arena, cell, BLOCK_WHITE);
- if (add_to_free_list) {
- qcgc_fit_allocator_add(arena->cells +
last_free_cell,
+ if (last_free_cell != 0) {
+ if (register_free_block) {
+
qcgc_fit_allocator_add(arena->cells + last_free_cell,
+ cell -
last_free_cell);
+#if DEBUG_ZERO_ON_SWEEP
+ memset(arena->cells +
last_free_cell, 0,
+ sizeof(cell_t)
* (cell - last_free_cell));
+#endif
+ }
+ qcgc_state.free_cells += cell -
last_free_cell;
+ qcgc_state.largest_free_block = MAX(
+
qcgc_state.largest_free_block,
cell - last_free_cell);
+ last_free_cell = 0;
}
+ register_free_block = false;
free = false;
- coalesce = false;
- add_to_free_list = false;
-#if DEBUG_ZERO_ON_SWEEP
- zero = false;
-#endif
+ // ==> last_free_cell == 0
break;
}
}
- if (add_to_free_list && !free) {
- qcgc_fit_allocator_add(arena->cells + last_free_cell,
- QCGC_ARENA_CELLS_COUNT
- last_free_cell);
+ if (last_free_cell != 0 && !free) {
+ if (register_free_block) {
+ qcgc_fit_allocator_add(arena->cells + last_free_cell,
+ QCGC_ARENA_CELLS_COUNT -
last_free_cell);
+#if DEBUG_ZERO_ON_SWEEP
+ memset(arena->cells + last_free_cell, 0,
+ sizeof(cell_t) *
(QCGC_ARENA_CELLS_COUNT - last_free_cell));
+#endif
+ }
+ qcgc_state.free_cells += QCGC_ARENA_CELLS_COUNT -
last_free_cell;
+ qcgc_state.largest_free_block = MAX(
+ qcgc_state.largest_free_block,
+ QCGC_ARENA_CELLS_COUNT - last_free_cell);
+ last_free_cell = 0;
}
#if CHECKED
assert(qcgc_arena_is_coalesced(arena));
@@ -284,6 +324,7 @@
return true;
}
+
bool qcgc_arena_is_coalesced(arena_t *arena) {
#if CHECKED
assert(arena != NULL);
diff --git a/rpython/translator/c/src/qcgc/arena.h
b/rpython/translator/c/src/qcgc/arena.h
--- a/rpython/translator/c/src/qcgc/arena.h
+++ b/rpython/translator/c/src/qcgc/arena.h
@@ -143,6 +143,15 @@
*/
bool qcgc_arena_sweep(arena_t *arena);
+/**
+ * Sweep given arena, but only reset black to white, no white to free
+ *
+ * @param arena Arena
+ * @return Whether arena is empty after sweeping, always false
+ */
+bool qcgc_arena_pseudo_sweep(arena_t *arena);
+
+
/*******************************************************************************
* Debug functions
*
******************************************************************************/
diff --git a/rpython/translator/c/src/qcgc/config.h
b/rpython/translator/c/src/qcgc/config.h
--- a/rpython/translator/c/src/qcgc/config.h
+++ b/rpython/translator/c/src/qcgc/config.h
@@ -1,14 +1,14 @@
#pragma once
#define CHECKED 0 //
Enable runtime sanity checks
-#define DEBUG_ZERO_ON_SWEEP 1 // Zero memory on sweep
(debug only)
+#define DEBUG_ZERO_ON_SWEEP 0 // Zero memory on sweep
(debug only)
#define QCGC_INIT_ZERO 1 // Init new
objects with zero bytes
/**
* Event logger
*/
-#define EVENT_LOG 0 //
Enable event log
+#define EVENT_LOG 1 //
Enable event log
#define LOGFILE "./qcgc_events.log" // Default logfile
#define LOG_ALLOCATION 0 // Enable
allocation log (warning:
// significant performance impact)
diff --git a/rpython/translator/c/src/qcgc/event_logger.h
b/rpython/translator/c/src/qcgc/event_logger.h
--- a/rpython/translator/c/src/qcgc/event_logger.h
+++ b/rpython/translator/c/src/qcgc/event_logger.h
@@ -21,7 +21,6 @@
EVENT_NEW_ARENA,
EVENT_MARK_START,
- EVENT_INCMARK_START,
EVENT_MARK_DONE,
};
diff --git a/rpython/translator/c/src/qcgc/gc_state.h
b/rpython/translator/c/src/qcgc/gc_state.h
--- a/rpython/translator/c/src/qcgc/gc_state.h
+++ b/rpython/translator/c/src/qcgc/gc_state.h
@@ -33,4 +33,9 @@
gc_phase_t phase;
size_t bytes_since_collection;
size_t bytes_since_incmark;
+ size_t free_cells; // Overall amount of free cells
without huge
+ // blocks and
free areans. Valid right after sweep
+ size_t largest_free_block; // Size of the largest free block.
+ // (Free arenas
don't count as free blocks)
+ // Valid right
after sweep
} qcgc_state;
diff --git a/rpython/translator/c/src/qcgc/qcgc.c
b/rpython/translator/c/src/qcgc/qcgc.c
--- a/rpython/translator/c/src/qcgc/qcgc.c
+++ b/rpython/translator/c/src/qcgc/qcgc.c
@@ -38,6 +38,8 @@
qcgc_state.phase = GC_PAUSE;
qcgc_state.bytes_since_collection = 0;
qcgc_state.bytes_since_incmark = 0;
+ qcgc_state.free_cells = 0;
+ qcgc_state.largest_free_block = 0;
qcgc_allocator_initialize();
qcgc_hbtable_initialize();
qcgc_event_logger_initialize();
@@ -145,7 +147,7 @@
if (size <= 1<<QCGC_LARGE_ALLOC_THRESHOLD_EXP) {
// Use bump / fit allocator
- if (true) { // FIXME: Implement reasonable switch
+ if (qcgc_allocator_state.use_bump_allocator) {
result = qcgc_bump_allocate(size);
} else {
result = qcgc_fit_allocate(size);
@@ -203,8 +205,17 @@
if (qcgc_state.phase == GC_COLLECT) {
return; // Fast exit when there is nothing to mark
}
- // FIXME: Log some more information
- qcgc_event_logger_log(EVENT_MARK_START, 0, NULL);
+
+ {
+ struct log_info_s {
+ bool incremental;
+ size_t gray_stack_size;
+ };
+ struct log_info_s log_info = {incremental,
qcgc_state.gray_stack_size};
+ qcgc_event_logger_log(EVENT_MARK_START, sizeof(struct
log_info_s),
+ (uint8_t *) &log_info);
+ }
+
qcgc_state.bytes_since_incmark = 0;
if (qcgc_state.phase == GC_PAUSE) {
@@ -268,8 +279,15 @@
qcgc_state.phase = GC_COLLECT;
}
- // FIXME: Log some more information
- qcgc_event_logger_log(EVENT_MARK_DONE, 0, NULL);
+ {
+ struct log_info_s {
+ bool incremental;
+ size_t gray_stack_size;
+ };
+ struct log_info_s log_info = {incremental,
qcgc_state.gray_stack_size};
+ qcgc_event_logger_log(EVENT_MARK_DONE, sizeof(struct
log_info_s),
+ (uint8_t *) &log_info);
+ }
#if CHECKED
assert(incremental || (qcgc_state.phase = GC_COLLECT));
assert(qcgc_state.phase != GC_PAUSE);
@@ -339,13 +357,17 @@
#if CHECKED
assert(qcgc_state.phase == GC_COLLECT);
#endif
- unsigned long arena_count;
- arena_count = qcgc_allocator_state.arenas->count;
- qcgc_event_logger_log(EVENT_SWEEP_START, sizeof(arena_count),
- (uint8_t *) &arena_count);
+ {
+ unsigned long arena_count;
+ arena_count = qcgc_allocator_state.arenas->count;
+ qcgc_event_logger_log(EVENT_SWEEP_START, sizeof(arena_count),
+ (uint8_t *) &arena_count);
+ }
qcgc_hbtable_sweep();
size_t i = 0;
+ qcgc_state.free_cells = 0;
+ qcgc_state.largest_free_block = 0;
while (i < qcgc_allocator_state.arenas->count) {
arena_t *arena = qcgc_allocator_state.arenas->items[i];
// The arena that contains the bump pointer is autmatically
skipped
@@ -355,7 +377,6 @@
qcgc_allocator_state.arenas, i);
qcgc_allocator_state.free_arenas = qcgc_arena_bag_add(
qcgc_allocator_state.free_arenas,
arena);
-
// NO i++
} else {
// Not free
@@ -364,8 +385,26 @@
}
qcgc_state.phase = GC_PAUSE;
- qcgc_event_logger_log(EVENT_SWEEP_DONE, 0, NULL);
+ // Determine whether fragmentation is too high
+ // Fragmenation = 1 - (largest block / total free space)
+ // Use bump allocator when fragmentation < 50%
+ qcgc_allocator_state.use_bump_allocator = qcgc_state.free_cells <
+ 2 * qcgc_state.largest_free_block;
+
update_weakrefs();
+
+ {
+ struct log_info_s {
+ size_t free_cells;
+ size_t largest_free_block;
+ };
+ struct log_info_s log_info = {
+ qcgc_state.free_cells,
+ qcgc_state.largest_free_block
+ };
+ qcgc_event_logger_log(EVENT_SWEEP_DONE, sizeof(struct
log_info_s),
+ (uint8_t *) &log_info);
+ }
}
void qcgc_collect(void) {
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit