@@ -88,27 +88,7 @@ fun runUsvmGeneration(
88
88
89
89
val classpathFiles = classpathString.split(File .pathSeparator).map { File (it) }
90
90
91
- val jcContainer by lazy {
92
- JcContainer (
93
- usePersistence = false ,
94
- persistenceDir = tmpDir,
95
- classpath = classpathFiles,
96
- javaHome = JdkInfoService .provide().path.toFile(),
97
- machineOptions = UMachineOptions (
98
- // TODO usvm-sbft: if we have less than CONTEST_TEST_EXECUTION_TIMEOUT time left, we should try execute
99
- // with smaller timeout, but instrumentation currently doesn't allow to change timeout for individual runs
100
- timeout = generationTimeoutMillisWithoutCodegen.milliseconds - CONTEST_TEST_EXECUTION_TIMEOUT ,
101
- pathSelectionStrategies = listOf (PathSelectionStrategy .CLOSEST_TO_UNCOVERED_RANDOM ),
102
- pathSelectorFairnessStrategy = PathSelectorFairnessStrategy .COMPLETELY_FAIR ,
103
- solverType = SolverType .Z3 , // TODO: usvm-ksmt: Yices doesn't work on old linux
104
- )
105
- ) {
106
- // TODO usvm-sbft: we may want to tune these JcSettings for contest
107
- // TODO: require usePersistence=false for ClassScorer
108
- installFeatures(InMemoryHierarchy , Approximations , ClassScorer (TypeScorer , ::scoreClassNode))
109
- loadByteCode(classpathFiles)
110
- }
111
- }
91
+ val jcContainer by lazy { createJcContainer(tmpDir, classpathFiles) }
112
92
113
93
val executor by lazy { JcTestExecutor (jcContainer.cp, jcContainer.runner) }
114
94
@@ -127,6 +107,7 @@ fun runUsvmGeneration(
127
107
}
128
108
129
109
logger.info { " STARTED COUNTING BUDGET FOR ${cut.classId.name} " }
110
+ val budgetStartTimeMillis = System .currentTimeMillis()
130
111
131
112
if (cut.classLoader.javaClass != URLClassLoader ::class .java) {
132
113
logger.error(" Seems like classloader for cut not valid (maybe it was backported to system): ${cut.classLoader} " )
@@ -147,10 +128,10 @@ fun runUsvmGeneration(
147
128
)
148
129
)
149
130
150
- logger.info().measureTime({ " Contest preparation: ensure JacoDB is initialized (NOT counted in time budget)" }) {
131
+ logger.info().measureTime({ " Contest preparation: ensure JacoDB is initialized (counted in time budget)" }) {
151
132
jcContainer // force init lazy property
152
133
}
153
- logger.info().measureTime({ " Contest preparation: ensure executor is started (NOT counted in time budget)" }) {
134
+ logger.info().measureTime({ " Contest preparation: ensure executor is started (counted in time budget)" }) {
154
135
jcContainer.runner.ensureRunnerAlive()
155
136
}
156
137
@@ -178,60 +159,73 @@ fun runUsvmGeneration(
178
159
179
160
val timeStats = mutableMapOf<String , Long >()
180
161
181
- jcContainer.machine.analyzeAsync(
182
- forceTerminationTimeout = (generationTimeoutMillisWithoutCodegen + timeBudgetMs) / 2 ,
183
- methods = jcMethods,
184
- targets = emptyList()
185
- ) { state ->
186
- val jcExecution = accumulateMeasureTime(" executor.execute(${cut.classId.name} )" , timeStats, state.entrypoint) {
187
- runCatching {
188
- executor.execute(
189
- method = state.entrypoint.typedMethod,
190
- state = state,
191
- stringConstants = jcContainer.machine.stringConstants,
192
- classConstants = jcContainer.machine.classConstants
193
- ) ? : return @analyzeAsync
194
- }.getOrElse { e ->
195
- logger.error(e) { " executor.execute(${state.entrypoint} ) failed" }
196
- return @analyzeAsync
162
+ val alreadySpentBudgetMillis = System .currentTimeMillis() - budgetStartTimeMillis
163
+ JcMachine (
164
+ cp = jcContainer.cp,
165
+ options = UMachineOptions (
166
+ // TODO usvm-sbft: if we have less than CONTEST_TEST_EXECUTION_TIMEOUT time left, we should try execute
167
+ // with smaller timeout, but instrumentation currently doesn't allow to change timeout for individual runs
168
+ timeout = generationTimeoutMillisWithoutCodegen.milliseconds - alreadySpentBudgetMillis.milliseconds - CONTEST_TEST_EXECUTION_TIMEOUT ,
169
+ pathSelectionStrategies = listOf (PathSelectionStrategy .CLOSEST_TO_UNCOVERED_RANDOM ),
170
+ pathSelectorFairnessStrategy = PathSelectorFairnessStrategy .COMPLETELY_FAIR ,
171
+ solverType = SolverType .Z3 , // TODO: usvm-ksmt: Yices doesn't work on old linux
172
+ )
173
+ ).use { jcMachine ->
174
+ jcMachine.analyzeAsync(
175
+ forceTerminationTimeout = (generationTimeoutMillisWithoutCodegen + timeBudgetMs) / 2 - alreadySpentBudgetMillis,
176
+ methods = jcMethods,
177
+ targets = emptyList()
178
+ ) { state ->
179
+ val jcExecution = accumulateMeasureTime(" executor.execute(${cut.classId.name} )" , timeStats, state.entrypoint) {
180
+ runCatching {
181
+ executor.execute(
182
+ method = state.entrypoint.typedMethod,
183
+ state = state,
184
+ stringConstants = jcMachine.stringConstants,
185
+ classConstants = jcMachine.classConstants
186
+ ) ? : return @analyzeAsync
187
+ }.getOrElse { e ->
188
+ logger.error(e) { " executor.execute(${state.entrypoint} ) failed" }
189
+ return @analyzeAsync
190
+ }
191
+ }
192
+ val methodId = jcExecution.method.method.toExecutableId(jcContainer.cp)
193
+ val utExecution = accumulateMeasureTime(" JcToUtExecutionConverter.convert(${cut.classId.name} )" , timeStats, jcExecution.method.method) {
194
+ runCatching {
195
+ JcToUtExecutionConverter (
196
+ jcExecution = jcExecution,
197
+ jcClasspath = jcContainer.cp,
198
+ idGenerator = utModelIdGenerator,
199
+ instructionIdProvider = instructionIdGenerator,
200
+ utilMethodProvider = codeGenerator.context.utilMethodProvider
201
+ ).convert()
202
+ // for some JcExecutions like RD faults we don't construct UtExecutions, converter logs such cases
203
+ ? : return @analyzeAsync
204
+ }.getOrElse { e ->
205
+ logger.error(e) { " JcToUtExecutionConverter.convert(${jcExecution.method.method} ) failed" }
206
+ return @analyzeAsync
207
+ }
197
208
}
198
- }
199
- val methodId = jcExecution.method.method.toExecutableId(jcContainer.cp)
200
- val utExecution = accumulateMeasureTime(" JcToUtExecutionConverter.convert(${cut.classId.name} )" , timeStats, jcExecution.method.method) {
201
209
runCatching {
202
- JcToUtExecutionConverter (
203
- jcExecution = jcExecution,
204
- jcClasspath = jcContainer.cp,
205
- idGenerator = utModelIdGenerator,
206
- instructionIdProvider = instructionIdGenerator,
207
- utilMethodProvider = codeGenerator.context.utilMethodProvider
208
- ).convert()
209
- // for some JcExecutions like RD faults we don't construct UtExecutions, converter logs such cases
210
- ? : return @analyzeAsync
210
+ val className = Type .getInternalName(methodId.classId.jClass)
211
+ val statsForMethod = methodToStats.getValue(methodId)
212
+ statsForMethod.testsGeneratedCount++
213
+ utExecution.result.exceptionOrNull()?.let { exception ->
214
+ statsForMethod.detectedExceptionFqns + = exception::class .java.name
215
+ }
216
+ utExecution.coverage?.let {
217
+ statsForClass.updateCoverage(
218
+ newCoverage = it,
219
+ isNewClass = ! statsForClass.testedClassNames.contains(className),
220
+ fromFuzzing = utExecution is UtFuzzedExecution
221
+ )
222
+ }
223
+ statsForClass.testedClassNames.add(className)
224
+ testsByMethod.getOrPut(methodId) { mutableListOf () } + = utExecution
211
225
}.getOrElse { e ->
212
- logger.error(e) { " JcToUtExecutionConverter.convert(${jcExecution.method.method} ) failed" }
213
- return @analyzeAsync
226
+ logger.error(e) { " Test generation failed during stats update for $methodId " }
214
227
}
215
228
}
216
- runCatching {
217
- val className = Type .getInternalName(methodId.classId.jClass)
218
- val statsForMethod = methodToStats.getValue(methodId)
219
- statsForMethod.testsGeneratedCount++
220
- utExecution.result.exceptionOrNull()?.let { exception ->
221
- statsForMethod.detectedExceptionFqns + = exception::class .java.name
222
- }
223
- utExecution.coverage?.let {
224
- statsForClass.updateCoverage(
225
- newCoverage = it,
226
- isNewClass = ! statsForClass.testedClassNames.contains(className),
227
- fromFuzzing = utExecution is UtFuzzedExecution
228
- )
229
- }
230
- statsForClass.testedClassNames.add(className)
231
- testsByMethod.getOrPut(methodId) { mutableListOf () } + = utExecution
232
- }.getOrElse { e ->
233
- logger.error(e) { " Test generation failed during stats update for $methodId " }
234
- }
235
229
}
236
230
237
231
timeStats.forEach { (regionName, timeMillis) ->
@@ -254,6 +248,21 @@ fun runUsvmGeneration(
254
248
statsForClass
255
249
}
256
250
251
+ fun createJcContainer (
252
+ tmpDir : File ,
253
+ classpathFiles : List <File >
254
+ ) = JcContainer (
255
+ usePersistence = false ,
256
+ persistenceDir = tmpDir,
257
+ classpath = classpathFiles,
258
+ javaHome = JdkInfoService .provide().path.toFile(),
259
+ ) {
260
+ // TODO usvm-sbft: we may want to tune these JcSettings for contest
261
+ // TODO: require usePersistence=false for ClassScorer
262
+ installFeatures(InMemoryHierarchy , Approximations , ClassScorer (TypeScorer , ::scoreClassNode))
263
+ loadByteCode(classpathFiles)
264
+ }
265
+
257
266
fun JcClasspath.findMethodOrNull (method : ExecutableId ): JcMethod ? =
258
267
findClass(method.classId.name).declaredMethods.firstOrNull {
259
268
it.name == method.name && it.jcdbSignature == method.jcdbSignature
0 commit comments