From fcf9a6d933c7045fdd0dd3408797d35b2dfc1d97 Mon Sep 17 00:00:00 2001 From: erg <devnull@localhost> Date: Thu, 25 Feb 2010 18:00:31 +0000 Subject: [PATCH] Fix connected component calculation to use explicit stack rather than recursion in order to handle big graphs. We already have a fair amount of bug reports where recursion has blown the stack. --- lib/pack/ccomps.c | 125 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 121 insertions(+), 4 deletions(-) diff --git a/lib/pack/ccomps.c b/lib/pack/ccomps.c index 8f9da00f6..197bd4906 100644 --- a/lib/pack/ccomps.c +++ b/lib/pack/ccomps.c @@ -21,10 +21,12 @@ #define MARKED(n) ND_mark(n) #define MARK(n) (ND_mark(n) = 1) +#define ONSTACK(n) (ND_mark(n) = 1) #define UNMARK(n) (ND_mark(n) = 0) typedef void (*dfsfn) (Agnode_t *, void *); +#if 0 static void dfs(Agraph_t * g, Agnode_t * n, dfsfn action, void *state) { Agedge_t *e; @@ -39,6 +41,106 @@ static void dfs(Agraph_t * g, Agnode_t * n, dfsfn action, void *state) dfs(g, other, action, state); } } +#endif + +typedef struct blk_t { + Agnode_t **data; + Agnode_t **endp; + struct blk_t *prev; + struct blk_t *next; +} blk_t; + +typedef struct { + blk_t *fstblk; + blk_t *curblk; + Agnode_t **curp; +} stk_t; + +#define INITBUF 1024 +#define BIGBUF 1000000 + +static void initStk(stk_t* sp, blk_t* bp, Agnode_t** base) +{ + bp->data = base; + bp->endp = bp->data + INITBUF; + bp->prev = bp->next = NULL; + sp->curblk = sp->fstblk = bp; + sp->curp = sp->curblk->data; +} + +static void freeBlk (blk_t* bp) +{ + free (bp->data); + free (bp); +} + +static void freeStk (stk_t* sp) +{ + blk_t* bp; + blk_t* nxtbp; + + for (bp = sp->fstblk->next; bp; bp = nxtbp) { + nxtbp = bp->next; + freeBlk (bp); + } +} + +static void push(stk_t* sp, Agnode_t * np) +{ + if (sp->curp == sp->curblk->endp) { + if (sp->curblk->next == NULL) { + blk_t *bp = GNEW(blk_t); + if (bp == 0) { + fprintf(stderr, "gc: Out of memory\n"); + exit(1); + } + bp->prev = sp->curblk; + bp->next = NULL; + bp->data = N_GNEW(BIGBUF, Agnode_t *); + if (bp->data == 0) { + fprintf(stderr, "gc: Out of memory\n"); + exit(1); + } + bp->endp = bp->data + BIGBUF; + sp->curblk->next = bp; + } + sp->curblk = sp->curblk->next; + sp->curp = sp->curblk->data; + } + ONSTACK(np); + *sp->curp++ = np; +} + +static Agnode_t *pop(stk_t* sp) +{ + if (sp->curp == sp->curblk->data) { + if (sp->curblk == sp->fstblk) + return 0; + sp->curblk = sp->curblk->prev; + sp->curp = sp->curblk->endp; + } + sp->curp--; + return *sp->curp; +} + + +static void dfs(Agraph_t * g, Agnode_t * n, dfsfn action, void *state, stk_t* stk) +{ + Agedge_t *e; + Agnode_t *other; + + push (stk, n); + while ((n = pop(stk))) { + MARK(n); + action(n, state); + for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) { + if ((other = agtail(e)) == n) + other = aghead(e); + if (!MARKED(other)) + push(stk, other); + } + } +} static int isLegal(char *p) { @@ -85,6 +187,9 @@ Agraph_t **pccomps(Agraph_t * g, int *ncc, char *pfx, boolean * pinned) int len; int bnd = 10; boolean pin = FALSE; + stk_t stk; + blk_t blk; + Agnode_t* base[INITBUF]; if (agnnodes(g) == 0) { *ncc = 0; @@ -105,6 +210,7 @@ Agraph_t **pccomps(Agraph_t * g, int *ncc, char *pfx, boolean * pinned) ccs = N_GNEW(bnd, Agraph_t *); + initStk (&stk, &blk, base); /* Component with pinned nodes */ for (n = agfstnode(g); n; n = agnxtnode(g, n)) { if (MARKED(n) || !isPinned(n)) @@ -121,7 +227,7 @@ Agraph_t **pccomps(Agraph_t * g, int *ncc, char *pfx, boolean * pinned) c_cnt++; pin = TRUE; } - dfs(g, n, insertFn, out); + dfs (g, n, insertFn, out, &stk); } /* Remaining nodes */ @@ -135,7 +241,7 @@ Agraph_t **pccomps(Agraph_t * g, int *ncc, char *pfx, boolean * pinned) out = agsubg(g, name,1); agbindrec(out, "Agraphinfo_t", sizeof(Agraphinfo_t), TRUE); //node custom data #endif /* WITH_CGRAPH */ - dfs(g, n, insertFn, out); + dfs(g, n, insertFn, out, &stk); if (c_cnt == bnd) { bnd *= 2; ccs = RALLOC(bnd, ccs, Agraph_t *); @@ -143,6 +249,7 @@ Agraph_t **pccomps(Agraph_t * g, int *ncc, char *pfx, boolean * pinned) ccs[c_cnt] = out; c_cnt++; } + freeStk (&stk); ccs = RALLOC(c_cnt, ccs, Agraph_t *); if (name != buffer) @@ -170,6 +277,9 @@ Agraph_t **ccomps(Agraph_t * g, int *ncc, char *pfx) Agraph_t **ccs; int len; int bnd = 10; + stk_t stk; + blk_t blk; + Agnode_t* base[INITBUF]; if (agnnodes(g) == 0) { *ncc = 0; @@ -189,6 +299,7 @@ Agraph_t **ccomps(Agraph_t * g, int *ncc, char *pfx) UNMARK(n); ccs = N_GNEW(bnd, Agraph_t *); + initStk (&stk, &blk, base); for (n = agfstnode(g); n; n = agnxtnode(g, n)) { if (MARKED(n)) continue; @@ -199,7 +310,7 @@ Agraph_t **ccomps(Agraph_t * g, int *ncc, char *pfx) out = agsubg(g, name,1); agbindrec(out, "Agraphinfo_t", sizeof(Agraphinfo_t), TRUE); //node custom data #endif /* WITH_CGRAPH */ - dfs(g, n, insertFn, out); + dfs(g, n, insertFn, out, &stk); if (c_cnt == bnd) { bnd *= 2; ccs = RALLOC(bnd, ccs, Agraph_t *); @@ -207,6 +318,7 @@ Agraph_t **ccomps(Agraph_t * g, int *ncc, char *pfx) ccs[c_cnt] = out; c_cnt++; } + freeStk (&stk); ccs = RALLOC(c_cnt, ccs, Agraph_t *); if (name != buffer) free(name); @@ -229,15 +341,20 @@ int isConnected(Agraph_t * g) Agnode_t *n; int ret = 1; int cnt = 0; + stk_t stk; + blk_t blk; + Agnode_t* base[INITBUF]; for (n = agfstnode(g); n; n = agnxtnode(g, n)) UNMARK(n); n = agfstnode(g); if (n) { - dfs(g, n, cntFn, &cnt); + initStk (&stk, &blk, base); + dfs(g, n, cntFn, &cnt, &stk); if (cnt != agnnodes(g)) ret = 0; + freeStk (&stk); } return ret; } -- 2.40.0