mirror of
https://github.com/corda/corda.git
synced 2024-12-19 21:17:58 +00:00
Add alwaysExcluded flag to quasar-hook, run config for generating exclude pattern
This commit is contained in:
parent
605d142738
commit
e9f3b92e97
@ -0,0 +1,25 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Quasar exclude pattern extraction from node tests (need not pass, check output at the bottom of console)" type="JUnit" factoryName="JUnit">
|
||||
<module name="" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
<option name="PACKAGE_NAME" value="net.corda.node" />
|
||||
<option name="MAIN_CLASS_NAME" value="" />
|
||||
<option name="METHOD_NAME" value="" />
|
||||
<option name="TEST_OBJECT" value="package" />
|
||||
<option name="VM_PARAMETERS" value="-ea -javaagent:$PROJECT_DIR$/experimental/quasar-hook/build/libs/quasar-hook.jar="expand=com,de,org,co,io;truncate=net.corda;alwaysExcluded=com.opengamma,io.atomix" -javaagent:lib/quasar.jar -Xmx4G" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
|
||||
<option name="ENV_VARIABLES" />
|
||||
<option name="PASS_PARENT_ENVS" value="true" />
|
||||
<option name="TEST_SEARCH_SCOPE">
|
||||
<value defaultName="wholeProject" />
|
||||
</option>
|
||||
<envs />
|
||||
<dir value="$PROJECT_DIR$" />
|
||||
<patterns />
|
||||
<method>
|
||||
<option name="Gradle.BeforeRunTask" enabled="true" tasks="jar" externalProjectPath="$PROJECT_DIR$/experimental/quasar-hook" vmOptions="" scriptParameters="" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
@ -5,17 +5,30 @@ This is a javaagent that may be used while running applications using quasar. It
|
||||
methods are scanned, instrumented and used at runtime, and generates an exclude pattern that may be passed in to quasar
|
||||
to stop it from scanning classes unnecessarily.
|
||||
|
||||
Example usage
|
||||
=============
|
||||
Arguments
|
||||
===
|
||||
|
||||
`expand`, `alwaysExcluded` and `truncate` tweak the output exclude pattern. `expand` is a list of packages to always expand (for example
|
||||
instead of generating `com.*` generate `com.google.*,com.typesafe.*` etc.), `alwaysExcluded` is a list of packages under
|
||||
which all classes are considered excluded irregardless of instrumentation, `truncate` is a list of packages that should
|
||||
not be included in the exclude pattern. Truncating `net.corda` means nothing should be excluded from instrumentation in
|
||||
Corda.
|
||||
|
||||
How to generate an exclude pattern for Corda
|
||||
====
|
||||
|
||||
In order to generate a good exclude pattern we need to exercise the Corda code so that most classes get loaded and
|
||||
inspected by quasar and quasar-hook. For this we can run tests using the 'Quasar exclude pattern extraction (...)'
|
||||
intellij run configuration, which includes the hook. In addition we should run the tool on a bare corda.jar, as some
|
||||
additional classes are used when the jar is invoked directly. To do this we'll use a node in samples:
|
||||
|
||||
```
|
||||
./gradlew experimental:quasar-hook:jar
|
||||
java -javaagent:experimental/quasar-hook/build/libs/quasar-hook.jar="expand=com,de,org,co;truncate=net.corda" -jar path/to/corda.jar
|
||||
./gradlew samples:irs-demo:deployNodes
|
||||
cd samples/irs-demo/build/nodes/NotaryService
|
||||
java -javaagent:../../../../../experimental/quasar-hook/build/libs/quasar-hook.jar=expand=com,de,org,co,io;truncate=net.corda;alwaysExcluded=com.opengamma,io.atomix -jar corda.jar
|
||||
```
|
||||
|
||||
The above will run corda.jar and on exit will print information about what classes were scanned/instrumented.
|
||||
Once the node is started just exit the node.
|
||||
|
||||
`expand` and `truncate` tweak the output exclude pattern. `expand` is a list of packages to always expand (for example
|
||||
instead of generating `com.*` generate `com.google.*,com.typesafe.*` etc.), `truncate` is a list of packages that should
|
||||
not be included in the exclude pattern. Truncating `net.corda` means nothing should be excluded from instrumentation in
|
||||
Corda.
|
||||
We can take the union of the two generated exclude patterns to get a final one.
|
@ -7,14 +7,15 @@ import java.lang.instrument.ClassFileTransformer
|
||||
import java.lang.instrument.Instrumentation
|
||||
import java.security.ProtectionDomain
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
/**
|
||||
* Used to collect classes through instrumentation.
|
||||
*/
|
||||
class ClassRecorder {
|
||||
val usedInstrumentedClasses = HashSet<String>()
|
||||
val instrumentedClasses = HashSet<String>()
|
||||
val scannedClasses = HashSet<String>()
|
||||
val usedInstrumentedClasses = ConcurrentHashMap<String, Unit>()
|
||||
val instrumentedClasses = ConcurrentHashMap<String, Unit>()
|
||||
val scannedClasses = ConcurrentHashMap<String, Unit>()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -39,13 +40,12 @@ fun recordUsedInstrumentedCallStack() {
|
||||
index++
|
||||
}
|
||||
index++
|
||||
while (true) {
|
||||
require (index < throwable.stackTrace.size) { "Can't find Fiber call" }
|
||||
while (index < throwable.stackTrace.size) {
|
||||
val stackElement = throwable.stackTrace[index]
|
||||
if (stackElement.className.startsWith("co.paralleluniverse")) {
|
||||
break
|
||||
}
|
||||
classRecorder.usedInstrumentedClasses.add(stackElement.className)
|
||||
classRecorder.usedInstrumentedClasses[stackElement.className] = Unit
|
||||
index++
|
||||
}
|
||||
}
|
||||
@ -55,7 +55,7 @@ fun recordUsedInstrumentedCallStack() {
|
||||
* instrumentation will happen.
|
||||
*/
|
||||
fun recordInstrumentedClass(className: String) {
|
||||
classRecorder.instrumentedClasses.add(className)
|
||||
classRecorder.instrumentedClasses[className] = Unit
|
||||
}
|
||||
|
||||
/**
|
||||
@ -63,7 +63,7 @@ fun recordInstrumentedClass(className: String) {
|
||||
*/
|
||||
fun recordScannedClass(className: String?) {
|
||||
if (className != null) {
|
||||
classRecorder.scannedClasses.add(className)
|
||||
classRecorder.scannedClasses[className] = Unit
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,11 +74,13 @@ fun recordScannedClass(className: String?) {
|
||||
* @param expand A comma-separated list of packages to expand in the glob output. This is useful for certain top-level
|
||||
* domains that we don't want to completely exclude, because later on classes may be loaded from those namespaces
|
||||
* that require instrumentation.
|
||||
* @param alwaysExcluded A comma-separated list of packages under which all touched classes will be excluded.
|
||||
* @param separator The package part separator character used in the above lists.
|
||||
*/
|
||||
data class Arguments(
|
||||
val truncate: List<String>? = null,
|
||||
val expand: List<String>? = null,
|
||||
val alwaysExcluded: List<String>? = null,
|
||||
val separator: Char = '.'
|
||||
)
|
||||
|
||||
@ -98,6 +100,7 @@ class QuasarInstrumentationHookAgent {
|
||||
when (key) {
|
||||
"truncate" -> arguments = arguments.copy(truncate = value.split(","))
|
||||
"expand" -> arguments = arguments.copy(expand = value.split(","))
|
||||
"alwaysExcluded" -> arguments = arguments.copy(alwaysExcluded = value.split(","))
|
||||
"separator" -> arguments = arguments.copy(separator = value.toCharArray()[0])
|
||||
}
|
||||
}
|
||||
@ -113,19 +116,21 @@ class QuasarInstrumentationHookAgent {
|
||||
println(" $it")
|
||||
}
|
||||
println("Scanned classes: ${classRecorder.scannedClasses.size}")
|
||||
classRecorder.scannedClasses.take(20).forEach {
|
||||
classRecorder.scannedClasses.keys.take(20).forEach {
|
||||
println(" $it")
|
||||
}
|
||||
println(" (...)")
|
||||
val scannedTree = PackageTree.fromStrings(classRecorder.scannedClasses.toList(), '/')
|
||||
val instrumentedTree = PackageTree.fromStrings(classRecorder.instrumentedClasses.toList(), '/')
|
||||
val scannedTree = PackageTree.fromStrings(classRecorder.scannedClasses.keys.toList(), '/')
|
||||
val instrumentedTree = PackageTree.fromStrings(classRecorder.instrumentedClasses.keys.toList(), '/')
|
||||
val alwaysExclude = arguments.alwaysExcluded?.let { PackageTree.fromStrings(it, arguments.separator) }
|
||||
val alwaysExcludedTree = alwaysExclude?.let { instrumentedTree.truncate(it) } ?: instrumentedTree
|
||||
println("Suggested exclude globs:")
|
||||
val truncate = arguments.truncate?.let { PackageTree.fromStrings(it, arguments.separator) }
|
||||
// The separator append is a hack, it causes a package with an empty name to be added to the exclude tree,
|
||||
// which practically causes that level of the tree to be always expanded in the output globs.
|
||||
val expand = arguments.expand?.let { PackageTree.fromStrings(it.map { "$it${arguments.separator}" }, arguments.separator) }
|
||||
val truncatedTree = truncate?.let { scannedTree.truncate(it)} ?: scannedTree
|
||||
val expandedTree = expand?.let { instrumentedTree.merge(it) } ?: instrumentedTree
|
||||
val expandedTree = expand?.let { alwaysExcludedTree.merge(it) } ?: alwaysExcludedTree
|
||||
val globs = truncatedTree.toGlobs(expandedTree)
|
||||
globs.forEach {
|
||||
println(" $it")
|
||||
|
@ -36,7 +36,8 @@ task buildCordaJAR(type: FatCapsule, dependsOn: project(':node').compileJava) {
|
||||
capsuleManifest {
|
||||
applicationVersion = corda_release_version
|
||||
appClassPath = ["jolokia-agent-war-${project.rootProject.ext.jolokia_version}.war"]
|
||||
def quasarExcludeExpression = "x(rx**;io**;antlr**;kotlin**;jdk**;reflectasm**;groovyjarjarasm**;groovy**;joptsimple**;groovyjarjarantlr**;com.fasterxml**;com.typesafe**;com.google**;com.zaxxer**;com.jcabi**;com.codahale**;com.esotericsoftware**;de.javakaffee**;org.objectweb**;org.slf4j**;org.w3c**;org.codehaus**;org.crsh**;org.fusesource**;org.h2**;org.hibernate**;org.dom4j**;org.bouncycastle**;org.apache**;org.objenesis**;org.jboss**;org.jcp**;org.xml**;co.paralleluniverse**;net.i2p**)"
|
||||
// See experimental/quasar-hook/README.md for how to generate.
|
||||
def quasarExcludeExpression = "x(antlr**;bftsmart**;ch**;co.paralleluniverse**;com.codahale**;com.esotericsoftware**;com.fasterxml**;com.google**;com.ibm**;com.intellij**;com.jcabi**;com.nhaarman**;com.opengamma**;com.typesafe**;com.zaxxer**;de.javakaffee**;groovy**;groovyjarjarantlr**;groovyjarjarasm**;io.atomix**;io.github**;io.netty**;jdk**;joptsimple**;junit**;kotlin**;net.bytebuddy**;net.i2p**;org.apache**;org.assertj**;org.bouncycastle**;org.codehaus**;org.crsh**;org.dom4j**;org.fusesource**;org.h2**;org.hamcrest**;org.hibernate**;org.jboss**;org.jcp**;org.joda**;org.junit**;org.mockito**;org.objectweb**;org.objenesis**;org.slf4j**;org.w3c**;org.xml**;org.yaml**;reflectasm**;rx**)"
|
||||
javaAgents = ["quasar-core-${quasar_version}-jdk8.jar=${quasarExcludeExpression}"]
|
||||
systemProperties['visualvm.display.name'] = 'Corda'
|
||||
minJavaVersion = '1.8.0'
|
||||
|
@ -801,7 +801,8 @@ class DriverDSL(
|
||||
"net.corda.node.cordapp.scan.package" to callerPackage,
|
||||
"java.io.tmpdir" to System.getProperty("java.io.tmpdir") // Inherit from parent process
|
||||
)
|
||||
val excludePattern = "x(rx**;io**;antlr**;kotlin**;jdk**;reflectasm**;groovyjarjarasm**;groovy**;joptsimple**;groovyjarjarantlr**;com.fasterxml**;com.typesafe**;com.google**;com.zaxxer**;com.jcabi**;com.codahale**;com.esotericsoftware**;de.javakaffee**;org.objectweb**;org.slf4j**;org.w3c**;org.codehaus**;org.crsh**;org.fusesource**;org.h2**;org.hibernate**;org.dom4j**;org.bouncycastle**;org.apache**;org.objenesis**;org.jboss**;org.jcp**;org.xml**;co.paralleluniverse**;net.i2p**)"
|
||||
// See experimental/quasar-hook/README.md for how to generate.
|
||||
val excludePattern = "x(antlr**;bftsmart**;ch**;co.paralleluniverse**;com.codahale**;com.esotericsoftware**;com.fasterxml**;com.google**;com.ibm**;com.intellij**;com.jcabi**;com.nhaarman**;com.opengamma**;com.typesafe**;com.zaxxer**;de.javakaffee**;groovy**;groovyjarjarantlr**;groovyjarjarasm**;io.atomix**;io.github**;io.netty**;jdk**;joptsimple**;junit**;kotlin**;net.bytebuddy**;net.i2p**;org.apache**;org.assertj**;org.bouncycastle**;org.codehaus**;org.crsh**;org.dom4j**;org.fusesource**;org.h2**;org.hamcrest**;org.hibernate**;org.jboss**;org.jcp**;org.joda**;org.junit**;org.mockito**;org.objectweb**;org.objenesis**;org.slf4j**;org.w3c**;org.xml**;org.yaml**;reflectasm**;rx**)"
|
||||
val extraJvmArguments = systemProperties.map { "-D${it.key}=${it.value}" } +
|
||||
"-javaagent:$quasarJarPath=$excludePattern"
|
||||
val loggingLevel = if (debugPort == null) "INFO" else "DEBUG"
|
||||
|
Loading…
Reference in New Issue
Block a user