Skip to content
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

Support custom threads #415

Open
wants to merge 141 commits into
base: develop
Choose a base branch
from
Open

Support custom threads #415

wants to merge 141 commits into from

Conversation

eupp
Copy link
Collaborator

@eupp eupp commented Oct 11, 2024

No description provided.

@eupp eupp marked this pull request as ready for review October 12, 2024 01:30
@eupp eupp requested a review from ndkoval October 12, 2024 01:30
@eupp
Copy link
Collaborator Author

eupp commented Oct 12, 2024

The only failing CI configuration is "Integration Test with kotlinx.coroutines".
I believe it is because of #412, and once we merge #413 the problem should be fixed.
I've create a separate test branch where I merged the #413 into my branch, and it seems that there all kotlinx.coroutines tests are passed.

@eupp eupp force-pushed the dynamic-threads branch 2 times, most recently from 0ad50bd to 25c0c45 Compare October 31, 2024 17:15
@eupp eupp requested a review from ndkoval October 31, 2024 17:20
@eupp
Copy link
Collaborator Author

eupp commented Oct 31, 2024

@ndkoval while working on this I discovered a few problems, which are probably should be addressed in separate PRs.

One of the problems is related to the local objects tracking --- the current implementation does not work correctly with custom threads (see example below and the comment in DataStructuresTests::incorrectHashMap test).
So the problem can be illustrated by the following example:

class Box(var x: Int)

fun test(): Int {
    val box = Box() // <- this object is incorrectly classified as a local object
    thread {
        box.x = 42 // the local object tracker does not detect here that the `box` object,
                   // stored in the local variable, escapes into another thread;
                   // thus it will not insert a switch point before accesses to this object fields
    }
    return box.x
}

I would propose that we can address this problem separately in another PR after we merge this one.
The reasons is that adding support of this case would require significant refactoring of local objects tracking algorithm,
and this PR is already big.

Alternatively, we can first perform the necessary refactoring of the local objects tracking algorithm in a separate PR,
and after this rebase and merge custom threads PR.

@eupp
Copy link
Collaborator Author

eupp commented Nov 26, 2024

Another small bug fix on which this PR relies on: #426

eupp added 16 commits December 11, 2024 16:22
Signed-off-by: Evgeniy Moiseenko <[email protected]>
* in preparation of implementing ignored sections for custom threads

Signed-off-by: Evgeniy Moiseenko <[email protected]>
Signed-off-by: Evgeniy Moiseenko <[email protected]>
…in `cancelByLincheck`

Signed-off-by: Evgeniy Moiseenko <[email protected]>
Signed-off-by: Evgeniy Moiseenko <[email protected]>
eupp added 25 commits December 11, 2024 16:24
Signed-off-by: Evgeniy Moiseenko <[email protected]>
…in the thread descriptors map

Signed-off-by: Evgeniy Moiseenko <[email protected]>
Signed-off-by: Evgeniy Moiseenko <[email protected]>
Signed-off-by: Evgeniy Moiseenko <[email protected]>
Signed-off-by: Evgeniy Moiseenko <[email protected]>
Signed-off-by: Evgeniy Moiseenko <[email protected]>
Signed-off-by: Evgeniy Moiseenko <[email protected]>
Signed-off-by: Evgeniy Moiseenko <[email protected]>
Signed-off-by: Evgeniy Moiseenko <[email protected]>
@@ -15,7 +15,7 @@ version=2.35-SNAPSHOT
inceptionYear=2019
lastCopyrightYear=2023

jdkToolchainVersion=17
jdkToolchainVersion=8
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please revert the change

@@ -45,6 +50,101 @@ public class Injections {
@SuppressWarnings({"FieldCanBeLocal", "unused"})
private static int currentEventId = -1;

// Thread local variable storing testing code and ignored section flags.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this line

* - These lists use copy-on-write strategy when a new descriptor is added to avoid race conditions.
* - Thread descriptors store weak references to thread objects, and thus do not prevent their garbage collection.
*
* TODO: although the garbage collection of thread objects is not prevented thanks to weak references,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can do the cleanup on each 1000's (feel free choose any number here) access

return ((TestThread) thread).descriptor;
}
int hashCode = System.identityHashCode(thread);
ArrayList<ThreadDescriptor> threadDescriptors = threadDescriptorsMap.get(hashCode);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use a weak hash map instead?

| | switch |
| operation() | |
| MONITORENTER at ObstructionFreedomSynchronizedRepresentationTest.operation(ObstructionFreedomRepresentationTest.kt:70) | |
| MONITORENTER at ObstructionFreedomSynchronizedRepresentationTest.operation(ObstructionFreedomRepresentationTest.kt:61) | |
| switch (reason: lock is already acquired) | |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there any switch? It seems the execution ends after this event.

| switch | | |
| | run() | |
| | switch | |
| switch (reason: waiting for thread to join) | | |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's mention which thread the execution is calling join on

internal fun modelCheckerTest(
testClass: KClass<*>,
testOperation: KFunction<*>,
outcomes: Set<Any?> = setOf(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these the excepted outcomes?

@@ -79,7 +79,8 @@ fun shouldReplayInterleaving(): Boolean {
*/
@Suppress("UNUSED_PARAMETER")
fun beforeEvent(eventId: Int, type: String) {
val strategy = (Thread.currentThread() as? TestThread)?.eventTracker ?: return
val strategy = Injections.getCurrentThreadDescriptor()?.eventTracker
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you checked how custom threads work with the plugin?

* with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

package org.jetbrains.kotlinx.lincheck.util
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to have to Utils.kt files?

@@ -204,7 +204,7 @@ internal class LoopDetector(
// Has the thread changed? Reset the counters in this case.
check(lastExecutedThread == iThread) { "reset expected!" }
// Ignore coroutine suspension code locations.
if (codeLocation == COROUTINE_SUSPENSION_CODE_LOCATION) return Decision.Idle
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why UNKNOWN? The documentation here and of the UNKNOWN_CODE_LOCATION field says it is the coroutine suspension code location.

@eupp
Copy link
Collaborator Author

eupp commented Dec 12, 2024

From what I can see, there is no significant changes in the time of CI builds between this branch and develop:

The reason is that in this PR I strive to preserve the old behavior whenever possible, by adding special treatment of TestThread class, see an example here:

if (thread instanceof TestThread) {

Thus, all the code interacting with TestThread-s (i.e. threads create by Lincheck) should work almost the same as before, and there should be no new performance penalties for it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants