-
Notifications
You must be signed in to change notification settings - Fork 34
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
Spin locks detection enhancements #228
Changes from all commits
67b3288
78df4c5
534ecc8
69df8ab
5f565d5
9f1dd61
cd264c4
b8b43a4
b1c31c3
e5d9224
4713ecf
6fbe1af
f743ea3
9aee14d
d21c6c9
083e60f
6ab8253
c8ecc73
98a3ed8
b84a8d0
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 |
---|---|---|
|
@@ -84,7 +84,8 @@ private static boolean doNotTransform(String className) { | |
className.equals(kotlinx.coroutines.CoroutineContextKt.class.getName()) || | ||
className.equals(kotlinx.coroutines.CancellableContinuation.class.getName()) || | ||
className.equals(kotlinx.coroutines.CoroutineExceptionHandler.class.getName()) || | ||
className.equals(kotlinx.coroutines.CoroutineDispatcher.class.getName()); | ||
className.equals(kotlinx.coroutines.CoroutineDispatcher.class.getName()) || | ||
className.equals(TrackMethodsFlagHolder.class.getName()); | ||
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. Similarly to other Lincheck classes, it should not be transformed by default |
||
} | ||
|
||
/** | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -57,6 +57,14 @@ class ObstructionFreedomViolationInvocationResult( | |
) : InvocationResult() | ||
|
||
/** | ||
* Indicates that spin-cycle has been found for the first time and replay of current interleaving is required. | ||
* Indicates that spin-cycle has been found for the first time, and replay with additional events tracking | ||
* (methods enter/exit, receiver and parameters) of current interleaving is required to measure its period. | ||
*/ | ||
object SpinCycleFoundAndReplayRequired: InvocationResult() | ||
object SpinCycleFoundForTheFirstTimeAndReplayRequired: InvocationResult() | ||
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. You can shorten the name to "SpinCycleDetectedAndReplayRequired" |
||
|
||
/** | ||
* Indicates that the period of the spin-cycle has been calculated, additional events tracking can be turned off, | ||
* and we can resume standard flow from the current interleaving. | ||
*/ | ||
object SpinCyclePeriodMeasuredAndExecutionCanBeContinued: InvocationResult() | ||
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. You can shorten the name to just "SpinCycleDetected" |
||
|
||
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. Keep only one empty line at the end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -51,7 +51,10 @@ internal fun <T> findMaxPrefixLengthWithNoCycleOnSuffix(elements: List<T>): Cycl | |
|
||
return if (targetCycleLength == elements.size) { | ||
null // cycle not found | ||
} else CycleInfo(minLastPositionNotRelatedToCycle + 1, targetCycleLength) // number of prefix elements with first cycle | ||
} else CycleInfo( | ||
minLastPositionNotRelatedToCycle + 1, | ||
targetCycleLength | ||
) // number of prefix elements with first cycle | ||
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. Is the comment in the correct place? |
||
} | ||
|
||
data class CycleInfo( | ||
|
@@ -83,6 +86,9 @@ private fun <T> findLastIndexNotRelatedToCycle(elements: List<T>, cycleLength: I | |
*/ | ||
internal class InterleavingHistoryNode( | ||
val threadId: Int, | ||
/** | ||
* Sum of executions before cycle and the cycle period | ||
*/ | ||
var executions: Int = 0, | ||
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. What do you mean by "execution"? Event? |
||
/** | ||
* Hash code calculated by execution ids of this switch, | ||
|
@@ -100,7 +106,8 @@ internal class InterleavingHistoryNode( | |
/** | ||
* This field is updated when execution is replayed and we meet a sequence that previously led to a cycle. | ||
*/ | ||
var spinCyclePeriod: Int = 0 | ||
var spinCyclePeriod: Int = 0, | ||
var executionsBeforeSpinCycleWithAdditionalEvents: Int, | ||
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. What does this mean? |
||
) { | ||
val cycleOccurred: Boolean get() = spinCyclePeriod != 0 | ||
|
||
|
@@ -119,22 +126,26 @@ internal class InterleavingHistoryNode( | |
fun asNodeCorrespondingToCycle( | ||
executionsBeforeCycle: Int, | ||
cyclePeriod: Int, | ||
cycleExecutionsHash: Int | ||
executionsBeforeSpinCycleWithAdditionalEvents: Int, | ||
cycleExecutionsHash: Int, | ||
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. Revert this line, please |
||
): InterleavingHistoryNode { | ||
check(executions >= executionsBeforeCycle) | ||
check(executions >= executionsBeforeCycle) { "?" } | ||
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. Please replace "?" with a meaningful message |
||
|
||
return InterleavingHistoryNode( | ||
threadId = threadId, | ||
executions = executionsBeforeCycle, | ||
spinCyclePeriod = cyclePeriod, | ||
executionHash = cycleExecutionsHash | ||
executionHash = cycleExecutionsHash, | ||
executionsBeforeSpinCycleWithAdditionalEvents = executionsBeforeSpinCycleWithAdditionalEvents, | ||
) | ||
} | ||
|
||
fun copy() = InterleavingHistoryNode( | ||
threadId = threadId, | ||
executions = executions, | ||
executionHash = executionHash | ||
executionHash = executionHash, | ||
spinCyclePeriod = spinCyclePeriod, | ||
executionsBeforeSpinCycleWithAdditionalEvents = executionsBeforeSpinCycleWithAdditionalEvents, | ||
) | ||
|
||
|
||
|
@@ -219,6 +230,10 @@ internal class InterleavingSequenceTrackableSet { | |
* Only present when this node corresponds to cycle, i.e. [cycleOccurred] != 0 | ||
*/ | ||
val cycleLocationsHash: Int, | ||
/** | ||
* Only present when this node corresponds to cycle, i.e. [cycleOccurred] != 0 | ||
*/ | ||
val executionsBeforeSpinCycleWithAdditionalEvents: Int, | ||
private var transitions: MutableMap<Int, InterleavingSequenceSetNode>? = null | ||
) { | ||
|
||
|
@@ -241,7 +256,8 @@ internal class InterleavingSequenceTrackableSet { | |
fun mergeBranch(newChain: List<InterleavingHistoryNode>, startIndex: Int, executionsCountedEarlier: Int) { | ||
if (startIndex > newChain.lastIndex) return | ||
val firstNewNode = newChain[startIndex] | ||
val firstNewNodeExecutions = (firstNewNode.executions + firstNewNode.spinCyclePeriod) - executionsCountedEarlier | ||
val firstNewNodeExecutions = | ||
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. Please revert the formatting |
||
(firstNewNode.executions + firstNewNode.spinCyclePeriod) - executionsCountedEarlier | ||
check(firstNewNode.threadId == threadId) | ||
|
||
when { | ||
|
@@ -263,7 +279,8 @@ internal class InterleavingSequenceTrackableSet { | |
transitions = transitions, | ||
cyclePeriod = cyclePeriod, | ||
cycleOccurred = cycleOccurred, | ||
cycleLocationsHash = cycleLocationsHash | ||
cycleLocationsHash = cycleLocationsHash, | ||
executionsBeforeSpinCycleWithAdditionalEvents = executionsBeforeSpinCycleWithAdditionalEvents | ||
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. Shorten the parameter name |
||
) | ||
executions = firstNewNodeExecutions | ||
cyclePeriod = firstNewNode.spinCyclePeriod | ||
|
@@ -320,6 +337,7 @@ internal class InterleavingSequenceTrackableSet { | |
cyclePeriod = first.spinCyclePeriod, | ||
cycleLocationsHash = first.executionHash, | ||
cycleOccurred = startIndex == chain.lastIndex, | ||
executionsBeforeSpinCycleWithAdditionalEvents = first.executionsBeforeSpinCycleWithAdditionalEvents | ||
) | ||
var current = root | ||
|
||
|
@@ -329,8 +347,9 @@ internal class InterleavingSequenceTrackableSet { | |
threadId = next.threadId, | ||
executions = next.executions + next.spinCyclePeriod, | ||
cyclePeriod = next.spinCyclePeriod, | ||
cycleLocationsHash = first.executionHash, | ||
cycleOccurred = i == chain.lastIndex | ||
cycleLocationsHash = next.executionHash, | ||
cycleOccurred = i == chain.lastIndex, | ||
executionsBeforeSpinCycleWithAdditionalEvents = next.executionsBeforeSpinCycleWithAdditionalEvents | ||
) | ||
current.addTransition(next.threadId, nextNode) | ||
current = nextNode | ||
|
@@ -396,6 +415,7 @@ internal class InterleavingSequenceTrackableSet { | |
Otherwise, if the next thread id is, for example, 5, then the cursor will become invalid and | ||
`isInCycle` property will return false and won't react on any events until the next cursor `reset` or `setTo` methods calls. | ||
*/ | ||
|
||
/** | ||
* Excepted to call only if [isInCycle] returned `true` | ||
*/ | ||
|
@@ -424,6 +444,8 @@ internal class InterleavingSequenceTrackableSet { | |
it.cycleOccurred && executionsCount == it.executions | ||
} ?: false | ||
|
||
val executionsBeforeSpinCycleWithAdditionalEvents: Int get() = currentNode!!.executionsBeforeSpinCycleWithAdditionalEvents | ||
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. Please document |
||
|
||
/** | ||
* Resets cursor to the leaf of the new added cycle | ||
*/ | ||
|
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.
Please repackage it to
org.jetbrains.kotlinx.lincheck