Skip to content

Commit

Permalink
Redirect logs to stdout in replay mode and introduce deterministic Th…
Browse files Browse the repository at this point in the history
…readLocalRandom (#35)

* Print logs to console in replay mode.

* Redirect logs to stdout in replay mode.
  • Loading branch information
aoli-al authored Aug 27, 2024
1 parent eabbd5b commit 2467497
Show file tree
Hide file tree
Showing 10 changed files with 82 additions and 17 deletions.
16 changes: 11 additions & 5 deletions core/src/main/kotlin/org/pastalab/fray/core/RunContext.kt
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,11 @@ class RunContext(val config: Configuration) {
if (config.exploreMode || config.noExitWhenBugFound) {
return
}
logger.error("Error found, the recording is saved to ${config.report}/recording_0/")
println("Error found, you may find the error report in ${config.report}")
config.saveToReportFolder(0)
if (!config.isReplay) {
logger.error("Error found, the recording is saved to ${config.report}/recording_0/")
println("Error found, you may find the error report in ${config.report}")
config.saveToReportFolder(0)
}
exitProcess(0)
}
}
Expand Down Expand Up @@ -160,7 +162,7 @@ class RunContext(val config: Configuration) {
mainExiting = false
currentThreadId = t.id
mainThreadId = t.id
registeredThreads[t.id] = ThreadContext(t, registeredThreads.size)
registeredThreads[t.id] = ThreadContext(t, registeredThreads.size, this)
registeredThreads[t.id]?.state = ThreadState.Enabled
scheduleNextOperation(true)
}
Expand All @@ -186,7 +188,7 @@ class RunContext(val config: Configuration) {
originalHanlder?.uncaughtException(t, e)
}
t.setUncaughtExceptionHandler(handler)
registeredThreads[t.id] = ThreadContext(t, registeredThreads.size)
registeredThreads[t.id] = ThreadContext(t, registeredThreads.size, this)
syncManager.createWait(t, 1)
}

Expand Down Expand Up @@ -903,4 +905,8 @@ class RunContext(val config: Configuration) {
}
return forkJoinPool!!
}

fun getThreadLocalRandomProbe(): Int {
return registeredThreads[Thread.currentThread().id]!!.localRandomProbe
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -773,4 +773,11 @@ class RuntimeDelegate(val context: RunContext) : org.pastalab.fray.runtime.Deleg
entered.set(false)
return pool
}

override fun onThreadLocalRandomGetProbe(probe: Int): Int {
if (checkEntered()) return probe
val probe = context.getThreadLocalRandomProbe()
entered.set(false)
return probe
}
}
4 changes: 4 additions & 0 deletions core/src/main/kotlin/org/pastalab/fray/core/TestRunner.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class TestRunner(val config: Configuration) {
}

fun reportProgress(iteration: Int, bugsFound: Int) {
if (config.isReplay) return
if (iteration % currentDivision == 0) {
print("\u001B[2J")
print("\u001B[2H")
Expand Down Expand Up @@ -89,6 +90,9 @@ class TestRunner(val config: Configuration) {
println(
"Error found at iter: $i, Elapsed time: ${(timeSource.markNow() - start).inWholeMilliseconds}ms",
)
if (config.isReplay) {
break
}
logger.error("Error found, the recording is saved to ${config.report}/recording_$i/")
if (!config.exploreMode) {
config.saveToReportFolder(i)
Expand Down
3 changes: 2 additions & 1 deletion core/src/main/kotlin/org/pastalab/fray/core/ThreadContext.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ enum class ThreadState {
Completed,
}

class ThreadContext(val thread: Thread, val index: Int) {
class ThreadContext(val thread: Thread, val index: Int, context: RunContext) {
val localRandomProbe = context.config.randomnessProvider.nextInt()
var state = ThreadState.Paused
var unparkSignaled = false
var interruptSignaled = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,13 +243,17 @@ data class Configuration(
val builder = ConfigurationBuilderFactory.newConfigurationBuilder()
builder.setConfigurationName("Fray")
builder.setLoggerContext(LoggerContext("Fray"))
val appender =
builder
.newAppender("log", "File")
.addAttribute("fileName", "${report}/fray.log")
.addAttribute("append", false)
val standard = builder.newLayout("PatternLayout")
standard.addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable")
val appender =
if (isReplay) {
builder.newAppender("log", "Console").addAttribute("target", "SYSTEM_OUT").add(standard)
} else {
builder
.newAppender("log", "File")
.addAttribute("fileName", "${report}/fray.log")
.addAttribute("append", false)
}
appender.add(standard)
builder.add(appender)
val logger = builder.newLogger("org.pastalab.fray", "INFO")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ class ScheduleVerifier(val schedules: List<ScheduleRecording>) : ScheduleObserve
val enabled = enabledSchedules.map { it.index }.toList()
val operation = scheduled.pendingOperation.toString()
if (recording.scheduled != scheduledIndex) {
// throw IllegalStateException(
// "Scheduled index mismatch: expected ${recording.scheduled}, got $scheduledIndex")
throw IllegalStateException(
"Scheduled index mismatch: expected ${recording.scheduled}, got $scheduledIndex")
}
if (recording.enabled != enabled) {
// throw IllegalStateException(
// "Enabled schedules mismatch: expected ${recording.enabled}, got $enabled")
throw IllegalStateException(
"Enabled schedules mismatch: expected ${recording.enabled}, got $enabled")
}
if (recording.operation != operation) {
// throw IllegalStateException(
// "Operation mismatch: expected ${recording.operation}, got $operation")
throw IllegalStateException(
"Operation mismatch: expected ${recording.operation}, got $operation")
}
index++
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ fun instrumentClass(path: String, inputStream: InputStream): ByteArray {
cv = CountDownLatchInstrumenter(cv)
cv = MethodHandleNativesInstrumenter(cv)
cv = TimedWaitInstrumenter(cv)
cv = ThreadLocalRandomInstrumenter(cv)
// MonitorInstrumenter should come second because ObjectInstrumenter will insert more
// monitors.
cv = MonitorInstrumenter(cv)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.pastalab.fray.instrumentation.base.visitors

import java.util.concurrent.ThreadLocalRandom
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.MethodVisitor
import org.pastalab.fray.runtime.Runtime

class ThreadLocalRandomInstrumenter(cv: ClassVisitor) :
ClassVisitorBase(cv, ThreadLocalRandom::class.java.name) {
override fun instrumentMethod(
mv: MethodVisitor,
access: Int,
name: String,
descriptor: String,
signature: String?,
exceptions: Array<out String>?
): MethodVisitor {
if (name == "getProbe") {
return MethodExitVisitor(
mv,
Runtime::onThreadLocalRandomGetProbe,
access,
name,
descriptor,
false,
false,
false,
)
}
return mv
}
}
4 changes: 4 additions & 0 deletions runtime/src/main/java/org/pastalab/fray/runtime/Delegate.java
Original file line number Diff line number Diff line change
Expand Up @@ -277,5 +277,9 @@ public int onObjectHashCode(Object t) {
public ForkJoinPool onForkJoinPoolCommonPool(ForkJoinPool pool) {
return pool;
}

public int onThreadLocalRandomGetProbe(int probe) {
return probe;
}
}

6 changes: 6 additions & 0 deletions runtime/src/main/java/org/pastalab/fray/runtime/Runtime.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
Expand Down Expand Up @@ -366,4 +367,9 @@ public static int onObjectHashCode(Object t) {
public static ForkJoinPool onForkJoinPoolCommonPool(ForkJoinPool pool) {
return DELEGATE.onForkJoinPoolCommonPool(pool);
}

public static int onThreadLocalRandomGetProbe(int probe) {
return DELEGATE.onThreadLocalRandomGetProbe(probe);
}

}

0 comments on commit 2467497

Please sign in to comment.