diff options
author | Daniel Gröber <dxld@darkboxed.org> | 2019-07-16 17:31:35 +0200 |
---|---|---|
committer | Daniel Gröber <dxld@darkboxed.org> | 2019-09-22 15:34:24 +0200 |
commit | 9b2a412063ef853d704c01a091aa7030c52a42fc (patch) | |
tree | 3a83df426d53419a5da29094e7d9e99cbdfa3199 | |
parent | 9aebc44fe590f22cbc336c3c328802e592334f94 (diff) | |
download | haskell-9b2a412063ef853d704c01a091aa7030c52a42fc.tar.gz |
rts: TraverseHeap: Add a basic test
For now this just tests that the order of the callbacks is what we expect
for a given heap graph.
-rw-r--r-- | rts/TraverseHeap.c | 2 | ||||
-rw-r--r-- | rts/TraverseHeap.h | 2 | ||||
-rw-r--r-- | rts/TraverseHeapTest.c | 225 | ||||
-rw-r--r-- | testsuite/tests/profiling/should_run/TraverseHeapTest.hs | 4 | ||||
-rw-r--r-- | testsuite/tests/profiling/should_run/TraverseHeapTest.stdout | 77 | ||||
-rw-r--r-- | testsuite/tests/profiling/should_run/all.T | 2 |
6 files changed, 312 insertions, 0 deletions
diff --git a/rts/TraverseHeap.c b/rts/TraverseHeap.c index 882d1095c3..8938da2462 100644 --- a/rts/TraverseHeap.c +++ b/rts/TraverseHeap.c @@ -16,6 +16,8 @@ #include "TraverseHeap.h" +const stackData nullStackData; + StgWord getTravData(const StgClosure *c) { const StgWord hp_hdr = c->header.prof.hp.trav; diff --git a/rts/TraverseHeap.h b/rts/TraverseHeap.h index bf7fa4489c..7ac02440ed 100644 --- a/rts/TraverseHeap.h +++ b/rts/TraverseHeap.h @@ -69,6 +69,8 @@ typedef union stackData_ { retainer c_child_r; } stackData; +extern const stackData nullStackData; + typedef union stackAccum_ { StgWord subtree_sizeW; } stackAccum; diff --git a/rts/TraverseHeapTest.c b/rts/TraverseHeapTest.c new file mode 100644 index 0000000000..8998be6766 --- /dev/null +++ b/rts/TraverseHeapTest.c @@ -0,0 +1,225 @@ + +#if defined(PROFILING) && defined(DEBUG) + +#include "PosixSource.h" +#include <string.h> +#include <Rts.h> +#include <rts/storage/Closures.h> +#include "TraverseHeap.h" + +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +static StgInfoTable info_weak = { .type = WEAK }; +static StgInfoTable info_selector = { .type = THUNK_SELECTOR }; +static StgInfoTable info_arrwords = { .type = ARR_WORDS }; + +struct node { + unsigned int id; + union node_union { + StgClosure cls; + StgWeak weak; + StgSelector selector; + StgArrBytes arrbytes; + } u; +}; + +// See INFO_PTR_TO_STRUCT in ClosureMacros.h +#if defined(TABLES_NEXT_TO_CODE) +#define INFO(ptr) ((StgInfoTable *)ptr + 1) +#else +#define INFO(ptr) ((StgInfoTable *)ptr) +#endif + +#define node3(_id, a,b,c) \ + static struct node n##_id = { \ + .id = _id, \ + .u.weak = { \ + .header = { .info = INFO(&info_weak) }, \ + .key = (StgClosure*)&(n##a.u), \ + .value = (StgClosure*)&(n##b.u), \ + .finalizer = (StgClosure*)&(n##c.u), \ + } \ + }; + +#define node1(_id, a) \ + static struct node n##_id = { \ + .id = _id, \ + .u.selector = { \ + .header = { .info = INFO(&info_selector) }, \ + .selectee = (StgClosure*)&(n##a.u), \ + } \ + } + +#define node0(_id) \ + static struct node n##_id = { \ + .id = _id, \ + .u.arrbytes = { \ + .header = { .info = INFO(&info_arrwords) }, \ + } \ + } + + +/* + 1.0) Just a simple case to start with. + + 1 + / + 0---2 + \ + 3 +*/ +node0(1003); +node0(1002); +node0(1001); +node3(1000, + 1001, + 1002, + 1003); + +/* + 1.1) Now with a cycle + + 1 + /` \, + 0--->2 + \, + 3 +*/ +node0(1103); +node0(1102); +node1(1101, + 1102); +node3(1100, + 1101, + 1102, + 1103); + +/* + 2.0) This tests the chain optimization. + + 1 6 + / / + 0-2-4-5-7 + \ \ + 3 8 +*/ + +node0(2006); +node0(2007); +node0(2008); + +node3(2005, + 2006, + 2007, + 2008); + +node1(2004, + 2005); + +node0(2003); +node1(2002, + 2004); +node0(2001); + +node3(2000, + 2001, + 2002, + 2003); + + +static void +testReturn(StgClosure *c, const stackAccum acc, + StgClosure *c_parent, stackAccum *acc_parent) +{ + (void) acc; + (void) c_parent; + (void) acc_parent; + + struct node *n = container_of(c, struct node, u.cls); + + printf("return %u\n", n->id); + + return; +} + +static bool +testVisit(StgClosure *c, const StgClosure *cp, + const stackData data, const bool first_visit, + stackAccum *acc, stackData *child_data) +{ + (void) cp; + (void) data; + (void) acc; + (void) child_data; + + struct node *n = container_of(c, struct node, u.cls); + + printf("visit %u\n", n->id); + + return first_visit; +} + +static traverseState g_with_return = { + .return_cb = &testReturn, +}; + +static traverseState g_just_visit; + +static struct node* const g_tests[] = { + &n1000, &n1100, + &n2000, +}; + +void traverseHeapRunTests(void); +void traverseHeapRunTests(void) +{ + + + { + printf("with return\n"); + + traverseState *ts = &g_with_return; + + initializeTraverseStack(ts); + + for(size_t i=0; i < (sizeof(g_tests)/sizeof(*g_tests)); i++) { + struct node *n = g_tests[i]; + + stackElement se; + memset(&se, 0, sizeof(se)); + + printf("\n\npush %u\n", n->id); + traversePushClosure(ts, &n->u.cls, &n->u.cls, &se, nullStackData); + traverseWorkStack(ts, &testVisit); + } + + closeTraverseStack(ts); + } + + { + printf("\n\n\n\njust visit\n"); + + traverseState *ts = &g_just_visit; + traverseInvalidateClosureData(ts); + + initializeTraverseStack(ts); + + for(size_t i=0; i < (sizeof(g_tests)/sizeof(*g_tests)); i++) { + struct node *n = g_tests[i]; + + stackElement se; + memset(&se, 0, sizeof(se)); + + printf("\n\npush %u\n", n->id); + traversePushClosure(ts, &n->u.cls, &n->u.cls, &se, nullStackData); + traverseWorkStack(ts, &testVisit); + } + + closeTraverseStack(ts); + + } +} + +#endif diff --git a/testsuite/tests/profiling/should_run/TraverseHeapTest.hs b/testsuite/tests/profiling/should_run/TraverseHeapTest.hs new file mode 100644 index 0000000000..889c0c0bfc --- /dev/null +++ b/testsuite/tests/profiling/should_run/TraverseHeapTest.hs @@ -0,0 +1,4 @@ +foreign import ccall unsafe "traverseHeapRunTests" c_traverseHeapRunTests + :: IO () + +main = c_traverseHeapRunTests diff --git a/testsuite/tests/profiling/should_run/TraverseHeapTest.stdout b/testsuite/tests/profiling/should_run/TraverseHeapTest.stdout new file mode 100644 index 0000000000..bd86ac8a1d --- /dev/null +++ b/testsuite/tests/profiling/should_run/TraverseHeapTest.stdout @@ -0,0 +1,77 @@ +with return + + +push 1000 +visit 1000 +visit 1001 +return 1001 +visit 1002 +return 1002 +visit 1003 +return 1003 +return 1000 + + +push 1100 +visit 1100 +visit 1101 +visit 1102 +return 1102 +return 1101 +visit 1102 +visit 1103 +return 1103 +return 1100 + + +push 2000 +visit 2000 +visit 2001 +return 2001 +visit 2002 +visit 2004 +visit 2005 +visit 2006 +return 2006 +visit 2007 +return 2007 +visit 2008 +return 2008 +return 2005 +return 2004 +return 2002 +visit 2003 +return 2003 +return 2000 + + + + +just visit + + +push 1000 +visit 1000 +visit 1001 +visit 1002 +visit 1003 + + +push 1100 +visit 1100 +visit 1101 +visit 1102 +visit 1102 +visit 1103 + + +push 2000 +visit 2000 +visit 2001 +visit 2002 +visit 2004 +visit 2005 +visit 2006 +visit 2007 +visit 2008 +visit 2003 diff --git a/testsuite/tests/profiling/should_run/all.T b/testsuite/tests/profiling/should_run/all.T index a56223d848..2d56e37b80 100644 --- a/testsuite/tests/profiling/should_run/all.T +++ b/testsuite/tests/profiling/should_run/all.T @@ -150,3 +150,5 @@ test('T15897', run_timeout_multiplier(2), fragile(15467)], makefile_test, ['T15897']) + +test('TraverseHeapTest', [only_ways(['prof'])], compile_and_run, ['-debug']) |