-
Notifications
You must be signed in to change notification settings - Fork 38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Example: Two-layered Cache #1549
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,185 @@ | ||||||||||||||||||||||||||
module twolayeredcache { | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In order to get some highlighting on GitHub while we don't have official support, we add this comment at the beginning which tells it to consider this as a bluespec file, which is the best matching highlighting for Quint at the moment. Also, adding underscores to the module name will make it easier to read (which we should also do for the file name).
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, if you can add a header comment here explaining the context and/or adding links about it, and include you as an author, it would be great. Like this one: quint/examples/classic/distributed/ewd840/ewd840.qnt Lines 3 to 10 in 7b968e5
|
||||||||||||||||||||||||||
//********************************************************** | ||||||||||||||||||||||||||
// TYPE DEFINITIONS | ||||||||||||||||||||||||||
//********************************************************** | ||||||||||||||||||||||||||
type CacheLayer = Set[int] | ||||||||||||||||||||||||||
type ClientPID = int | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
// tpe: "read" or "write" | ||||||||||||||||||||||||||
type HistoryEntry = { tpe: str, value: int} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
//********************************************************** | ||||||||||||||||||||||||||
// CONSTANTS | ||||||||||||||||||||||||||
//********************************************************** | ||||||||||||||||||||||||||
pure val DefaultExpireDuration = 3 | ||||||||||||||||||||||||||
pure val ClientProcesses: Set[ClientPID] = 1.to(10) | ||||||||||||||||||||||||||
pure val MaxVal = 1000000 | ||||||||||||||||||||||||||
pure val Expired = -99 | ||||||||||||||||||||||||||
pure val NotFound = -98 | ||||||||||||||||||||||||||
Comment on lines
+14
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some of these are not used. Shall we remove them?
Suggested change
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
//********************************************************** | ||||||||||||||||||||||||||
// STATE MACHINE | ||||||||||||||||||||||||||
// State-dependent definitions and actions | ||||||||||||||||||||||||||
//********************************************************** | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
var l1: CacheLayer | ||||||||||||||||||||||||||
var l2: CacheLayer | ||||||||||||||||||||||||||
var num: int | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
// Global log of system events. Use to specify correctness | ||||||||||||||||||||||||||
// properties below. | ||||||||||||||||||||||||||
var history: List[HistoryEntry] | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
//********************************************************** | ||||||||||||||||||||||||||
// FUNCTIONAL LAYER | ||||||||||||||||||||||||||
// Values and functions that are state-independent | ||||||||||||||||||||||||||
//********************************************************** | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
action writeLayer(layer: CacheLayer, v: int): bool = all { | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is part of your functional layer section, but it is an action and interacts with state, so I think it should belong in either helpers or actions. |
||||||||||||||||||||||||||
layer' = layer.union(Set(v)) | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
Comment on lines
+38
to
+40
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Passing the state variable "as reference" here and assigning to a parameter is not valid Quint. I noticed Apalache is working with that, I guess because it's made for TLA+ and TLA+ allows arbitrary usage of the prime operator (
Suggested change
Using the Quint simulator ( |
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
//********************************************************** | ||||||||||||||||||||||||||
// HELPERS | ||||||||||||||||||||||||||
// Functions for convenience | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor thing, but we refer to Quint definitions as operators
Suggested change
|
||||||||||||||||||||||||||
//********************************************************** | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
//********************************************************** | ||||||||||||||||||||||||||
// ACTIONS | ||||||||||||||||||||||||||
//********************************************************** | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
action writeCache(pid: ClientPID, v: int): bool = all { | ||||||||||||||||||||||||||
writeLayer(l1, v), | ||||||||||||||||||||||||||
writeLayer(l2, v), | ||||||||||||||||||||||||||
history' = history.append({ | ||||||||||||||||||||||||||
tpe: "write", | ||||||||||||||||||||||||||
value: v, | ||||||||||||||||||||||||||
}), | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
action handleNotFound: bool = all { | ||||||||||||||||||||||||||
l1' = l1, | ||||||||||||||||||||||||||
l2' = l2, | ||||||||||||||||||||||||||
history' = history.append({ | ||||||||||||||||||||||||||
tpe: "read", | ||||||||||||||||||||||||||
value: NotFound, | ||||||||||||||||||||||||||
}), | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
action handleL1Found(v: int): bool = all { | ||||||||||||||||||||||||||
l1' = l1, | ||||||||||||||||||||||||||
l2' = l2, | ||||||||||||||||||||||||||
history' = history.append({ | ||||||||||||||||||||||||||
tpe: "read", | ||||||||||||||||||||||||||
value: v, | ||||||||||||||||||||||||||
}), | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
action handleL2Found(v: int): bool = all { | ||||||||||||||||||||||||||
writeLayer(l1, v), | ||||||||||||||||||||||||||
l2' = l2, | ||||||||||||||||||||||||||
history' = history.append({ | ||||||||||||||||||||||||||
tpe: "read", | ||||||||||||||||||||||||||
value: v, | ||||||||||||||||||||||||||
}), | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
action handleFound(v: int): bool = { | ||||||||||||||||||||||||||
if(l1.contains(v)) { | ||||||||||||||||||||||||||
handleL1Found(v) | ||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||
handleL2Found(v) | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
// If this val doesn't exist in L1, read from L2. | ||||||||||||||||||||||||||
// If val exists in L2, write back to L1 then return. | ||||||||||||||||||||||||||
// Otherwise, not found (false). | ||||||||||||||||||||||||||
action readCache(pid: ClientPID, v: int): bool = { | ||||||||||||||||||||||||||
if (not(l1.contains(v)) and not(l2.contains(v))) { | ||||||||||||||||||||||||||
handleNotFound | ||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||
handleFound(v) | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
Comment on lines
+99
to
+103
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is easier to read and follows the comment more closely
Suggested change
|
||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
action clientProc = all { | ||||||||||||||||||||||||||
num' = num + 1, | ||||||||||||||||||||||||||
nondet pid = ClientProcesses.oneOf() | ||||||||||||||||||||||||||
nondet readVal = 1.to(num).oneOf() | ||||||||||||||||||||||||||
any { | ||||||||||||||||||||||||||
writeCache(pid, num), | ||||||||||||||||||||||||||
readCache(pid, readVal), | ||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
action init = all { | ||||||||||||||||||||||||||
num' = 0, | ||||||||||||||||||||||||||
l1' = Set(), | ||||||||||||||||||||||||||
l2' = Set(), | ||||||||||||||||||||||||||
history' = [], | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
action stutter = all { | ||||||||||||||||||||||||||
num' = num, | ||||||||||||||||||||||||||
l1' = l1, | ||||||||||||||||||||||||||
l2' = l2, | ||||||||||||||||||||||||||
history' = history, | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
action step = any { | ||||||||||||||||||||||||||
clientProc, | ||||||||||||||||||||||||||
stutter, | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
//********************************************************** | ||||||||||||||||||||||||||
// CORRECTNESS | ||||||||||||||||||||||||||
// 1. Safety Properties / Invariants | ||||||||||||||||||||||||||
//********************************************************** | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
// Read the latest write | ||||||||||||||||||||||||||
val readAfterWrite: bool = { | ||||||||||||||||||||||||||
val idx = history.indices() | ||||||||||||||||||||||||||
idx.forall(i => { | ||||||||||||||||||||||||||
idx.forall(j => { | ||||||||||||||||||||||||||
i < j | ||||||||||||||||||||||||||
and history[i].tpe == "write" | ||||||||||||||||||||||||||
and history[j].tpe == "read" | ||||||||||||||||||||||||||
implies history[i].value <= history[j].value | ||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
// Later write must contain a greater value | ||||||||||||||||||||||||||
val writeAfterWrite: bool = { | ||||||||||||||||||||||||||
val idx = history.indices() | ||||||||||||||||||||||||||
idx.forall(i => { | ||||||||||||||||||||||||||
idx.forall(j => { | ||||||||||||||||||||||||||
i < j | ||||||||||||||||||||||||||
and history[i].tpe == "write" | ||||||||||||||||||||||||||
and history[j].tpe == "write" | ||||||||||||||||||||||||||
implies history[i].value < history[j].value | ||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
val strongConsistency: bool = { | ||||||||||||||||||||||||||
readAfterWrite | ||||||||||||||||||||||||||
and writeAfterWrite | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
val safety: bool = { | ||||||||||||||||||||||||||
strongConsistency | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
//********************************************************** | ||||||||||||||||||||||||||
// CORRECTNESS | ||||||||||||||||||||||||||
// 2. Liveness Properties / Temporal | ||||||||||||||||||||||||||
//********************************************************** | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
//********************************************************** | ||||||||||||||||||||||||||
// QUICK TESTS | ||||||||||||||||||||||||||
//********************************************************** | ||||||||||||||||||||||||||
// run initAndStepTest = init.then(step) | ||||||||||||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if this would fit into one of the existing folders. I think it could be under
classic/distributed
, WDYT?