diff options
| author | Mike Haertel | 2023-03-21 08:35:13 -0700 |
|---|---|---|
| committer | Mike Haertel | 2023-03-21 08:35:13 -0700 |
| commit | fa364103127162af6656950c56be2e8953010d25 (patch) | |
| tree | c8afd4a3556880eafdfb09cd3991974d29014193 /spin | |
| parent | Nefariously add our nefarious plan. (diff) | |
| download | biggolf-fa364103127162af6656950c56be2e8953010d25.tar.xz | |
Messy spin snapshot with bug demobug-skip-introduces-failure
Diffstat (limited to 'spin')
| -rw-r--r-- | spin/Makefile | 2 | ||||
| -rw-r--r-- | spin/snoopy.pml | 66 |
2 files changed, 41 insertions, 27 deletions
diff --git a/spin/Makefile b/spin/Makefile index 73669f9..cb862cf 100644 --- a/spin/Makefile +++ b/spin/Makefile | |||
| @@ -5,7 +5,7 @@ clean: | |||
| 5 | 5 | ||
| 6 | %.pml.trail: %.pml | 6 | %.pml.trail: %.pml |
| 7 | @rm -f $@ | 7 | @rm -f $@ |
| 8 | spin -search -bitstate -l $< | egrep '^(pan|spin):' | 8 | spin -search -bit $< | egrep '^(pan|spin):' |
| 9 | [ ! -e $@ ] || spin -c -g -l -p -replay $< | 9 | [ ! -e $@ ] || spin -c -g -l -p -replay $< |
| 10 | 10 | ||
| 11 | .SECONDARY: | 11 | .SECONDARY: |
diff --git a/spin/snoopy.pml b/spin/snoopy.pml index 4774b1a..0b4de5d 100644 --- a/spin/snoopy.pml +++ b/spin/snoopy.pml | |||
| @@ -20,70 +20,84 @@ proctype cache(int recvqbase; int sendqbase; int npeers) | |||
| 20 | #define ALLPEERS ((1 << npeers) - 1) | 20 | #define ALLPEERS ((1 << npeers) - 1) |
| 21 | #define RQ(i) qs[recvqbase+i] | 21 | #define RQ(i) qs[recvqbase+i] |
| 22 | #define SQ(i) qs[sendqbase+i] | 22 | #define SQ(i) qs[sendqbase+i] |
| 23 | #define ERESET() atomic { ebcmd = I; ebstate = I; enotsent = 0; enotrcvd = 0; ereverse = 0; esource = -1; } | ||
| 24 | #define P() noprogress = 0 | ||
| 23 | 25 | ||
| 24 | mtype cstate = I; // I, M, or Busy | 26 | mtype cstate = I; // I, M, or Busy |
| 25 | mtype ebcmd = I; // I, ItoM, or Busy | 27 | mtype ebcmd = I; // I, ItoM, or Busy |
| 26 | int ebstate = I; // I, M, or U | 28 | mtype ebstate = I; // I, M, or U |
| 27 | int enotsent = 0; // bitmask of snoops remaining to send | 29 | int enotsent = 0; // bitmask of snoops remaining to send |
| 28 | int enotrcvd = 0; // bitmask of replies remaining to receive | 30 | int enotrcvd = 0; // bitmask of replies remaining to receive |
| 29 | int ereverse = 0; // count of reverse progress | 31 | int ereverse = 0; // count of reverse progress |
| 30 | int esource = -1; // source of command (-1 is originated locally) | 32 | int esource = -1; // source of command (-1 is originated locally) |
| 31 | int i = 0; // current peer | 33 | int i = 0; // current peer |
| 34 | int fairmask = 0; // fairness mask to ensure servicing all peers | ||
| 35 | int noprogress = 0; // increment loop breaker | ||
| 32 | 36 | ||
| 33 | do | 37 | do |
| 34 | // Receive fill request from peer | 38 | // Receive fill request from peer |
| 35 | :: atomic { RQ(i)?ItoM -> if | 39 | :: atomic { RQ(i)?ItoM -> if |
| 36 | :: cstate == M -> cstate = I -> SQ(i)!M | 40 | :: cstate == M -> cstate = I -> SQ(i)!M |
| 37 | :: cstate == I && ebcmd == I -> ebcmd = ItoM -> enotsent = ALLPEERS & ~(1 << i) -> esource = i | 41 | :: cstate != M && ebcmd == I -> ebcmd = ItoM -> enotsent = ALLPEERS & ~(1 << i) -> esource = i |
| 38 | :: else -> SQ(i)!X | 42 | :: else -> SQ(i)!X |
| 39 | fi } | 43 | fi -> P() } |
| 40 | 44 | ||
| 41 | // Receive fill responses from peers | 45 | // Receive fill responses from peers |
| 42 | :: atomic { RQ(i)?I -> assert(ebcmd == ItoM && (enotsent & (1 << i)) == 0 && (enotrcvd & (1 << i)) != 0) -> enotrcvd = enotrcvd & ~(1 << i) } | 46 | :: atomic { RQ(i)?I -> assert(ebcmd == ItoM && (enotsent & (1 << i)) == 0 && (enotrcvd & (1 << i)) != 0) -> enotrcvd = enotrcvd & ~(1 << i) -> P() } |
| 43 | :: atomic { RQ(i)?M -> assert(ebcmd == ItoM && (enotsent & (1 << i)) == 0 && (enotrcvd & (1 << i)) != 0) -> enotrcvd = enotrcvd & ~(1 << i) -> ebstate = M -> if | 47 | :: atomic { RQ(i)?M -> assert(ebcmd == ItoM && (enotsent & (1 << i)) == 0 && (enotrcvd & (1 << i)) != 0) -> enotrcvd = enotrcvd & ~(1 << i) -> ebstate = M -> if |
| 44 | :: esource != -1 -> SQ(esource)!M | 48 | :: esource != -1 -> SQ(esource)!M |
| 45 | :: else /* ideally put it into the cache right away */ | 49 | :: else /* ideally put it into the cache right away */ |
| 46 | fi } | 50 | fi -> P() } |
| 47 | :: atomic { RQ(i)?U -> assert(ebcmd == ItoM && (enotsent & (1 << i)) == 0 && (enotrcvd & (1 << i)) != 0) -> enotrcvd = enotrcvd & ~(1 << i) -> if :: ebstate == I -> ebstate = U :: else fi } | 51 | :: atomic { RQ(i)?U -> assert(ebcmd == ItoM && (enotsent & (1 << i)) == 0 && (enotrcvd & (1 << i)) != 0) -> enotrcvd = enotrcvd & ~(1 << i) -> if :: ebstate == I -> ebstate = U :: else fi -> P() } |
| 48 | :: atomic { RQ(i)?X -> assert(ebcmd == ItoM && (enotsent & (1 << i)) == 0 && (enotrcvd & (1 << i)) != 0) -> enotrcvd = enotrcvd & ~(1 << i) -> enotsent = enotsent | (1 << i) -> ereverse = ereverse + 1 -> if | 52 | :: atomic { RQ(i)?X -> assert(ebcmd == ItoM && (enotsent & (1 << i)) == 0 && (enotrcvd & (1 << i)) != 0) -> enotrcvd = enotrcvd & ~(1 << i) -> enotsent = enotsent | (1 << i) -> ereverse = ereverse + 1 -> if |
| 49 | // To prevent deadlock, if we get X'd too many times abandon the transaction and send X to its source | 53 | // To prevent deadlock, if we get X'd too many times abandon the transaction and send X to its source |
| 50 | :: ereverse > npeers && esource == -1 && enotsent == ALLPEERS -> ebcmd = I -> ebstate = I -> enotsent = 0 -> ereverse = 0 -> esource = -1 | 54 | :: ereverse > npeers && esource == -1 && enotsent == ALLPEERS -> ERESET() |
| 51 | :: ereverse > npeers && esource != -1 && enotsent == ALLPEERS & ~(1 << esource) -> SQ(esource)!X -> ebcmd = I -> ebstate = I -> enotsent = 0 -> ereverse = 0 -> esource = -1 | 55 | :: ereverse > npeers && esource != -1 && enotsent == ALLPEERS & ~(1 << esource) -> SQ(esource)!X -> ERESET() |
| 52 | :: else | 56 | :: else |
| 53 | fi } | 57 | fi -> P() } |
| 54 | 58 | ||
| 55 | // Send not-yet-sent snoops | 59 | // Send not-yet-sent snoops |
| 56 | :: atomic { ebcmd == ItoM && (enotsent & (1 << i)) -> enotsent = enotsent & ~(1 << i) -> enotrcvd = enotrcvd | (1 << i) -> SQ(i)!ItoM } | 60 | :: atomic { ebcmd == ItoM && (enotsent & (1 << i)) -> enotsent = enotsent & ~(1 << i) -> enotrcvd = enotrcvd | (1 << i) -> SQ(i)!ItoM -> P() } |
| 57 | 61 | ||
| 58 | // Complete requests from peers (sending response if not sent earlier) | 62 | // Complete requests from peers (sending response to source if not already sent earlier) |
| 59 | :: atomic { ebcmd == ItoM && enotsent == 0 && enotrcvd == 0 && esource != -1 -> if | 63 | :: atomic { ebcmd == ItoM && enotsent == 0 && enotrcvd == 0 && esource != -1 -> if |
| 60 | :: ebstate == I -> SQ(esource)!I | 64 | :: ebstate == I -> SQ(esource)!I |
| 61 | :: ebstate == M | 65 | :: ebstate == M -> skip |
| 62 | :: ebstate == U -> SQ(esource)!U | 66 | :: ebstate == U -> SQ(esource)!U |
| 63 | :: else -> assert(false) | 67 | :: else -> assert(false) |
| 64 | fi -> ebcmd = I -> ebstate = I -> ereverse = 0 -> esource = -1 } | 68 | fi -> ERESET() -> P() } |
| 65 | 69 | ||
| 66 | // Complete locally-originated request when cache space is available to hold the data | 70 | // Complete locally-originated request when cache space is available to hold the data |
| 67 | :: atomic { ebcmd == ItoM && enotsent == 0 && enotrcvd == 0 && esource == -1 && cstate == I -> if | 71 | :: atomic { ebcmd == ItoM && enotsent == 0 && enotrcvd == 0 && esource == -1 && cstate == I -> if |
| 68 | :: (ebstate == M | ebstate == U) -> cstate = M | 72 | :: (ebstate == M | ebstate == U) -> cstate = M |
| 69 | :: else -> assert(false) | 73 | :: else -> assert(false) |
| 70 | fi -> ebcmd = I -> ebstate = I } | 74 | fi -> ERESET() -> P() } -> skip |
| 71 | 75 | ||
| 72 | :: else -> atomic { if | 76 | #if 0 |
| 73 | // Simulate local cache being occupied by other address | 77 | // Simulate local resources in use due to activity at other addresses |
| 74 | :: atomic { cstate == I -> cstate = Busy } | 78 | :: atomic { if :: cstate == I -> cstate = Busy :: cstate == Busy -> cstate = I fi } |
| 75 | :: atomic { cstate == Busy -> cstate = I } | 79 | :: atomic { if :: ebcmd == I -> ebcmd = Busy :: ebcmd == Busy -> ebcmd = I } |
| 80 | #endif | ||
| 76 | 81 | ||
| 77 | // Simulate evilbuffers conducting transaction for other address | 82 | #if 0 // these assertions further explode the states |
| 78 | :: atomic { ebcmd == I -> ebcmd = Busy } | 83 | // If we're not in a transaction assert that the evil buffer is fully reset (just to make sure we've limited reachable states) |
| 79 | :: atomic { ebcmd == Busy -> ebcmd = I } | 84 | :: atomic { ebcmd == Busy || ebcmd == I -> assert(ebstate == I && enotsent == 0 && enotrcvd == 0 && ereverse == 0 && esource == -1) } |
| 85 | // If we're in ItoM transaction assert that it's not in the cache | ||
| 86 | :: atomic { ebcmd == ItoM -> assert(cstate == I || cstate == Busy) } | ||
| 87 | #endif | ||
| 80 | 88 | ||
| 81 | // Launch locally-requested fills; rely on deadlock avoidance above to protect from multiple peers simultaneously deciding to do this | 89 | // Launch locally-requested fills; rely on deadlock avoidance above to protect from multiple peers simultaneously deciding to do this |
| 82 | :: atomic { ebcmd == I -> ebcmd = ItoM -> enotsent = ALLPEERS -> enotrcvd = 0 -> ereverse = 0 -> esource = -1 } | 90 | :: atomic { cstate != M && ebcmd == I -> ebcmd = ItoM -> enotsent = ALLPEERS -> esource = -1 -> P() } |
| 83 | 91 | ||
| 84 | // Cycle through connections to all peers to ensure fairness | 92 | #if 1 |
| 85 | :: atomic { i = (i + 1) % npeers } | 93 | // Cycle through connections to all peers to ensure fairness |
| 86 | fi } | 94 | :: atomic { noprogress < 2 -> i = (i + 1) % npeers -> if :: i == 0 -> noprogress = noprogress + 1 :: else fi } |
| 95 | #else | ||
| 96 | :: atomic { noprogress < 2 && npeers >= 1 && (fairmask & 1) == 0 -> i = 0 -> fairmask = fairmask | 1 } | ||
| 97 | :: atomic { noprogress < 2 && npeers >= 2 && (fairmask & 2) == 0 -> i = 1 -> fairmask = fairmask | 2 } | ||
| 98 | :: atomic { noprogress < 2 && npeers >= 3 && (fairmask & 4) == 0 -> i = 2 -> fairmask = fairmask | 4 } | ||
| 99 | :: atomic { fairmask == (1 << npeers) - 1 -> fairmask = 0 -> noprogress = noprogress + 1 } | ||
| 100 | #endif | ||
| 87 | od | 101 | od |
| 88 | 102 | ||
| 89 | #undef ALLPEERS | 103 | #undef ALLPEERS |
