From 530cffe0343a5d3b48bd3cd2734dacf053982492 Mon Sep 17 00:00:00 2001 From: klee0kai Date: Sun, 13 Aug 2023 21:38:19 +0400 Subject: [PATCH 1/7] recursive detect --- .../com/github/klee0kai/tasktree/utils/ProjectExt.kt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/utils/ProjectExt.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/utils/ProjectExt.kt index 546d9ad..e1cbd35 100644 --- a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/utils/ProjectExt.kt +++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/utils/ProjectExt.kt @@ -6,6 +6,8 @@ import org.gradle.api.Project import org.gradle.api.Task import org.gradle.execution.taskgraph.DefaultTaskExecutionGraph +private const val RECURSIVE_DETECT = 1000 + val Project.fullName get() = buildString { parents @@ -27,12 +29,16 @@ val Project.allRequestedTasks .flatMap { setOf(it) + taskGraph.getAllDeps(it) } .toSet() -val Project.parents get() = generateSequence(this) { runCatching { it.parent }.getOrNull() } +val Project.parents + get() = generateSequence(this) { + runCatching { it.parent }.getOrNull() + }.take(RECURSIVE_DETECT) -fun DefaultTaskExecutionGraph.getAllDeps(task: Task): Set = +fun DefaultTaskExecutionGraph.getAllDeps(task: Task, depth: Int = RECURSIVE_DETECT): Set = getDeps(task) .flatMap { - setOf(it) + getAllDeps(it) + val depTasks = if (depth > 0) getAllDeps(it, depth = depth - 1) else emptyList() + setOf(it) + depTasks } .toSet() From 2bc49afe8573d0ad5c27cd820800910ccd34bae4 Mon Sep 17 00:00:00 2001 From: klee0kai Date: Sun, 13 Aug 2023 23:05:15 +0400 Subject: [PATCH 2/7] speed up work --- .../com/github/klee0kai/tasktree/TaskStat.kt | 37 ++++++------------- .../klee0kai/tasktree/tasks/TaskTreeTask.kt | 13 ++++++- .../klee0kai/tasktree/utils/ProjectExt.kt | 14 +++---- 3 files changed, 28 insertions(+), 36 deletions(-) diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/TaskStat.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/TaskStat.kt index e9eb351..e61ab25 100644 --- a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/TaskStat.kt +++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/TaskStat.kt @@ -1,10 +1,7 @@ package com.github.klee0kai.tasktree -import com.github.klee0kai.tasktree.utils.getAllDeps -import com.github.klee0kai.tasktree.utils.taskGraph import org.gradle.api.Project import org.gradle.api.Task -import org.gradle.kotlin.dsl.provideDelegate class TaskStat( val task: Task, @@ -12,31 +9,19 @@ class TaskStat( val rootProject: Project, ) { - val allDepsCount by lazy { rootProject.taskGraph.getAllDeps(task).count() } - val allDependedOnCount by lazy { - allTasks.count { - rootProject.taskGraph - .getAllDeps(it) - .contains(task) - } - } - val price by lazy { allDepsCount } - val importance by lazy { allDependedOnCount } + var allDepsCount: Long = 0 + var allDependedOnCount: Long = 0 + var allDependedOnOutsideProjectCount: Long = 0 - val complexPrice by lazy { - (price * importance).toFloat() / allTasks.size - } + + val price get() = allDepsCount + val importance get() = allDependedOnCount + + val complexPrice get() = (price * importance).toFloat() / allTasks.size // ---- outside of project ------ - val allDependedOnOutsideProjectCount by lazy { - allTasks.count { - it.project != task.project && - rootProject.taskGraph - .getAllDeps(it) - .contains(task) - } - } - val importanceOutsideProject by lazy { allDependedOnOutsideProjectCount } - val complexPriceOutsideProject by lazy { (price * importanceOutsideProject).toFloat() / allTasks.size } + val importanceOutsideProject get() = allDependedOnOutsideProjectCount + val complexPriceOutsideProject get() = (price * importanceOutsideProject).toFloat() / allTasks.size + } diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt index 7285dd7..39d1a50 100644 --- a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt +++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt @@ -19,7 +19,6 @@ open class TaskTreeTask @Inject constructor( override fun generate(project: Project) { val allTasks = project.allRequestedTasks.toSet() - allTasks.forEach { task -> taskStat.putIfAbsent( task, @@ -30,6 +29,18 @@ open class TaskTreeTask @Inject constructor( ) ) } + taskStat.values.forEach { stat -> + val allDeps = project.taskGraph.getAllDeps(stat.task) + stat.allDepsCount += allDeps.count() + allDeps.forEach { + val depStat = taskStat[it]!! + depStat.allDependedOnCount++ + if (depStat.task.project != stat.task.project) { + depStat.allDependedOnOutsideProjectCount++ + } + } + } + val topTasks = taskStat.values .filter { it.allDependedOnCount <= 0 } diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/utils/ProjectExt.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/utils/ProjectExt.kt index e1cbd35..efc8ad4 100644 --- a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/utils/ProjectExt.kt +++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/utils/ProjectExt.kt @@ -26,21 +26,17 @@ val Project.taskGraph get() = gradle.taskGraph as DefaultTaskExecutionGraph val Project.allRequestedTasks get() = taskGraph.allTasks .filter { it !is TaskTreeTask && it !is DiagonDagTask } - .flatMap { setOf(it) + taskGraph.getAllDeps(it) } - .toSet() val Project.parents get() = generateSequence(this) { runCatching { it.parent }.getOrNull() }.take(RECURSIVE_DETECT) -fun DefaultTaskExecutionGraph.getAllDeps(task: Task, depth: Int = RECURSIVE_DETECT): Set = - getDeps(task) - .flatMap { - val depTasks = if (depth > 0) getAllDeps(it, depth = depth - 1) else emptyList() - setOf(it) + depTasks - } - .toSet() +fun DefaultTaskExecutionGraph.getAllDeps(task: Task, depth: Int = RECURSIVE_DETECT): List = + getDeps(task).flatMap { + val depTasks = if (depth > 0) getAllDeps(it, depth = depth - 1) else emptyList() + listOf(it) + depTasks + } fun DefaultTaskExecutionGraph.getDeps(task: Task): Set = From 731eae559bfe471d133d78d7e05c7e2ff84cfd30 Mon Sep 17 00:00:00 2001 From: klee0kai Date: Sun, 13 Aug 2023 23:29:09 +0400 Subject: [PATCH 3/7] little more speed up --- .../klee0kai/tasktree/tasks/TaskTreeTask.kt | 15 ++++++++++++++- .../github/klee0kai/tasktree/utils/ProjectExt.kt | 9 +-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt index 39d1a50..b00a028 100644 --- a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt +++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt @@ -15,6 +15,7 @@ open class TaskTreeTask @Inject constructor( private val renderedTasks = mutableSetOf() private val taskStat = mutableMapOf() + private val depsGraph = mutableMapOf>() override fun generate(project: Project) { @@ -28,9 +29,11 @@ open class TaskTreeTask @Inject constructor( rootProject = project ) ) + depsGraph.putIfAbsent(task, project.taskGraph.getDeps(task)) } + taskStat.values.forEach { stat -> - val allDeps = project.taskGraph.getAllDeps(stat.task) + val allDeps = stat.task.getAllDeps() stat.allDepsCount += allDeps.count() allDeps.forEach { val depStat = taskStat[it]!! @@ -148,6 +151,16 @@ open class TaskTreeTask @Inject constructor( } } + private fun Task.getAllDeps(): Sequence { + val task = this + return sequence { + depsGraph[task]?.let { deps -> + yieldAll(deps) + deps.forEach { yieldAll(it.getAllDeps()) } + } + } + } + private fun StyledTextOutput.printTaskShort(taskStat: TaskStat) = apply { withStyle(Identifier) .text(taskStat.task.fullName) diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/utils/ProjectExt.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/utils/ProjectExt.kt index efc8ad4..031276e 100644 --- a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/utils/ProjectExt.kt +++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/utils/ProjectExt.kt @@ -6,7 +6,7 @@ import org.gradle.api.Project import org.gradle.api.Task import org.gradle.execution.taskgraph.DefaultTaskExecutionGraph -private const val RECURSIVE_DETECT = 1000 +private const val RECURSIVE_DETECT = 10_000 val Project.fullName get() = buildString { @@ -32,13 +32,6 @@ val Project.parents runCatching { it.parent }.getOrNull() }.take(RECURSIVE_DETECT) -fun DefaultTaskExecutionGraph.getAllDeps(task: Task, depth: Int = RECURSIVE_DETECT): List = - getDeps(task).flatMap { - val depTasks = if (depth > 0) getAllDeps(it, depth = depth - 1) else emptyList() - listOf(it) + depTasks - } - - fun DefaultTaskExecutionGraph.getDeps(task: Task): Set = try { getDependencies(task) From 011b473014686af42d5c415eaf9d2c29956403cf Mon Sep 17 00:00:00 2001 From: klee0kai Date: Sun, 13 Aug 2023 23:50:15 +0400 Subject: [PATCH 4/7] map use with string key --- .../github/klee0kai/tasktree/tasks/TaskTreeTask.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt index b00a028..eb2c7de 100644 --- a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt +++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt @@ -14,29 +14,29 @@ open class TaskTreeTask @Inject constructor( ) : BaseReportTask() { private val renderedTasks = mutableSetOf() - private val taskStat = mutableMapOf() - private val depsGraph = mutableMapOf>() + private val taskStat = mutableMapOf() + private val depsGraph = mutableMapOf>() override fun generate(project: Project) { val allTasks = project.allRequestedTasks.toSet() allTasks.forEach { task -> taskStat.putIfAbsent( - task, + task.fullName, TaskStat( task = task, allTasks = allTasks, rootProject = project ) ) - depsGraph.putIfAbsent(task, project.taskGraph.getDeps(task)) + depsGraph.putIfAbsent(task.fullName, project.taskGraph.getDeps(task)) } taskStat.values.forEach { stat -> val allDeps = stat.task.getAllDeps() stat.allDepsCount += allDeps.count() allDeps.forEach { - val depStat = taskStat[it]!! + val depStat = taskStat[it.fullName]!! depStat.allDependedOnCount++ if (depStat.task.project != stat.task.project) { depStat.allDependedOnOutsideProjectCount++ @@ -58,7 +58,7 @@ open class TaskTreeTask @Inject constructor( private fun render(task: Task, lastChild: Boolean = true, depth: Int = 0) { graphRenderer?.visit({ - val taskStat = taskStat[task] ?: return@visit + val taskStat = taskStat[task.fullName] ?: return@visit printTaskShort(taskStat) @@ -154,7 +154,7 @@ open class TaskTreeTask @Inject constructor( private fun Task.getAllDeps(): Sequence { val task = this return sequence { - depsGraph[task]?.let { deps -> + depsGraph[task.fullName]?.let { deps -> yieldAll(deps) deps.forEach { yieldAll(it.getAllDeps()) } } From 2337482eb9d44a96ddd099880823f6a83187f37d Mon Sep 17 00:00:00 2001 From: klee0kai Date: Mon, 14 Aug 2023 07:35:38 +0400 Subject: [PATCH 5/7] Revert "map use with string key" This reverts commit 011b473014686af42d5c415eaf9d2c29956403cf. --- .../github/klee0kai/tasktree/tasks/TaskTreeTask.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt index eb2c7de..b00a028 100644 --- a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt +++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt @@ -14,29 +14,29 @@ open class TaskTreeTask @Inject constructor( ) : BaseReportTask() { private val renderedTasks = mutableSetOf() - private val taskStat = mutableMapOf() - private val depsGraph = mutableMapOf>() + private val taskStat = mutableMapOf() + private val depsGraph = mutableMapOf>() override fun generate(project: Project) { val allTasks = project.allRequestedTasks.toSet() allTasks.forEach { task -> taskStat.putIfAbsent( - task.fullName, + task, TaskStat( task = task, allTasks = allTasks, rootProject = project ) ) - depsGraph.putIfAbsent(task.fullName, project.taskGraph.getDeps(task)) + depsGraph.putIfAbsent(task, project.taskGraph.getDeps(task)) } taskStat.values.forEach { stat -> val allDeps = stat.task.getAllDeps() stat.allDepsCount += allDeps.count() allDeps.forEach { - val depStat = taskStat[it.fullName]!! + val depStat = taskStat[it]!! depStat.allDependedOnCount++ if (depStat.task.project != stat.task.project) { depStat.allDependedOnOutsideProjectCount++ @@ -58,7 +58,7 @@ open class TaskTreeTask @Inject constructor( private fun render(task: Task, lastChild: Boolean = true, depth: Int = 0) { graphRenderer?.visit({ - val taskStat = taskStat[task.fullName] ?: return@visit + val taskStat = taskStat[task] ?: return@visit printTaskShort(taskStat) @@ -154,7 +154,7 @@ open class TaskTreeTask @Inject constructor( private fun Task.getAllDeps(): Sequence { val task = this return sequence { - depsGraph[task.fullName]?.let { deps -> + depsGraph[task]?.let { deps -> yieldAll(deps) deps.forEach { yieldAll(it.getAllDeps()) } } From 7c38942597c886911b5969fddde3de7912119c5b Mon Sep 17 00:00:00 2001 From: klee0kai Date: Mon, 14 Aug 2023 07:41:36 +0400 Subject: [PATCH 6/7] use sorted list --- .../klee0kai/tasktree/tasks/TaskTreeTask.kt | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt index b00a028..1676098 100644 --- a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt +++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt @@ -15,7 +15,6 @@ open class TaskTreeTask @Inject constructor( private val renderedTasks = mutableSetOf() private val taskStat = mutableMapOf() - private val depsGraph = mutableMapOf>() override fun generate(project: Project) { @@ -29,21 +28,28 @@ open class TaskTreeTask @Inject constructor( rootProject = project ) ) - depsGraph.putIfAbsent(task, project.taskGraph.getDeps(task)) } - taskStat.values.forEach { stat -> - val allDeps = stat.task.getAllDeps() - stat.allDepsCount += allDeps.count() - allDeps.forEach { + //https://docs.gradle.org/current/javadoc/org/gradle/api/execution/TaskExecutionGraph.html#getAllTasks-- + // use sorted list + allTasks.forEach { task -> + val stat = taskStat[task]!! + val deps = project.taskGraph.getDeps(task) + stat.allDepsCount += deps.count() + deps.sumOf { dep -> + taskStat[dep]!!.allDepsCount + } + } + allTasks.reversed().forEach { task -> + val stat = taskStat[task]!! + project.taskGraph.getDeps(task).forEach { val depStat = taskStat[it]!! - depStat.allDependedOnCount++ + depStat.allDependedOnCount += 1 + stat.allDependedOnCount if (depStat.task.project != stat.task.project) { - depStat.allDependedOnOutsideProjectCount++ + depStat.allDependedOnOutsideProjectCount += 1 + stat.allDependedOnCount } } - } + } val topTasks = taskStat.values .filter { it.allDependedOnCount <= 0 } @@ -151,16 +157,6 @@ open class TaskTreeTask @Inject constructor( } } - private fun Task.getAllDeps(): Sequence { - val task = this - return sequence { - depsGraph[task]?.let { deps -> - yieldAll(deps) - deps.forEach { yieldAll(it.getAllDeps()) } - } - } - } - private fun StyledTextOutput.printTaskShort(taskStat: TaskStat) = apply { withStyle(Identifier) .text(taskStat.task.fullName) From 7901532e7f5c2128f7632ff7b45c81e1602f1764 Mon Sep 17 00:00:00 2001 From: klee0kai Date: Mon, 14 Aug 2023 23:10:21 +0400 Subject: [PATCH 7/7] print importance outside project --- example/build.gradle.kts | 26 ++++++++++++++++++- .../klee0kai/tasktree/TaskTreeExtension.kt | 9 +++++-- .../klee0kai/tasktree/tasks/TaskTreeTask.kt | 12 ++++++--- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/example/build.gradle.kts b/example/build.gradle.kts index 45a96c5..37d7529 100644 --- a/example/build.gradle.kts +++ b/example/build.gradle.kts @@ -3,12 +3,33 @@ plugins { id("tasktree") } -tasks.create("simple_first_task") { +val firstTask = tasks.create("simple_first_task") { doLast { println("run simple_first_task") } tasks.getByName("assemble").dependsOn(this) } + +tasks.create("sub_first_task") { + doLast { println("run sub_first_task") } + + firstTask.dependsOn(this) +} + + +val secondTask = tasks.create("simple_second_task") { + doLast { println("run simple_second_task") } + + tasks.getByName("assemble").dependsOn(this) +} + + +tasks.create("sub_second_task") { + doLast { println("run sub_second_task") } + + secondTask.dependsOn(this) +} + tasktree { inputs = false @@ -17,6 +38,9 @@ tasktree { printPrice = true printImportance = true printComplexPrice = true + printDoubles = true + printImportanceOutSide = true + } diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/TaskTreeExtension.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/TaskTreeExtension.kt index 57129ab..25b2e81 100644 --- a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/TaskTreeExtension.kt +++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/TaskTreeExtension.kt @@ -28,15 +28,20 @@ open class TaskTreeExtension { var printDoubles: Boolean = false /** - * Print dependency count for task + * Print the number of dependencies for a task */ var printPrice: Boolean = false /** - * Print depended task count + * Print number of dependent tasks */ var printImportance: Boolean = false + /** + * Print the number of dependent tasks from another project + */ + var printImportanceOutSide: Boolean = false + /** * Complex price * ``` diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt index 1676098..2753b53 100644 --- a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt +++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt @@ -16,8 +16,10 @@ open class TaskTreeTask @Inject constructor( private val renderedTasks = mutableSetOf() private val taskStat = mutableMapOf() - override fun generate(project: Project) { + renderedTasks.clear() + taskStat.clear() + val allTasks = project.allRequestedTasks.toSet() allTasks.forEach { task -> taskStat.putIfAbsent( @@ -35,7 +37,7 @@ open class TaskTreeTask @Inject constructor( allTasks.forEach { task -> val stat = taskStat[task]!! val deps = project.taskGraph.getDeps(task) - stat.allDepsCount += deps.count() + deps.sumOf { dep -> + stat.allDepsCount = deps.count() + deps.sumOf { dep -> taskStat[dep]!!.allDepsCount } } @@ -59,7 +61,7 @@ open class TaskTreeTask @Inject constructor( printMostExpensiveTasksIfNeed() printMostExpensiveModulesIfNeed() - renderedTasks.clear() + } private fun render(task: Task, lastChild: Boolean = true, depth: Int = 0) { @@ -169,6 +171,10 @@ open class TaskTreeTask @Inject constructor( withStyle(Description) .text(" importance: ${taskStat.importance};") } + if (ext.printImportanceOutSide) { + withStyle(Description) + .text(" importance outside: ${taskStat.importanceOutsideProject};") + } if (ext.printComplexPrice) { withStyle(Description) .text(" complexPrice: ${taskStat.complexPrice.formatString()};")