Skip to content

Commit

Permalink
Add booster-task-graph for task graph visualization
Browse files Browse the repository at this point in the history
  • Loading branch information
johnsonlee committed Apr 25, 2022
1 parent 5e2f136 commit f057517
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class CallGraph private constructor(private val edges: Map<Node, Set<Node>>, val
open class Node internal constructor(val type: String, val name: String, val desc: String, val args: String) {

constructor(type: String, name: String, desc: String)
: this(type, name, desc, desc.substring(desc.indexOf('(') + 1, desc.lastIndexOf(')')))
: this(type, name, desc, desc.substring(desc.indexOf('(') + 1, desc.lastIndexOf(')').takeIf { it > -1 } ?: desc.length))

override fun equals(other: Any?) = when {
other === this -> true
Expand Down
16 changes: 16 additions & 0 deletions booster-task-graph/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# booster-task-graph

Generate task graph in [dot](https://graphviz.org/), please make sure you have installed the [dot command line](https://graphviz.org/doc/info/command.html).

## Getting Started

Executing tasks and then find the `*.dot` and `*.dot.png` files under `${rootProject}/build` directory, for example, if I run the following command line

```bash
./gradlew assembleDebug --dry-run
```

Then, the following files will be generated under `${rootProject}/build`:

* `assembleDebug.dot`
* `assembleDebug.dot.png`
12 changes: 12 additions & 0 deletions booster-task-graph/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apply from: "$rootDir/gradle/booster.gradle"

dependencies {
kapt "com.google.auto.service:auto-service:1.0"
implementation project(':booster-api')
implementation project(':booster-cha')
implementation project(':booster-command')
compileOnly 'com.android.tools.build:gradle:4.0.0'
compileOnly 'com.android.tools.build:builder:4.0.0'
testCompileOnly 'com.android.tools.build:gradle:4.0.0'
testCompileOnly 'com.android.tools.build:builder:4.0.0'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.didiglobal.booster.task.graph

import com.android.build.gradle.api.BaseVariant
import com.didiglobal.booster.cha.graph.CallGraph
import com.didiglobal.booster.cha.graph.dot.DotGraph
import com.didiglobal.booster.command.CommandService
import com.didiglobal.booster.gradle.project
import com.didiglobal.booster.kotlinx.OS
import com.didiglobal.booster.kotlinx.execute
import com.didiglobal.booster.kotlinx.file
import com.didiglobal.booster.task.spi.VariantProcessor
import com.google.auto.service.AutoService
import java.io.BufferedReader
import java.io.File
import java.util.concurrent.atomic.AtomicBoolean

private val DOT = "dot${OS.executableSuffix}"

@AutoService(VariantProcessor::class)
class TaskGraphVariantProcessor : VariantProcessor {

private var generating = AtomicBoolean(false)

override fun process(variant: BaseVariant) {
generating.compareAndSet(false, true).takeIf { it } ?: return

val project = variant.project

project.gradle.taskGraph.whenReady {
val taskNames = project.gradle.startParameter.taskNames
val dot = project.rootProject.buildDir.file("${taskNames.joinToString("-")}.dot")
val title = "./gradlew ${taskNames.joinToString(" ")}"
val graph = project.gradle.taskGraph.allTasks.map { task ->
task.taskDependencies.getDependencies(task).map { dep ->
dep to task
}
}.flatten().map { (dep, task) ->
CallGraph.Edge(TaskNode(dep.path), TaskNode(task.path))
}.fold(CallGraph.Builder().setTitle(title)) { builder, edge ->
builder.addEdge(edge)
builder
}.build()

// write dot file
dot.writeText(DotGraph.DIGRAPH.render(graph).toString())

// convert dot to png
CommandService.fromPath(DOT).location.file.let(::File).takeIf(File::exists)?.let {
val cmdline = "${it.canonicalPath} -Tpng -O ${dot.canonicalPath}"
project.logger.info(cmdline)
cmdline.execute()
}?.let { p ->
p.waitFor()
if (p.exitValue() != 0) {
project.logger.error(p.errorStream.bufferedReader().use(BufferedReader::readText))
}
} ?: project.logger.warn("Command `${DOT}` not found")
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.didiglobal.booster.task.graph

import com.didiglobal.booster.cha.graph.CallGraph

data class TaskNode(val path: String) : CallGraph.Node("", path, "") {

override fun toPrettyString(): String = path

}
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ include ':booster-task-compression'
include ':booster-task-compression-cwebp'
include ':booster-task-compression-pngquant'
include ':booster-task-compression-processed-res'
include ':booster-task-graph'
include ':booster-task-list-artifact'
include ':booster-task-list-permission'
include ':booster-task-list-shared-library'
Expand Down

0 comments on commit f057517

Please sign in to comment.