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

Add cross-target compiler plugin option #127

Merged
merged 3 commits into from
Jul 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions docs/user-guide/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,14 @@ lazy val myproject = project
There are several compiler plugin options to enable to enrichment of analysis capabilities.
All the following options are prepended by the `-P:scalac-profiling:`.

| Name | Description |
|:-----------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `generate-global-flamegraph` | Creates a global flamegraph of implicit searches for all compilation units. Use the `-P:scalac-profiling:sourceroot` option to manage the root directory, otherwise, a working directory (defined by the `user.dir` property) will be picked. |
| `generate-macro-flamegraph` | Generate a flamegraph for macro expansions. The flamegraph for implicit searches is enabled by default. |
| `generate-profiledb` | Generate profiledb. |
| `print-failed-implicit-macro-candidates` | Print trees of all failed implicit searches that triggered a macro expansion. |
| `print-search-result` | Print the result retrieved by an implicit search. Example: `-P:scalac-profiling:print-search-result:$MACRO_ID`. |
| `show-concrete-implicit-tparams` | Use more concrete type parameters in the implicit search flamegraph. Note that it may change the shape of the flamegraph. |
| `show-profiles` | Show implicit searches and macro expansions by type and call-site. |
| `sourceroot` | Tell the plugin what is the source directory of the project. Example: `-P:scalac-profiling:sourceroot:$PROJECT_BASE_DIR`. |
| Name | Description |
|:-----------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `generate-global-flamegraph` | Creates a global flamegraph of implicit searches for all compilation units. Use the `-P:scalac-profiling:cross-target` option to manage the target directory for the resulting flamegraph file, otherwise, the SBT target directory will be picked. |
| `generate-macro-flamegraph` | Generate a flamegraph for macro expansions. The flamegraph for implicit searches is enabled by default. |
| `generate-profiledb` | Generate profiledb. |
| `print-failed-implicit-macro-candidates` | Print trees of all failed implicit searches that triggered a macro expansion. |
| `print-search-result` | Print the result retrieved by an implicit search. Example: `-P:scalac-profiling:print-search-result:$MACRO_ID`. |
| `show-concrete-implicit-tparams` | Use more concrete type parameters in the implicit search flamegraph. Note that it may change the shape of the flamegraph. |
| `show-profiles` | Show implicit searches and macro expansions by type and call-site. |
| `sourceroot` | Tell the plugin what is the source directory of the project. Example: `-P:scalac-profiling:sourceroot:$PROJECT_BASE_DIR`. |
| `cross-target` | Tell the plugin what is the cross target directory of the project. Example: `-P:scalac-profiling:cross-target:$PROJECT_TARGET`. |
1 change: 1 addition & 0 deletions plugin/src/main/scala/ch/epfl/scala/PluginConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ final case class PluginConfig(
showProfiles: Boolean,
generateDb: Boolean,
sourceRoot: AbsolutePath,
crossTarget: AbsolutePath,
printSearchIds: Set[Int],
generateMacroFlamegraph: Boolean,
generateGlobalFlamegraph: Boolean,
Expand Down
63 changes: 38 additions & 25 deletions plugin/src/main/scala/ch/epfl/scala/ProfilingPlugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class ProfilingPlugin(val global: Global) extends Plugin { self =>

private final lazy val ShowProfiles = "show-profiles"
private final lazy val SourceRoot = "sourceroot"
private final lazy val CrossTarget = "cross-target"
private final lazy val PrintSearchResult = "print-search-result"
private final lazy val GenerateMacroFlamegraph = "generate-macro-flamegraph"
private final lazy val GenerateGlobalFlamegraph = "generate-global-flamegraph"
Expand All @@ -40,6 +41,7 @@ class ProfilingPlugin(val global: Global) extends Plugin { self =>
private final lazy val ShowConcreteImplicitTparams = "show-concrete-implicit-tparams"
private final lazy val PrintSearchRegex = s"$PrintSearchResult:(.*)".r
private final lazy val SourceRootRegex = s"$SourceRoot:(.*)".r
private final lazy val CrossTargetRegex = s"$CrossTarget:(.*)".r

def findOption(name: String, pattern: Regex): Option[String] = {
super.options.find(_.startsWith(name)).flatMap {
Expand All @@ -55,18 +57,39 @@ class ProfilingPlugin(val global: Global) extends Plugin { self =>
}
}

private final lazy val config = PluginConfig(
showProfiles = super.options.contains(ShowProfiles),
generateDb = super.options.contains(GenerateProfileDb),
sourceRoot = findOption(SourceRoot, SourceRootRegex)
private final lazy val config = {
val sourceRoot = findOption(SourceRoot, SourceRootRegex)
.map(AbsolutePath.apply)
.getOrElse(AbsolutePath.workingDirectory),
printSearchIds = findSearchIds(findOption(PrintSearchResult, PrintSearchRegex)),
generateMacroFlamegraph = super.options.contains(GenerateMacroFlamegraph),
generateGlobalFlamegraph = super.options.contains(GenerateGlobalFlamegraph),
printFailedMacroImplicits = super.options.contains(PrintFailedMacroImplicits),
concreteTypeParamsInImplicits = super.options.contains(ShowConcreteImplicitTparams)
)
.getOrElse(AbsolutePath.workingDirectory)
val crossTarget = findOption(CrossTarget, CrossTargetRegex)
.map(AbsolutePath.apply)
.getOrElse {
val scalaDir =
if (ScalaSettingsOps.isScala212)
"scala-2.12"
else if (ScalaSettingsOps.isScala213)
"scala-2.13"
else
sys.error(
s"Currently, only Scala 2.12 and 2.13 are supported, " +
s"but [${global.settings.source.value}] has been spotted"
)

sourceRoot.resolve(RelativePath(s"target/$scalaDir"))
}

PluginConfig(
showProfiles = super.options.contains(ShowProfiles),
generateDb = super.options.contains(GenerateProfileDb),
sourceRoot = sourceRoot,
crossTarget = crossTarget,
printSearchIds = findSearchIds(findOption(PrintSearchResult, PrintSearchRegex)),
generateMacroFlamegraph = super.options.contains(GenerateMacroFlamegraph),
generateGlobalFlamegraph = super.options.contains(GenerateGlobalFlamegraph),
printFailedMacroImplicits = super.options.contains(PrintFailedMacroImplicits),
concreteTypeParamsInImplicits = super.options.contains(ShowConcreteImplicitTparams)
)
}

private lazy val logger = new Logger(global)

Expand All @@ -77,15 +100,16 @@ class ProfilingPlugin(val global: Global) extends Plugin { self =>
// format: off
override val optionsHelp: Option[String] = Some(
s"""
|-P:$name:${pad20(GenerateGlobalFlamegraph)} Creates a global flamegraph of implicit searches for all compilation units. Use the `-P:$name:$SourceRoot` option to manage the root directory, otherwise, a working directory (defined by the `user.dir` property) will be picked.
|-P:$name:${pad20(GenerateGlobalFlamegraph)} Creates a global flamegraph of implicit searches for all compilation units. Use the `-P:$name:$CrossTarget` option to manage the target directory for the resulting flamegraph file, otherwise, the SBT target directory will be picked.
|-P:$name:${pad20(GenerateMacroFlamegraph)} Generates a flamegraph for macro expansions. The flamegraph for implicit searches is enabled by default.
|-P:$name:${pad20(GenerateProfileDb)} Generates profiledb (will be removed later).
|-P:$name:${pad20(PrintFailedMacroImplicits)} Prints trees of all failed implicit searches that triggered a macro expansion.
|-P:$name:${pad20(PrintSearchResult)}:_ Print implicit search result trees for a list of search ids separated by a comma.
|-P:$name:${pad20(ShowConcreteImplicitTparams)} Shows types in flamegraphs of implicits with concrete type params.
|-P:$name:${pad20(ShowProfiles)} Logs profile information for every call-site.
|-P:$name:${pad20(SourceRoot)}:_ Sets the source root for this project.
""".stripMargin
|-P:$name:${pad20(CrossTarget)}:_ Sets the cross target for this project.
""".stripMargin
) // format: on

lazy val implementation = new ProfilingImpl(ProfilingPlugin.this.global, config, logger)
Expand All @@ -111,20 +135,9 @@ class ProfilingPlugin(val global: Global) extends Plugin { self =>
private def reportStatistics(graphsPath: AbsolutePath): Unit = {
val globalDir =
if (config.generateGlobalFlamegraph) {
val scalaDir =
if (ScalaSettingsOps.isScala212)
"scala-2.12"
else if (ScalaSettingsOps.isScala213)
"scala-2.13"
else
sys.error(
s"Currently, only Scala 2.12 and 2.13 are supported, " +
s"but [${global.settings.source.value}] has been spotted"
)

val globalDir =
ProfileDbPath.toGraphsProfilePath(
config.sourceRoot.resolve(RelativePath(s"target/$scalaDir/classes"))
config.crossTarget.resolve(RelativePath("classes"))
)

Some(globalDir)
Expand Down