summaryrefslogtreecommitdiff
path: root/spin
diff options
context:
space:
mode:
authorJulian Blake Kongslie2023-04-08 13:28:28 -0700
committerJulian Blake Kongslie2023-04-08 13:28:28 -0700
commit4420244e9c0fdef41baf811c283d9f843265d254 (patch)
tree68db1b02e937866da72025735753f4123a529ba1 /spin
parentquestionable hacks (diff)
downloadbiggolf-4420244e9c0fdef41baf811c283d9f843265d254.tar.xz
Add spontaneous evictions.HEADmain
Diffstat (limited to '')
-rw-r--r--spin/Makefile2
-rw-r--r--spin/snoopy.pml55
2 files changed, 40 insertions, 17 deletions
diff --git a/spin/Makefile b/spin/Makefile
index 73669f9..65bf08e 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 -run -bfs -bitstate $< #| 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 1aff5af..3d22d21 100644
--- a/spin/snoopy.pml
+++ b/spin/snoopy.pml
@@ -1,6 +1,6 @@
1mtype { 1mtype {
2 I, M, // valid cache line states: invalid, modified 2 I, M, // valid cache line states: invalid, modified
3 U, X, // fill/snoop responses that are not valid cache line states: unknown (from DRAM only), fail (you have to try again) 3 U, X, // evict/fill/snoop responses that are not valid cache line states: unknown (from DRAM only), fail (you have to try again)
4 ItoM, MtoI, // commands from peers 4 ItoM, MtoI, // commands from peers
5 Busy, // used as both cache line state and evil buffer command to denote activity on behalf of other addresses 5 Busy, // used as both cache line state and evil buffer command to denote activity on behalf of other addresses
6} 6}
@@ -23,7 +23,7 @@ proctype cache(int recvqbase; int sendqbase; int npeers)
23#define SQ(i) qs[sendqbase+i] 23#define SQ(i) qs[sendqbase+i]
24 24
25 mtype cstate = I; // I, M, or Busy 25 mtype cstate = I; // I, M, or Busy
26 mtype ebcmd = I; // I, ItoM, or Busy 26 mtype ebcmd = I; // I, ItoM, MtoI, or Busy
27 int ebstate = I; // I, M, or U 27 int ebstate = I; // I, M, or U
28 int enotsent = 0; // bitmask of snoops remaining to send 28 int enotsent = 0; // bitmask of snoops remaining to send
29 int enotrcvd = 0; // bitmask of replies remaining to receive 29 int enotrcvd = 0; // bitmask of replies remaining to receive
@@ -36,26 +36,48 @@ proctype cache(int recvqbase; int sendqbase; int npeers)
36 :: atomic { RQ(i)?ItoM -> if 36 :: atomic { RQ(i)?ItoM -> if
37 :: cstate == M -> cstate = I -> SQ(i)!M 37 :: cstate == M -> cstate = I -> SQ(i)!M
38 :: cstate == I && ebcmd == I -> ebcmd = ItoM -> enotsent = ALLPEERS & ~(1 << i) -> esource = i 38 :: cstate == I && ebcmd == I -> ebcmd = ItoM -> enotsent = ALLPEERS & ~(1 << i) -> esource = i
39 :: cstate == I && ebcmd == MtoI && enotsent != 0 -> ERESET() -> SQ(i)!M
39 :: else -> SQ(i)!X 40 :: else -> SQ(i)!X
40 fi } 41 fi }
41 42
43 // Receive eviction request from peer
44 :: atomic { RQ(i)?MtoI -> if
45 :: cstate == M || ebcmd == MtoI -> assert(false)
46 :: cstate == I && ebcmd == I -> cstate = M -> SQ(i)!I
47// :: cstate == I && ebcmd == ItoM -> ebstate = M -> enotsent = 0 -> SQ(i)!I // Missing logic: cut-through send to esource, clear out eb when enotrcvd is already 0
48 :: cstate == I && ebcmd == ItoM -> SQ(i)!X
49 :: cstate == I && ebcmd == Busy -> cstate = M -> SQ(i)!I
50 :: cstate == Busy && ebcmd == I -> assert(i != npeers-1) -> ebcmd = MtoI -> enotsent = 1 << (npeers-1) -> SQ(i)!I
51 :: cstate == Busy && ebcmd != I -> SQ(i)!X
52 fi }
53
42 // Receive fill responses from peers 54 // Receive fill responses from peers
43 :: atomic { RQ(i)?I -> assert(ebcmd == ItoM && (enotsent & (1 << i)) == 0 && (enotrcvd & (1 << i)) != 0) -> enotrcvd = enotrcvd & ~(1 << i) } 55 :: atomic { RQ(i)?I -> assert((enotsent & (1 << i)) == 0 && (enotrcvd & (1 << i)) != 0) -> if
44 :: atomic { RQ(i)?M -> assert(ebcmd == ItoM && (enotsent & (1 << i)) == 0 && (enotrcvd & (1 << i)) != 0) -> enotrcvd = enotrcvd & ~(1 << i) -> ebstate = M -> if 56 :: ebcmd == ItoM -> enotrcvd = enotrcvd & ~(1 << i)
57 :: ebcmd == MtoI -> ERESET()
58 :: else -> assert(false)
59 fi }
60 :: atomic { RQ(i)?M -> assert(ebcmd == ItoM) -> assert((enotsent & (1 << i)) == 0 && (enotrcvd & (1 << i)) != 0) -> enotrcvd = enotrcvd & ~(1 << i) -> ebstate = M -> if
45 :: esource != -1 -> SQ(esource)!M 61 :: esource != -1 -> SQ(esource)!M
46 :: else /* ideally put it into the cache right away */ 62 :: else /* ideally put it into the cache right away */
47 fi } 63 fi }
48 :: 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 } 64 :: atomic { RQ(i)?U -> assert(ebcmd == ItoM) -> assert((enotsent & (1 << i)) == 0 && (enotrcvd & (1 << i)) != 0) -> enotrcvd = enotrcvd & ~(1 << i) -> if :: ebstate == I -> ebstate = U :: else fi }
49 :: 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 65 :: atomic { RQ(i)?X -> assert((enotsent & (1 << i)) == 0 && (enotrcvd & (1 << i)) != 0) -> enotrcvd = enotrcvd & ~(1 << i) -> enotsent = enotsent | (1 << i) -> if
50 // To prevent deadlock, if we get X'd too many times abandon the transaction and send X to its source 66 :: ebcmd == ItoM -> ereverse = ereverse + 1 -> if
51 :: atomic { ereverse > npeers && esource == -1 && enotsent == ALLPEERS -> ERESET() } 67 :: atomic { ereverse > npeers && esource == -1 && enotsent == ALLPEERS -> ERESET() }
52 :: atomic { ereverse > npeers && esource != -1 && enotsent == ALLPEERS & ~(1 << esource) -> SQ(esource)!X -> ERESET() } 68 :: atomic { ereverse > npeers - 1 && esource != -1 && enotsent == ALLPEERS & ~(1 << esource) -> SQ(esource)!X -> ERESET() }
53 :: else 69 :: else
70 fi
71 :: ebcmd == MtoI
72 :: else -> assert(false)
54 fi } 73 fi }
55 74
56 // Send not-yet-sent snoops 75 // Send not-yet-sent snoops
57 :: atomic { ebcmd == ItoM && (enotsent & (1 << i)) -> enotsent = enotsent & ~(1 << i) -> enotrcvd = enotrcvd | (1 << i) -> SQ(i)!ItoM } 76 :: atomic { ebcmd == ItoM && (enotsent & (1 << i)) -> enotsent = enotsent & ~(1 << i) -> enotrcvd = enotrcvd | (1 << i) -> SQ(i)!ItoM }
58 77
78 // Send not-yet-sent evictions
79 :: atomic { ebcmd == MtoI && (enotsent & (1 << i)) -> enotsent = enotsent & ~(1 << i) -> enotrcvd = enotrcvd | (1 << i) -> SQ(i)!MtoI }
80
59 // Complete requests from peers (sending response if not sent earlier) 81 // Complete requests from peers (sending response if not sent earlier)
60 :: atomic { ebcmd == ItoM && enotsent == 0 && enotrcvd == 0 && esource != -1 -> if 82 :: atomic { ebcmd == ItoM && enotsent == 0 && enotrcvd == 0 && esource != -1 -> if
61 :: ebstate == I -> SQ(esource)!I 83 :: ebstate == I -> SQ(esource)!I
@@ -70,20 +92,21 @@ proctype cache(int recvqbase; int sendqbase; int npeers)
70 :: else -> assert(false) 92 :: else -> assert(false)
71 fi -> ERESET() } 93 fi -> ERESET() }
72 94
73#if 0
74 // Simulate local cache being occupied by other address 95 // Simulate local cache being occupied by other address
75 :: atomic { if :: cstate == I -> cstate = Busy :: cstate == Busy -> cstate = I :: else fi } 96 :: atomic { cstate == I -> cstate = Busy }
97 :: atomic { cstate == Busy -> cstate = I }
76 98
77 // Simulate evilbuffers conducting transaction for other address 99 // Simulate evilbuffers conducting transaction for other address
78 :: atomic { if :: ebcmd == I -> ebcmd = Busy :: ebcmd == Busy -> ebcmd = I :: else fi } 100 :: atomic { ebcmd == I -> ebcmd = Busy }
79#endif 101 :: atomic { ebcmd == Busy -> ebcmd = I }
102
103 // Simulate local cache spontaneously evicting
104 :: atomic { cstate == M && ebcmd == I -> cstate = I -> ebcmd = MtoI -> enotsent = 1 << (npeers-1) }
80 105
81#if 0
82 // If we're not in a transaction assert that the evil buffer is fully reset (just to make sure we've limited reachable states) 106 // If we're not in a transaction assert that the evil buffer is fully reset (just to make sure we've limited reachable states)
83 :: atomic { ebcmd == Busy || ebcmd == I -> assert(ebstate == I && enotsent == 0 && enotrcvd == 0 && ereverse == 0 && esource == -1) } 107 :: atomic { ebcmd == Busy || ebcmd == I -> assert(ebstate == I && enotsent == 0 && enotrcvd == 0 && ereverse == 0 && esource == -1) }
84 // If we're in ItoM transaction assert that it's not in the cache 108 // If we're in ItoM transaction assert that it's not in the cache
85 :: atomic { ebcmd == ItoM -> assert(cstate == I || cstate == Busy) } 109 :: atomic { ebcmd == ItoM -> assert(cstate == I || cstate == Busy) }
86#endif
87 110
88 // Launch locally-requested fills; rely on deadlock avoidance above to protect from multiple peers simultaneously deciding to do this 111 // Launch locally-requested fills; rely on deadlock avoidance above to protect from multiple peers simultaneously deciding to do this
89 :: atomic { cstate != M && ebcmd == I -> ebcmd = ItoM -> enotsent = ALLPEERS -> esource = -1 } 112 :: atomic { cstate != M && ebcmd == I -> ebcmd = ItoM -> enotsent = ALLPEERS -> esource = -1 }