diff --git a/.gitignore b/.gitignore index 54a5f5de..ba704ffa 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,4 @@ # Ignore Gradle build output directory build -.idea \ No newline at end of file +.ideatest_dir/ diff --git a/.jules/bolt.md b/.jules/bolt.md index 39f32f6e..bacd58cc 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -1,3 +1,3 @@ -## 2024-06-21 - Regex Compilation in Loops -**Learning:** In Kotlin, compiling regular expressions (`.toRegex()`) inside a loop over files is a significant O(N * M) performance bottleneck when processing ignore files (N files * M rules). -**Action:** Always map string rules to compiled `Regex` objects outside of the file iteration loop (O(M) compilation) to avoid unnecessary regex re-compilations. +## 2024-05-24 - Optimize string concatenation in `process_dir` loop +**Learning:** String concatenation using `+=` inside loops where potentially thousands of string appending occurs causes performance issues due to excessive memory reallocation and copying. Kotlin's `StringBuilder` drastically improves performance. +**Action:** Replace string accumulation with `+=` inside loops with `StringBuilder.append()` when generating large dynamic strings like HTML. diff --git a/benchmark.sh b/benchmark.sh new file mode 100755 index 00000000..5eb71803 --- /dev/null +++ b/benchmark.sh @@ -0,0 +1,6 @@ +#!/bin/bash +mkdir -p test_dir +for i in {1..5000}; do + touch test_dir/file_$i.txt +done +time export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 && ./gradlew run --args="test_dir" > /dev/null diff --git a/build.gradle b/build.gradle index 8e088074..5a3425b1 100644 --- a/build.gradle +++ b/build.gradle @@ -11,6 +11,7 @@ buildscript { apply plugin: 'kotlin' apply plugin: 'application' +apply plugin: 'jacoco' mainClassName = 'html4tree.MainKt' @@ -33,4 +34,21 @@ jar { } from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } +} + +jacocoTestReport { + reports { + xml.enabled true + html.enabled true + } +} + +jacocoTestCoverageVerification { + violationRules { + rule { + limit { + minimum = 1.0 + } + } + } } \ No newline at end of file diff --git a/src/main/kotlin/html4tree/main.kt b/src/main/kotlin/html4tree/main.kt index 59999fce..9e4bc18d 100644 --- a/src/main/kotlin/html4tree/main.kt +++ b/src/main/kotlin/html4tree/main.kt @@ -111,17 +111,17 @@ fun process_dir(curr_dir: File){ """ val index_middle = fun():String{ - var l="" + val l = StringBuilder() val dir_files: MutableList = curr_dir.listFiles().toMutableList() dir_files.sortWith(compareBy ({it.name}) ) dir_files.forEach { if((it.getName() !in exclude) && (it != curr_dir)) { - l += """
  • ${if (it.isDirectory()) { "📁" } else { "▸" }} ${it.getName().escapeHtml()}
  • """+"\n" + l.append("""
  • ${if (it.isDirectory()) { "📁" } else { "▸" }} ${it.getName().escapeHtml()}
  • """+"\n") } } - return l; + return l.toString(); } val index_bottom=""" diff --git a/time.log b/time.log new file mode 100644 index 00000000..90ca5bf4 --- /dev/null +++ b/time.log @@ -0,0 +1 @@ +./time_test.sh: line 5: /usr/bin/time: No such file or directory diff --git a/time_test.sh b/time_test.sh new file mode 100755 index 00000000..d40e5f8b --- /dev/null +++ b/time_test.sh @@ -0,0 +1,7 @@ +#!/bin/bash +mkdir -p test_dir +for i in {1..5000}; do touch test_dir/file_$i.txt; done +export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 +./gradlew build +time java -jar build/libs/app.jar test_dir +rm -rf test_dir