Commit 20237a73 authored by Jonathan Jenkins's avatar Jonathan Jenkins

simple GVT-aware stack with garbage collection

NOTE: very inefficient
parent 86ecd422
/*
* Copyright (C) 2014 University of Chicago.
* See COPYRIGHT notice in top-level directory.
*
*/
#ifndef RC_STACK_H
#define RC_STACK_H
#include <ross.h>
/* A simple stack data structure that is GVT-aware for cleanup purposes. It's
* meant to use as an alternative to event-stuffing for allocating data that
* would be too large to put into the event.
*
* It's currently overly simple and will not perform well for workloads that
* hit the RC stack often. Just currently meant to act as a simple placeholder
* until we have time to do a high-performance implementation.
*
* TODO:
* - use dedicated memory (pass out mem for data, use singly-linked-list of
* large-ish chunks to prevent lots of malloc/free calls)
* - provide better options for invoking garbage collection (enter collection
* loop if more than N entries present, every X events, etc.). Don't want to
* enter the loop every event or modify the list every time gvt changes.
*/
struct rc_stack;
void rc_stack_create(struct rc_stack **s);
/* setting free_data to non-zero will free the data associated with each entry
*/
void rc_stack_destroy(int free_data, struct rc_stack *s);
/* push data to the stack with time given by tw_now(lp) */
void rc_stack_push(
tw_lp *lp,
void *data,
struct rc_stack *s);
/* pop data from the stack for rc (tw_error if stack empty) */
void * rc_stack_pop(struct rc_stack *s);
/* get the number of entries on the stack (mostly for debug) */
int rc_stack_count(struct rc_stack *s);
/* remove entries from the stack with generation time < GVT (lp->pe->GVT)
*
* setting free_data to non-zero will free the associated data */
void rc_stack_gc(
tw_lp *lp,
int free_data,
struct rc_stack *s);
#endif /* end of include guard: RC-STACK_H */
/*
* Local variables:
* c-indent-level: 4
* c-basic-offset: 4
* End:
*
* vim: ts=8 sts=4 sw=4 expandtab
*/
......@@ -68,7 +68,8 @@ nobase_include_HEADERS = \
codes/codes-workload.h \
codes/resource.h \
codes/resource-lp.h \
codes/local-storage-model.h
codes/local-storage-model.h \
codes/rc-stack.h
src_libcodes_base_a_SOURCES = \
codes/codesparser.h \
......@@ -119,7 +120,9 @@ src_libcodes_base_a_SOURCES = \
codes/codes-nw-workload.h \
src/network-workload/codes-nw-workload.c \
src/network-workload/codes-nw-workload-method.h \
src/network-workload/codes-scala-trace-nw-wrkld.c
src/network-workload/codes-scala-trace-nw-wrkld.c \
codes/rc-stack.h \
src/util/rc-stack.c
# stealth testing of the template code (actual test is not run, just compiled as
# a program - Make error signifies test failure)
......
/*
* Copyright (C) 2014 University of Chicago.
* See COPYRIGHT notice in top-level directory.
*
*/
#include <assert.h>
#include <ross.h>
#include "codes/rc-stack.h"
#include "codes/quicklist.h"
typedef struct rc_entry_s {
tw_stime time;
void * data;
struct qlist_head ql;
} rc_entry;
struct rc_stack {
int count;
struct qlist_head head;
};
void rc_stack_create(struct rc_stack **s){
struct rc_stack *ss = malloc(sizeof(*ss));
if (ss) {
INIT_QLIST_HEAD(&ss->head);
ss->count = 0;
}
*s = ss;
}
void rc_stack_destroy(int free_data, struct rc_stack *s) {
#define FREE_ENTRY(_e, _free_data)\
do { \
if (_e != NULL){\
rc_entry *r = qlist_entry(_e, rc_entry, ql);\
if (_free_data) free(r->data);\
free(r);\
} \
} while(0)
struct qlist_head *ent, *ent_prev = NULL;
qlist_for_each(ent, &s->head) {
FREE_ENTRY(ent_prev, free_data);
ent_prev = ent;
}
FREE_ENTRY(ent_prev, free_data);
free(s);
#undef FREE_ENTRY
}
void rc_stack_push(
tw_lp *lp,
void * data,
struct rc_stack *s){
rc_entry * ent = malloc(sizeof(*ent));
assert(ent);
ent->time = tw_now(lp);
ent->data = data;
qlist_add_tail(&ent->ql, &s->head);
s->count++;
}
void* rc_stack_pop(struct rc_stack *s){
struct qlist_head *item = qlist_pop_back(&s->head);
if (item == NULL)
tw_error(TW_LOC,
"could not pop item from rc stack (stack likely empty)\n");
s->count--;
return qlist_entry(item, rc_entry, ql)->data;
}
int rc_stack_count(struct rc_stack *s) { return s->count; }
void rc_stack_gc(tw_lp *lp, int free_data, struct rc_stack *s) {
struct qlist_head *ent = s->head.next;
while (ent != &s->head) {
rc_entry *r = qlist_entry(ent, rc_entry, ql);
if (r->time < lp->pe->GVT){
qlist_del(ent);
if (free_data) free(r->data);
free(r);
s->count--;
ent = s->head.next;
}
else
break;
}
}
/*
* Local variables:
* c-indent-level: 4
* c-basic-offset: 4
* End:
*
* vim: ts=8 sts=4 sw=4 expandtab
*/
......@@ -4,12 +4,14 @@ check_PROGRAMS += tests/lp-io-test \
tests/workload/codes-workload-mpi-replay \
tests/mapping_test \
tests/lsm-test \
tests/resource-test
tests/resource-test \
tests/rc-stack-test
TESTS += tests/lp-io-test.sh \
tests/workload/codes-workload-test.sh \
tests/mapping_test.sh \
tests/lsm-test.sh
tests/lsm-test.sh \
tests/rc-stack-test
EXTRA_DIST += tests/lp-io-test.sh \
tests/workload/codes-workload-test.sh \
......@@ -40,6 +42,10 @@ tests_lsm_test_LDADD = $(testlib) ${ROSS_LIBS}
tests_lsm_test_LDFLAGS = ${ROSS_LDFLAGS}
tests_lsm_test_SOURCES = tests/local-storage-model-test.c
tests_rc_stack_test_LDADD = $(testlib) ${ROSS_LIBS}
tests_rc_stack_test_LDFLAGS = ${ROSS_LDFLAGS}
tests_rc_stack_test_SOURCES = tests/rc-stack-test.c
tests_workload_codes_workload_test_LDADD = $(testlib) ${ROSS_LIBS}
tests_workload_codes_workload_test_LDFLAGS = ${ROSS_LDFLAGS}
tests_workload_codes_workload_test_SOURCES = \
......
/*
* Copyright (C) 2014 University of Chicago.
* See COPYRIGHT notice in top-level directory.
*
*/
#include <assert.h>
#include <ross.h>
#include "codes/rc-stack.h"
int main(int argc, char *argv[])
{
/* mock up a dummy lp for testing */
tw_lp lp;
tw_kp kp;
tw_pe pe;
memset(&lp, 0, sizeof(lp));
memset(&kp, 0, sizeof(kp));
memset(&pe, 0, sizeof(pe));
lp.pe = &pe;
lp.kp = &kp;
struct rc_stack *s;
rc_stack_create(&s);
assert(s != NULL);
int *a = malloc(sizeof(*a));
int *b = malloc(sizeof(*b));
int *c = malloc(sizeof(*c));
*a = 1;
*b = 2;
*c = 3;
#define PUSH_ALL() \
do { \
kp.last_time = 1.0; \
rc_stack_push(&lp, a, s); \
kp.last_time = 2.0; \
rc_stack_push(&lp, b, s); \
kp.last_time = 3.0; \
rc_stack_push(&lp, c, s); \
} while (0)
PUSH_ALL();
void *dat;
assert(3 == rc_stack_count(s));
dat = rc_stack_pop(s);
assert(c == dat);
dat = rc_stack_pop(s);
assert(b == dat);
dat = rc_stack_pop(s);
assert(a == dat);
assert(0 == rc_stack_count(s));
PUSH_ALL();
/* garbage collect the first two (NOT freeing the pointers first) */
pe.GVT = 2.5;
rc_stack_gc(&lp, 0, s);
assert(1 == rc_stack_count(s));
dat = rc_stack_pop(s);
assert(c == dat);
assert(0 == rc_stack_count(s));
/* destroy everything */
PUSH_ALL();
rc_stack_destroy(1, s);
return 0;
}
/*
* Local variables:
* c-indent-level: 4
* c-basic-offset: 4
* End:
*
* vim: ts=8 sts=4 sw=4 expandtab
*/
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment