Skip to content

Commit 5d77c28

Browse files
committed
[instrumentation-rd]
review & bug fixes, removed rd-gen from dependencies and moved rdgen generator to utbot-rd project
1 parent 947a983 commit 5d77c28

File tree

16 files changed

+181
-172
lines changed

16 files changed

+181
-172
lines changed

gradle.properties

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,5 @@ shadow_jar_version=7.1.2
4848

4949
org.gradle.daemon=false
5050
org.gradle.parallel=false
51-
org.gradle.jvmargs="-XX:MaxHeapSize=3072m"
52-
kotlin.compiler.execution.strategy=in-process
53-
54-
org.gradle.jvmargs=-Xmx6144m
55-
#kotlin.stdlib.default.dependency=false
51+
org.gradle.jvmargs=-Xmx6144m -XX:MaxHeapSize=3072m
52+
kotlin.compiler.execution.strategy=in-process

utbot-framework/build.gradle

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ dependencies {
3535
api project(':utbot-framework-api')
3636

3737
implementation group: 'com.jetbrains.rd', name: 'rd-framework', version: '2022.3.1'
38-
implementation group: 'com.jetbrains.rd', name: 'rd-gen', version: '2022.3.1'
3938
implementation group: 'com.jetbrains.rd', name: 'rd-core', version: '2022.3.1'
4039

4140
implementation "com.github.UnitTestBot:soot:${soot_commit_hash}"

utbot-instrumentation-tests/build.gradle

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ dependencies {
1717
testImplementation project(':utbot-sample')
1818
testImplementation group: 'org.jacoco', name: 'org.jacoco.report', version: jacoco_version
1919
implementation group: 'com.jetbrains.rd', name: 'rd-framework', version: '2022.3.1'
20-
implementation group: 'com.jetbrains.rd', name: 'rd-gen', version: '2022.3.1'
2120
implementation group: 'com.jetbrains.rd', name: 'rd-core', version: '2022.3.1'
2221
}
2322

utbot-instrumentation/build.gradle

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
import com.jetbrains.rd.generator.gradle.RdGenExtension
2-
import com.jetbrains.rd.generator.gradle.RdGenTask
3-
4-
plugins {
5-
id 'com.jetbrains.rdgen' version "2022.3.1"
6-
}
71
apply from: "${parent.projectDir}/gradle/include/jvm-project.gradle"
82

93
dependencies {
@@ -18,11 +12,8 @@ dependencies {
1812
implementation group: 'io.github.microutils', name: 'kotlin-logging', version: kotlin_logging_version
1913

2014
implementation group: 'com.jetbrains.rd', name: 'rd-framework', version: '2022.3.1'
21-
implementation group: 'com.jetbrains.rd', name: 'rd-gen', version: '2022.3.1'
2215
implementation group: 'com.jetbrains.rd', name: 'rd-core', version: '2022.3.1'
2316

24-
implementation group: 'net.java.dev.jna', name: 'jna-platform', version: '5.5.0'
25-
2617

2718
// TODO: this is necessary for inline classes mocking in UtExecutionInstrumentation
2819
implementation group: 'org.mockito', name: 'mockito-core', version: '4.2.0'
@@ -68,29 +59,4 @@ configurations {
6859

6960
artifacts {
7061
instrumentationArchive jar
71-
}
72-
73-
def repoRoot = project.projectDir
74-
def hashBaseDir = new File(repoRoot, "build/rdgen")
75-
def rdBaseDir = new File(repoRoot, "src/main/kotlin/org/utbot/instrumentation/rd")
76-
def rdOutputDir = new File(rdBaseDir, "generated")
77-
78-
task generateProtocolModels(type: RdGenTask) {
79-
group = "rdgen"
80-
// todo which extensions
81-
def rdParams = extensions.getByName("params") as RdGenExtension
82-
rdParams.verbose = true
83-
84-
rdParams.sources(new File(rdBaseDir, "models"))
85-
rdParams.hashFolder = new File(hashBaseDir, "models").canonicalPath
86-
rdParams.packages = "org.utbot.instrumentation.rd.models"
87-
88-
rdParams.generator {
89-
language = "kotlin"
90-
transform = "symmetric"
91-
root = "org.utbot.instrumentation.rd.models.ProtocolRoot"
92-
93-
directory = rdOutputDir.canonicalPath
94-
namespace = "org.utbot.instrumentation.rd.generated"
95-
}
9662
}

utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/ConcreteExecutor.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,15 @@ class ConcreteExecutor<TIResult, TInstrumentation : Instrumentation<TIResult>> p
168168

169169
return proc!!
170170
}
171+
172+
/**
173+
* Main entry point for communicating with child process.
174+
* Use this function every time you want to access protocol model.
175+
* This method prepares child process for execution and ensures it is alive before giving it block
176+
*
177+
* @param exclusively if true - executes block under mutex.
178+
* This guarantees that no one can access protocol model - no other calls made before block completes
179+
*/
171180
suspend fun <T> withProcess(exclusively: Boolean = false, block: suspend UtInstrumentationProcess.() -> T): T {
172181
fun throwConcreteIfDead(e: Throwable, proc: UtInstrumentationProcess?) {
173182
if (proc?.lifetime?.isAlive != true) {

utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/ChildProcess.kt

Lines changed: 62 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.utbot.instrumentation.process
22

3+
import com.jetbrains.rd.framework.*
34
import com.jetbrains.rd.framework.util.launchChild
45
import com.jetbrains.rd.util.ILoggerFactory
56
import com.jetbrains.rd.util.LogLevel
@@ -17,11 +18,11 @@ import org.utbot.instrumentation.instrumentation.coverage.CoverageInstrumentatio
1718
import org.utbot.instrumentation.rd.childCreatedFileName
1819
import org.utbot.instrumentation.rd.generated.CollectCoverageResult
1920
import org.utbot.instrumentation.rd.generated.InvokeMethodCommandResult
21+
import org.utbot.instrumentation.rd.generated.ProtocolModel
2022
import org.utbot.instrumentation.rd.obtainClientIO
2123
import org.utbot.instrumentation.rd.processSyncDirectory
2224
import org.utbot.instrumentation.rd.signalChildReady
2325
import org.utbot.instrumentation.util.KryoHelper
24-
import org.utbot.rd.UtRdUtil
2526
import org.utbot.rd.UtSingleThreadScheduler
2627
import java.io.File
2728
import java.io.OutputStream
@@ -86,6 +87,7 @@ private fun logTrace(any: () -> Any?) {
8687
private val executionStart = AtomicLong(1)
8788
private val executionEnd = AtomicLong(0)
8889
private const val messageFromMainTimeoutMillis = 120 * 1000
90+
private const val delayTimeoutMillis = 1000L
8991

9092
/**
9193
* It should be compiled into separate jar file (child_process.jar) and be run with an agent (agent.jar) option.
@@ -111,7 +113,7 @@ suspend fun main(args: Array<String>) {
111113
val end = executionEnd.get()
112114

113115
if (start > end) { // process is doing something
114-
delay(1000)
116+
delay(delayTimeoutMillis)
115117
} else { // process is waiting for message
116118
if (now - end > messageFromMainTimeoutMillis) {
117119
logInfo { "terminating lifetime" }
@@ -154,49 +156,16 @@ private lateinit var pathsToUserClasses: Set<String>
154156
private lateinit var pathsToDependencyClasses: Set<String>
155157
private lateinit var instrumentation: Instrumentation<*>
156158

157-
private suspend fun initiate(lifetime: Lifetime, port: Int, pid: Int) {
158-
// We don't want user code to litter the standard output, so we redirect it.
159-
val tmpStream = PrintStream(object : OutputStream() {
160-
override fun write(b: Int) {}
161-
})
162-
System.setOut(tmpStream)
163-
164-
Logger.set(lifetime, object : ILoggerFactory {
165-
override fun getLogger(category: String) = object : Logger {
166-
override fun isEnabled(level: LogLevel): Boolean {
167-
return level >= logLevel
168-
}
169-
170-
override fun log(level: LogLevel, message: Any?, throwable: Throwable?) {
171-
val msg = defaultLogFormat(category, level, message, throwable)
172-
173-
log(logLevel) { msg }
174-
}
175-
176-
}
177-
})
178-
179-
val def = CompletableDeferred<Unit>()
180-
lifetime.onTermination { def.complete(Unit) }
181-
val kryoHelper = KryoHelper(lifetime)
182-
logInfo { "kryo created" }
183-
184-
val clientProtocol = UtRdUtil.createUtClientProtocol(lifetime, port, UtSingleThreadScheduler { logInfo(it) })
185-
logInfo {
186-
"heartbeatAlive - ${clientProtocol.wire.heartbeatAlive.value}, connected - ${
187-
clientProtocol.wire.connected.value
188-
}"
189-
}
190-
val (sync, protocolModel) = obtainClientIO(lifetime, clientProtocol)
191-
protocolModel.warmup.set { _ ->
159+
fun ProtocolModel.setup(kryoHelper: KryoHelper, onStop: () -> Unit) {
160+
warmup.set { _ ->
192161
measureExecutionForTermination {
193162
val time = measureTimeMillis {
194163
HandlerClassesLoader.scanForClasses("").toList() // here we transform classes
195164
}
196165
logInfo { "warmup finished in $time ms" }
197166
}
198167
}
199-
protocolModel.invokeMethodCommand.set { params ->
168+
invokeMethodCommand.set { params ->
200169
measureExecutionForTermination {
201170
val clazz = HandlerClassesLoader.loadClass(params.classname)
202171
val res = instrumentation.invoke(
@@ -210,15 +179,15 @@ private suspend fun initiate(lifetime: Lifetime, port: Int, pid: Int) {
210179
InvokeMethodCommandResult(kryoHelper.writeObject(res))
211180
}
212181
}
213-
protocolModel.setInstrumentation.set { params ->
182+
setInstrumentation.set { params ->
214183
measureExecutionForTermination {
215184
instrumentation = kryoHelper.readObject(params.instrumentation)
216185
Agent.dynamicClassTransformer.transformer = instrumentation // classTransformer is set
217186
Agent.dynamicClassTransformer.addUserPaths(pathsToUserClasses)
218187
instrumentation.init(pathsToUserClasses)
219188
}
220189
}
221-
protocolModel.addPaths.set { params ->
190+
addPaths.set { params ->
222191
measureExecutionForTermination {
223192
pathsToUserClasses = params.pathsToUserClasses.split(File.pathSeparatorChar).toSet()
224193
pathsToDependencyClasses = params.pathsToDependencyClasses.split(File.pathSeparatorChar).toSet()
@@ -231,18 +200,67 @@ private suspend fun initiate(lifetime: Lifetime, port: Int, pid: Int) {
231200
UtContext.setUtContext(UtContext(HandlerClassesLoader))
232201
}
233202
}
234-
protocolModel.stopProcess.set { _ ->
203+
stopProcess.set { _ ->
235204
measureExecutionForTermination {
236-
def.complete(Unit)
205+
onStop()
237206
}
238207
}
239-
protocolModel.collectCoverage.set { params ->
208+
collectCoverage.set { params ->
240209
measureExecutionForTermination {
241210
val anyClass: Class<*> = kryoHelper.readObject(params.clazz)
242211
val result = (instrumentation as CoverageInstrumentation).collectCoverageInfo(anyClass)
243212
CollectCoverageResult(kryoHelper.writeObject(result))
244213
}
245214
}
215+
216+
}
217+
218+
private suspend fun initiate(lifetime: Lifetime, port: Int, pid: Int) {
219+
// We don't want user code to litter the standard output, so we redirect it.
220+
val tmpStream = PrintStream(object : OutputStream() {
221+
override fun write(b: Int) {}
222+
})
223+
System.setOut(tmpStream)
224+
225+
Logger.set(lifetime, object : ILoggerFactory {
226+
override fun getLogger(category: String) = object : Logger {
227+
override fun isEnabled(level: LogLevel): Boolean {
228+
return level >= logLevel
229+
}
230+
231+
override fun log(level: LogLevel, message: Any?, throwable: Throwable?) {
232+
val msg = defaultLogFormat(category, level, message, throwable)
233+
234+
log(logLevel) { msg }
235+
}
236+
237+
}
238+
})
239+
240+
val deferred = CompletableDeferred<Unit>()
241+
lifetime.onTermination { deferred.complete(Unit) }
242+
val kryoHelper = KryoHelper(lifetime)
243+
logInfo { "kryo created" }
244+
245+
val scheduler = UtSingleThreadScheduler { logInfo(it) }
246+
val clientProtocol = Protocol(
247+
"ChildProcess",
248+
Serializers(),
249+
Identities(IdKind.Client),
250+
scheduler,
251+
SocketWire.Client(lifetime, scheduler, port),
252+
lifetime
253+
)
254+
logInfo {
255+
"heartbeatAlive - ${clientProtocol.wire.heartbeatAlive.value}, connected - ${
256+
clientProtocol.wire.connected.value
257+
}"
258+
}
259+
val (sync, protocolModel) = obtainClientIO(lifetime, clientProtocol)
260+
261+
protocolModel.setup(kryoHelper) {
262+
deferred.complete(Unit)
263+
}
246264
signalChildReady(pid)
247265
logInfo { "IO obtained" }
248266

@@ -257,7 +275,7 @@ private suspend fun initiate(lifetime: Lifetime, port: Int, pid: Int) {
257275
if (latch.await(messageFromMainTimeoutMillis.toLong(), TimeUnit.MILLISECONDS)) {
258276
logInfo { "starting instrumenting" }
259277
try {
260-
def.await()
278+
deferred.await()
261279
} catch (e: Throwable) {
262280
logError { "Terminating process because exception occurred: ${e.stackTraceToString()}" }
263281
}

utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/ChildProcessRunner.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class ChildProcessRunner {
4949
}
5050

5151
val directory = WorkingDirService.provide().toFile()
52-
val processBuilder = ProcessBuilder(cmds + " " + portArgument).redirectError(errorLogFile).directory(directory)
52+
val processBuilder = ProcessBuilder(cmds + portArgument).redirectError(errorLogFile).directory(directory)
5353

5454
return processBuilder.start().also {
5555
logger.debug { "Process started with PID=${it.pid()}" }

utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/rd/UtInstrumentationProcess.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import org.utbot.instrumentation.rd.generated.SetInstrumentationParams
1515
import org.utbot.instrumentation.rd.generated.protocolModel
1616
import org.utbot.instrumentation.util.KryoHelper
1717
import org.utbot.rd.ProcessWithRdServer
18-
import org.utbot.rd.UtRdUtil
18+
import org.utbot.rd.startUtProcessWithRdServer
1919
import java.io.File
2020
import java.nio.file.Files
2121
import java.util.concurrent.atomic.AtomicBoolean
@@ -98,7 +98,7 @@ class UtInstrumentationProcess private constructor(
9898
pathsToDependencyClasses: String,
9999
classLoader: ClassLoader?
100100
): UtInstrumentationProcess {
101-
val rdProcess: ProcessWithRdServer = UtRdUtil.startUtProcessWithRdServer(
101+
val rdProcess: ProcessWithRdServer = startUtProcessWithRdServer(
102102
parent = parent
103103
) {
104104
childProcessRunner.start(it)

utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/util/InstrumentationException.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ class ReadingFromKryoException(e: Throwable) :
2424
class WritingToKryoException(e: Throwable) :
2525
InstrumentationException("Writing to Kryo exception |> ${e.stackTraceToString()}", e)
2626

27-
// this exception is thrown only in main process.
28-
// currently it means that {e: Throwable} happened in child process,
29-
// but child process still can operate and not dead.
30-
// on child process death - ConcreteExecutionFailureException is thrown
27+
/**
28+
* this exception is thrown only in main process.
29+
* currently it means that {e: Throwable} happened in child process,
30+
* but child process still can operate and not dead.
31+
* on child process death - ConcreteExecutionFailureException is thrown
32+
*/
3133
class ChildProcessError(e: Throwable) :
3234
InstrumentationException("Error in the child process |> ${e.stackTraceToString()}", e)

utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/util/KryoHelper.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,14 @@ class KryoHelper internal constructor(
3838
receiveKryo.classLoader = classLoader
3939
}
4040

41+
/**
42+
* Serializes object to ByteArray
43+
*
44+
* @throws WritingToKryoException wraps all exceptions
45+
*/
4146
fun <T> writeObject(obj: T): ByteArray {
4247
lifetime.throwIfNotAlive()
4348
try {
44-
4549
sendKryo.writeClassAndObject(kryoOutput, obj)
4650
kryoOutput.flush()
4751

@@ -54,6 +58,11 @@ class KryoHelper internal constructor(
5458
}
5559
}
5660

61+
/**
62+
* Deserializes object form ByteArray
63+
*
64+
* @throws ReadingFromKryoException wraps all exceptions
65+
*/
5766
fun <T> readObject(byteArray: ByteArray): T {
5867
lifetime.throwIfNotAlive()
5968
return try {

0 commit comments

Comments
 (0)