mirror of
https://github.com/justinethier/cyclone.git
synced 2025-05-23 20:15:05 +02:00
Inline gc_mark_globals
Force inlining to attempt to improve performance
This commit is contained in:
parent
5823b37b5d
commit
649e0eb5c8
3 changed files with 136 additions and 128 deletions
180
gc.c
180
gc.c
|
@ -1138,51 +1138,18 @@ void gc_mark_gray2(gc_thread_data * thd, object obj)
|
|||
}
|
||||
}
|
||||
|
||||
void gc_collector_trace()
|
||||
{
|
||||
ck_array_iterator_t iterator;
|
||||
gc_thread_data *m;
|
||||
int clean = 0;
|
||||
while (!clean) {
|
||||
clean = 1;
|
||||
|
||||
CK_ARRAY_FOREACH(&Cyc_mutators, &iterator, &m) {
|
||||
// TODO: ideally, want to use a lock-free data structure to prevent
|
||||
// having to use a mutex here. see corresponding code in gc_mark_gray
|
||||
pthread_mutex_lock(&(m->lock));
|
||||
while (m->last_read < m->last_write) {
|
||||
clean = 0;
|
||||
#if GC_DEBUG_VERBOSE
|
||||
fprintf(stderr,
|
||||
"gc_mark_black mark buffer %p, last_read = %d last_write = %d\n",
|
||||
(m->mark_buffer)[m->last_read], m->last_read, m->last_write);
|
||||
#endif
|
||||
gc_mark_black((m->mark_buffer)[m->last_read]);
|
||||
gc_empty_collector_stack();
|
||||
(m->last_read)++; // Inc here to prevent off-by-one error
|
||||
}
|
||||
pthread_mutex_unlock(&(m->lock));
|
||||
|
||||
// Try checking the condition once more after giving the
|
||||
// mutator a chance to respond, to prevent exiting early.
|
||||
// This is experimental, not sure if it is necessary
|
||||
if (clean) {
|
||||
pthread_mutex_lock(&(m->lock));
|
||||
if (m->last_read < m->last_write) {
|
||||
#if GC_SAFETY_CHECKS
|
||||
fprintf(stderr,
|
||||
"gc_collector_trace - might have exited trace early\n");
|
||||
#endif
|
||||
clean = 0;
|
||||
} else if (m->pending_writes) {
|
||||
clean = 0;
|
||||
}
|
||||
pthread_mutex_unlock(&(m->lock));
|
||||
}
|
||||
}
|
||||
// "Color" objects gray by adding them to the mark stack for further processing.
|
||||
//
|
||||
// Note that stack objects are always colored red during creation, so
|
||||
// they should never be added to the mark stack. Which would be bad because it
|
||||
// could lead to stack corruption.
|
||||
//
|
||||
// Attempt to speed this up by forcing an inline
|
||||
//
|
||||
#define gc_collector_mark_gray(parent, gobj) \
|
||||
if (is_object_type(gobj) && mark(gobj) == gc_color_clear) { \
|
||||
mark_stack = vpbuffer_add(mark_stack, &mark_stack_len, mark_stack_i++, gobj); \
|
||||
}
|
||||
}
|
||||
|
||||
//static void gc_collector_mark_gray(object parent, object obj)
|
||||
//{
|
||||
// if (is_object_type(obj) && mark(obj) == gc_color_clear) {
|
||||
|
@ -1194,6 +1161,50 @@ void gc_collector_trace()
|
|||
// }
|
||||
//}
|
||||
|
||||
#define gc_mark_black(obj) \
|
||||
{ \
|
||||
int markColor = ck_pr_load_int(&gc_color_mark); \
|
||||
if (is_object_type(obj) && mark(obj) != markColor) { \
|
||||
switch (type_of(obj)) { \
|
||||
case pair_tag:{ \
|
||||
gc_collector_mark_gray(obj, car(obj)); \
|
||||
gc_collector_mark_gray(obj, cdr(obj)); \
|
||||
break; \
|
||||
} \
|
||||
case closure1_tag: \
|
||||
gc_collector_mark_gray(obj, ((closure1) obj)->element); \
|
||||
break; \
|
||||
case closureN_tag:{ \
|
||||
int i, n = ((closureN) obj)->num_elements; \
|
||||
for (i = 0; i < n; i++) { \
|
||||
gc_collector_mark_gray(obj, ((closureN) obj)->elements[i]); \
|
||||
} \
|
||||
break; \
|
||||
} \
|
||||
case vector_tag:{ \
|
||||
int i, n = ((vector) obj)->num_elements; \
|
||||
for (i = 0; i < n; i++) { \
|
||||
gc_collector_mark_gray(obj, ((vector) obj)->elements[i]); \
|
||||
} \
|
||||
break; \
|
||||
} \
|
||||
case cvar_tag:{ \
|
||||
cvar_type *c = (cvar_type *) obj; \
|
||||
object pvar = *(c->pvar); \
|
||||
if (pvar) { \
|
||||
gc_collector_mark_gray(obj, pvar); \
|
||||
} \
|
||||
break; \
|
||||
} \
|
||||
default: \
|
||||
break; \
|
||||
} \
|
||||
if (mark(obj) != gc_color_red) { \
|
||||
mark(obj) = markColor; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
/*
|
||||
void gc_mark_black(object obj)
|
||||
{
|
||||
|
@ -1254,8 +1265,55 @@ void gc_mark_black(object obj)
|
|||
}
|
||||
*/
|
||||
|
||||
|
||||
void gc_collector_trace()
|
||||
{
|
||||
ck_array_iterator_t iterator;
|
||||
gc_thread_data *m;
|
||||
int clean = 0;
|
||||
while (!clean) {
|
||||
clean = 1;
|
||||
|
||||
CK_ARRAY_FOREACH(&Cyc_mutators, &iterator, &m) {
|
||||
// TODO: ideally, want to use a lock-free data structure to prevent
|
||||
// having to use a mutex here. see corresponding code in gc_mark_gray
|
||||
pthread_mutex_lock(&(m->lock));
|
||||
while (m->last_read < m->last_write) {
|
||||
clean = 0;
|
||||
#if GC_DEBUG_VERBOSE
|
||||
fprintf(stderr,
|
||||
"gc_mark_black mark buffer %p, last_read = %d last_write = %d\n",
|
||||
(m->mark_buffer)[m->last_read], m->last_read, m->last_write);
|
||||
#endif
|
||||
gc_mark_black((m->mark_buffer)[m->last_read]);
|
||||
gc_empty_collector_stack();
|
||||
(m->last_read)++; // Inc here to prevent off-by-one error
|
||||
}
|
||||
pthread_mutex_unlock(&(m->lock));
|
||||
|
||||
// Try checking the condition once more after giving the
|
||||
// mutator a chance to respond, to prevent exiting early.
|
||||
// This is experimental, not sure if it is necessary
|
||||
if (clean) {
|
||||
pthread_mutex_lock(&(m->lock));
|
||||
if (m->last_read < m->last_write) {
|
||||
#if GC_SAFETY_CHECKS
|
||||
fprintf(stderr,
|
||||
"gc_collector_trace - might have exited trace early\n");
|
||||
#endif
|
||||
clean = 0;
|
||||
} else if (m->pending_writes) {
|
||||
clean = 0;
|
||||
}
|
||||
pthread_mutex_unlock(&(m->lock));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gc_empty_collector_stack()
|
||||
{
|
||||
object obj;
|
||||
// Mark stack is only used by the collector thread, so no sync needed
|
||||
while (mark_stack_i > 0) { // not empty
|
||||
mark_stack_i--;
|
||||
|
@ -1263,7 +1321,8 @@ void gc_empty_collector_stack()
|
|||
// fprintf(stderr, "gc_mark_black mark stack %p \n",
|
||||
// mark_stack[mark_stack_i]);
|
||||
//#endif
|
||||
gc_mark_black(mark_stack[mark_stack_i]);
|
||||
obj = mark_stack[mark_stack_i];
|
||||
gc_mark_black(obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1398,9 +1457,7 @@ void gc_collector()
|
|||
#if GC_DEBUG_TRACE
|
||||
fprintf(stderr, "DEBUG - after post_handshake async\n");
|
||||
#endif
|
||||
|
||||
TODO: call into shim in runtime, that will call back into gc_mark_globals in this module, but with global objs as parameters. this should allow us to explicitly inline all instances of gc_mark_black since they would now be in this module. and of course, none of the changes on this branch matter if they don't actually speed anything up, so need to measure that once it compiles!
|
||||
gc_mark_globals();
|
||||
gc_request_mark_globals();
|
||||
gc_wait_handshake();
|
||||
#if GC_DEBUG_TRACE
|
||||
fprintf(stderr, "DEBUG - after wait_handshake async\n");
|
||||
|
@ -1499,6 +1556,33 @@ void gc_start_collector()
|
|||
}
|
||||
}
|
||||
|
||||
// Mark globals as part of the tracing collector
|
||||
// This is called by the collector thread
|
||||
void gc_mark_globals(object globals, object global_table)
|
||||
{
|
||||
#if GC_DEBUG_TRACE
|
||||
//fprintf(stderr, "(gc_mark_globals heap: %p size: %d)\n", h, (unsigned int)gc_heap_total_size(h));
|
||||
fprintf(stderr, "Cyc_global_variables %p\n", globals);
|
||||
#endif
|
||||
// Mark global variables
|
||||
gc_mark_black(globals); // Internal global used by the runtime
|
||||
// Marking it ensures all glos are marked
|
||||
{
|
||||
list l = global_table;
|
||||
for (; l != NULL; l = cdr(l)) {
|
||||
cvar_type *c = (cvar_type *) car(l);
|
||||
object glo = *(c->pvar);
|
||||
if (glo != NULL) {
|
||||
#if GC_DEBUG_VERBOSE
|
||||
fprintf(stderr, "global pvar %p\n", glo);
|
||||
#endif
|
||||
gc_mark_black(glo); // Mark actual object the global points to
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// END tri-color marking section
|
||||
/////////////////////////////////////////////
|
||||
|
|
|
@ -670,7 +670,8 @@ size_t gc_heap_total_size(gc_heap * h);
|
|||
//size_t gc_heap_total_free_size(gc_heap *h);
|
||||
//size_t gc_collect(gc_heap *h, size_t *sum_freed);
|
||||
//void gc_mark(gc_heap *h, object obj);
|
||||
void gc_mark_globals(void);
|
||||
void gc_request_mark_globals(void);
|
||||
void gc_mark_globals(object globals, object global_table);
|
||||
size_t gc_sweep(gc_heap * h, int heap_type, size_t * sum_freed_ptr);
|
||||
void gc_thr_grow_move_buffer(gc_thread_data * d);
|
||||
void gc_thr_add_to_move_buffer(gc_thread_data * d, int *alloci, object obj);
|
||||
|
@ -708,61 +709,5 @@ int gc_minor(void *data, object low_limit, object high_limit, closure cont,
|
|||
void add_mutation(void *data, object var, int index, object value);
|
||||
void clear_mutations(void *data);
|
||||
|
||||
// "Color" objects gray by adding them to the mark stack for further processing.
|
||||
//
|
||||
// Note that stack objects are always colored red during creation, so
|
||||
// they should never be added to the mark stack. Which would be bad because it
|
||||
// could lead to stack corruption.
|
||||
//
|
||||
// Attempt to speed this up by forcing an inline
|
||||
//
|
||||
#define gc_collector_mark_gray(parent, gobj) \
|
||||
if (is_object_type(gobj) && mark(gobj) == gc_color_clear) { \
|
||||
mark_stack = vpbuffer_add(mark_stack, &mark_stack_len, mark_stack_i++, gobj); \
|
||||
}
|
||||
|
||||
#define gc_mark_black(obj) \
|
||||
{ \
|
||||
int markColor = ck_pr_load_int(&gc_color_mark); \
|
||||
if (is_object_type(obj) && mark(obj) != markColor) { \
|
||||
switch (type_of(obj)) { \
|
||||
case pair_tag:{ \
|
||||
gc_collector_mark_gray(obj, car(obj)); \
|
||||
gc_collector_mark_gray(obj, cdr(obj)); \
|
||||
break; \
|
||||
} \
|
||||
case closure1_tag: \
|
||||
gc_collector_mark_gray(obj, ((closure1) obj)->element); \
|
||||
break; \
|
||||
case closureN_tag:{ \
|
||||
int i, n = ((closureN) obj)->num_elements; \
|
||||
for (i = 0; i < n; i++) { \
|
||||
gc_collector_mark_gray(obj, ((closureN) obj)->elements[i]); \
|
||||
} \
|
||||
break; \
|
||||
} \
|
||||
case vector_tag:{ \
|
||||
int i, n = ((vector) obj)->num_elements; \
|
||||
for (i = 0; i < n; i++) { \
|
||||
gc_collector_mark_gray(obj, ((vector) obj)->elements[i]); \
|
||||
} \
|
||||
break; \
|
||||
} \
|
||||
case cvar_tag:{ \
|
||||
cvar_type *c = (cvar_type *) obj; \
|
||||
object pvar = *(c->pvar); \
|
||||
if (pvar) { \
|
||||
gc_collector_mark_gray(obj, pvar); \
|
||||
} \
|
||||
break; \
|
||||
} \
|
||||
default: \
|
||||
break; \
|
||||
} \
|
||||
if (mark(obj) != gc_color_red) { \
|
||||
mark(obj) = markColor; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif /* CYCLONE_TYPES_H */
|
||||
|
|
25
runtime.c
25
runtime.c
|
@ -3995,30 +3995,9 @@ void Cyc_start_trampoline(gc_thread_data * thd)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
// Mark globals as part of the tracing collector
|
||||
// This is called by the collector thread
|
||||
void gc_mark_globals()
|
||||
void gc_request_mark_globals()
|
||||
{
|
||||
#if GC_DEBUG_TRACE
|
||||
//fprintf(stderr, "(gc_mark_globals heap: %p size: %d)\n", h, (unsigned int)gc_heap_total_size(h));
|
||||
fprintf(stderr, "Cyc_global_variables %p\n", Cyc_global_variables);
|
||||
#endif
|
||||
// Mark global variables
|
||||
gc_mark_black(Cyc_global_variables); // Internal global used by the runtime
|
||||
// Marking it ensures all glos are marked
|
||||
{
|
||||
list l = global_table;
|
||||
for (; l != NULL; l = cdr(l)) {
|
||||
cvar_type *c = (cvar_type *) car(l);
|
||||
object glo = *(c->pvar);
|
||||
if (glo != NULL) {
|
||||
#if GC_DEBUG_VERBOSE
|
||||
fprintf(stderr, "global pvar %p\n", glo);
|
||||
#endif
|
||||
gc_mark_black(glo); // Mark actual object the global points to
|
||||
}
|
||||
}
|
||||
}
|
||||
gc_mark_globals(Cyc_global_variables, global_table);
|
||||
}
|
||||
|
||||
char *gc_fixup_moved_obj(gc_thread_data * thd, int *alloci, char *obj,
|
||||
|
|
Loading…
Add table
Reference in a new issue