|
| 1 | +#include "bfs.h" |
| 2 | + |
| 3 | +#include "stinger_core/x86_full_empty.h" |
| 4 | + |
| 5 | +int64_t |
| 6 | +parallel_breadth_first_search (struct stinger * S, int64_t nv, |
| 7 | + int64_t source, int64_t * marks, |
| 8 | + int64_t * queue, int64_t * Qhead, int64_t * level) |
| 9 | +{ |
| 10 | + for (int64_t i = 0; i < nv; i++) { |
| 11 | + level[i] = -1; |
| 12 | + marks[i] = 0; |
| 13 | + } |
| 14 | + |
| 15 | + int64_t nQ, Qnext, Qstart, Qend; |
| 16 | + /* initialize */ |
| 17 | + queue[0] = source; |
| 18 | + level[source] = 0; |
| 19 | + marks[source] = 1; |
| 20 | + Qnext = 1; /* next open slot in the queue */ |
| 21 | + nQ = 1; /* level we are currently processing */ |
| 22 | + Qhead[0] = 0; /* beginning of the current frontier */ |
| 23 | + Qhead[1] = 1; /* end of the current frontier */ |
| 24 | + |
| 25 | + Qstart = Qhead[nQ-1]; |
| 26 | + Qend = Qhead[nQ]; |
| 27 | + |
| 28 | + while (Qstart != Qend) { |
| 29 | + OMP ("omp parallel for") |
| 30 | + for (int64_t j = Qstart; j < Qend; j++) { |
| 31 | + STINGER_FORALL_OUT_EDGES_OF_VTX_BEGIN (S, queue[j]) { |
| 32 | + int64_t d = level[STINGER_EDGE_DEST]; |
| 33 | + if (d < 0) { |
| 34 | + if (stinger_int64_fetch_add (&marks[STINGER_EDGE_DEST], 1) == 0) { |
| 35 | + level[STINGER_EDGE_DEST] = nQ; |
| 36 | + |
| 37 | + int64_t mine = stinger_int64_fetch_add(&Qnext, 1); |
| 38 | + queue[mine] = STINGER_EDGE_DEST; |
| 39 | + } |
| 40 | + } |
| 41 | + } STINGER_FORALL_OUT_EDGES_OF_VTX_END(); |
| 42 | + } |
| 43 | + |
| 44 | + Qstart = Qhead[nQ-1]; |
| 45 | + Qend = Qnext; |
| 46 | + Qhead[nQ++] = Qend; |
| 47 | + } |
| 48 | + |
| 49 | + return nQ; |
| 50 | +} |
| 51 | + |
| 52 | +int64_t |
| 53 | +direction_optimizing_parallel_breadth_first_search (struct stinger * S, int64_t nv, |
| 54 | + int64_t source, int64_t * marks, |
| 55 | + int64_t * queue, int64_t * Qhead, int64_t * level) |
| 56 | +{ |
| 57 | + for (int64_t i = 0; i < nv; i++) { |
| 58 | + level[i] = -1; |
| 59 | + marks[i] = 0; |
| 60 | + } |
| 61 | + |
| 62 | + int64_t nQ, Qnext, Qstart, Qend; |
| 63 | + int64_t mf = 0; /* number of edges incident on frontier */ |
| 64 | + int64_t nf = 0; /* number of vertices in frontier */ |
| 65 | + int64_t mu = 0; /* number of edges incident on unexplored vertices */ |
| 66 | + int64_t nf_last = 0; /* size of previous frontier */ |
| 67 | + |
| 68 | + /* initialize */ |
| 69 | + queue[0] = source; |
| 70 | + level[source] = 0; |
| 71 | + marks[source] = 1; |
| 72 | + Qnext = 1; /* next open slot in the queue */ |
| 73 | + nQ = 1; /* level we are currently processing */ |
| 74 | + Qhead[0] = 0; /* beginning of the current frontier */ |
| 75 | + Qhead[1] = 1; /* end of the current frontier */ |
| 76 | + |
| 77 | + Qstart = Qhead[nQ-1]; |
| 78 | + Qend = Qhead[nQ]; |
| 79 | + |
| 80 | + mf = 0; |
| 81 | + nf = 0; |
| 82 | + mu = stinger_total_edges(S); |
| 83 | + //printf("mf: %ld, nf: %ld, mu: %ld, nf_last: %ld\n", mf, nf, mu, nf_last); |
| 84 | + |
| 85 | + int64_t top_down = 1; |
| 86 | + |
| 87 | + while (Qstart != Qend) { |
| 88 | + if (top_down) { |
| 89 | + /* forward (top down) traversal */ |
| 90 | + OMP ("omp parallel for") |
| 91 | + for (int64_t j = Qstart; j < Qend; j++) { |
| 92 | + STINGER_FORALL_OUT_EDGES_OF_VTX_BEGIN (S, queue[j]) { |
| 93 | + int64_t d = level[STINGER_EDGE_DEST]; |
| 94 | + if (d < 0) { |
| 95 | + if (stinger_int64_fetch_add (&marks[STINGER_EDGE_DEST], 1) == 0) { |
| 96 | + level[STINGER_EDGE_DEST] = nQ; |
| 97 | + |
| 98 | + int64_t mine = stinger_int64_fetch_add(&Qnext, 1); |
| 99 | + queue[mine] = STINGER_EDGE_DEST; |
| 100 | + } |
| 101 | + } |
| 102 | + } STINGER_FORALL_OUT_EDGES_OF_VTX_END(); |
| 103 | + } |
| 104 | + } else { |
| 105 | + /* reverse (bottom up) traversal */ |
| 106 | + OMP ("omp parallel for") |
| 107 | + for (int64_t i = 0; i < nv; i++) { |
| 108 | + int64_t done = 0; |
| 109 | + /* only process unvisited vertices */ |
| 110 | + if (!marks[i]) { |
| 111 | + STINGER_FORALL_OUT_EDGES_OF_VTX_BEGIN (S, i) { |
| 112 | + /* neighbor has been visited */ |
| 113 | + if (!done && level[STINGER_EDGE_DEST] == nQ-1) { |
| 114 | + level[i] = nQ; |
| 115 | + marks[i] = 1; |
| 116 | + |
| 117 | + /* if we don't queue here, we cannot restart the forward search */ |
| 118 | + int64_t mine = stinger_int64_fetch_add(&Qnext, 1); |
| 119 | + queue[mine] = i; |
| 120 | + done = 1; |
| 121 | + } |
| 122 | + } STINGER_FORALL_OUT_EDGES_OF_VTX_END(); |
| 123 | + } |
| 124 | + } |
| 125 | + } |
| 126 | + |
| 127 | + Qstart = Qhead[nQ-1]; |
| 128 | + Qend = Qnext; |
| 129 | + Qhead[nQ++] = Qend; |
| 130 | + |
| 131 | + /* calculate new transition parameters */ |
| 132 | + nf_last = nf; |
| 133 | + nf = Qend - Qstart; |
| 134 | + mf = 0; |
| 135 | + OMP ("omp parallel for reduction(+:mf) reduction(-:mu)") |
| 136 | + for (int64_t j = Qstart; j < Qend; j++) { |
| 137 | + int64_t deg_j = stinger_outdegree_get(S, queue[j]); |
| 138 | + mf += deg_j; |
| 139 | + mu -= deg_j; |
| 140 | + } |
| 141 | + //printf("mf: %ld, nf: %ld, mu: %ld, nf_last: %ld\n", mf, nf, mu, nf_last); |
| 142 | + |
| 143 | + /* evaluate the transition state machine */ |
| 144 | + if (top_down) { |
| 145 | + if (mf > (mu / 14) && (nf - nf_last > 0)) { |
| 146 | + top_down = 0; |
| 147 | + } |
| 148 | + } else { |
| 149 | + if (nf < (nv / 24) && (nf - nf_last < 0)) { |
| 150 | + top_down = 1; |
| 151 | + } |
| 152 | + } |
| 153 | + } /* end while */ |
| 154 | + |
| 155 | + return nQ; |
| 156 | +} |
0 commit comments