From 930faf6a0a990ed5631944e1307cb32d9ec22021 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Fri, 24 Jul 2026 03:37:58 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20Bolt:=20[performance=20improvement]?= =?UTF-8?q?=20Hoist=20static=20strings=20and=20expensive=20SHA-256=20out?= =?UTF-8?q?=20of=20loop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit πŸ’‘ What: `process_dir` 내뢀에 μœ„μΉ˜ν•˜λ˜ λΆˆλ³€ 정적 λ¬Έμžμ—΄(`cssContent`, `css`)κ³Ό λΉ„μš©μ΄ 큰 SHA-256 ν•΄μ‹œ μ—°μ‚° μ½”λ“œλ₯Ό μ΅œμƒμœ„ 레벨의 `private val` μƒμˆ˜λ‘œ ν˜Έμ΄μŠ€νŒ…ν–ˆμŠ΅λ‹ˆλ‹€. 🎯 Why: ν•΄λ‹Ή λ³€μˆ˜λ“€μ€ 파일 디렉토리 크둀링 μ‹œ `process_dir` ν˜ΈμΆœλ§ˆλ‹€ λ³€ν•˜μ§€ μ•ŠλŠ” κ³ μ •λœ κ°’μž…λ‹ˆλ‹€. κ·ΈλŸΌμ—λ„ λΆˆκ΅¬ν•˜κ³  맀번 호좜될 λ•Œλ§ˆλ‹€ 무거운 SHA-256 μ—°μ‚°κ³Ό λŒ€λŸ‰μ˜ λ¬Έμžμ—΄ 할당이 반볡적으둜 λ°œμƒν•˜μ—¬ λΆˆν•„μš”ν•œ λ©”λͺ¨λ¦¬(GC) 및 CPU μ˜€λ²„ν—€λ“œλ₯Ό μœ λ°œν•˜κ³  μžˆμ—ˆμŠ΅λ‹ˆλ‹€. πŸ“Š Impact: 디렉토리λ₯Ό μˆœνšŒν•  λ•Œλ§ˆλ‹€ λ°œμƒν•˜λ˜ μ€‘λ³΅λœ λ©”λͺ¨λ¦¬ ν• λ‹Ή 및 ν•΄μ‹œ μ—°μ‚° λΉ„μš©μ΄ μ‚¬λΌμ‘ŒμŠ΅λ‹ˆλ‹€. 특히 λ§Žμ€ 디렉토리(1,000개 이상)λ₯Ό μˆœνšŒν•  λ•Œ 처리 속도가 κ°œμ„ λ˜λ©° λ©”λͺ¨λ¦¬ 압박이 λŒ€ν­ μ€„μ–΄λ“­λ‹ˆλ‹€. πŸ”¬ Measurement: ν…ŒμŠ€νŠΈ 컀버리지 100%λ₯Ό μœ μ§€ν•˜λŠ”μ§€ ν™•μΈν•˜κΈ° μœ„ν•΄ `./gradlew clean test jacocoTestReport jacocoTestCoverageVerification --continue`λ₯Ό μ‹€ν–‰ν•˜μ—¬ 톡과함을 ν™•μΈν–ˆμŠ΅λ‹ˆλ‹€. --- .jules/bolt.md | 3 +++ src/main/kotlin/html4tree/main.kt | 16 +++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index 19b4c61..94802e9 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -43,3 +43,6 @@ ## 2025-01-24 - 단일 readAttributes 호좜둜 파일 속성 쑰회 μ΅œμ ν™” **ν•™μŠ΅:** `isDirectory`, `!it.isDirectory()`, `isSymbolicLink` 3개의 κ°œλ³„μ μΈ 파일 μ‹œμŠ€ν…œ I/O ν˜ΈμΆœμ„ μˆ˜ν–‰ν•˜λ©΄ μ„±λŠ₯ μ €ν•˜κ°€ ν½λ‹ˆλ‹€. 이λ₯Ό 단일 `Files.readAttributes` 호좜둜 λ³€κ²½ν•˜μ—¬ 메타데이터λ₯Ό ν•œ λ²ˆμ— μ‘°νšŒν•¨μœΌλ‘œμ¨ I/O μ˜€λ²„ν—€λ“œλ₯Ό λŒ€ν­ 쀄일 수 μžˆμŒμ„ ν™•μΈν–ˆμŠ΅λ‹ˆλ‹€. **쑰치:** 디렉토리 순회 μ‹œ 파일의 μ—¬λŸ¬ 속성을 확인할 λ•ŒλŠ” κ°œλ³„μ μΈ stat ν˜ΈμΆœλ³΄λ‹€ `Files.readAttributes`λ₯Ό μ‚¬μš©ν•˜μ—¬ ν•„μš”ν•œ λͺ¨λ“  속성을 ν•œ λ²ˆμ— κ°€μ Έμ˜€λŠ” 방식을 μš°μ„ μ μœΌλ‘œ κ³ λ €ν•΄μ•Ό ν•©λ‹ˆλ‹€. +## 2026-07-24 - 루프 λ‚΄λΆ€μ˜ λΆˆλ³€κ°’ μ—°μ‚° ν˜Έμ΄μŠ€νŒ… +**ν•™μŠ΅:** `process_dir`와 같이 자주 ν˜ΈμΆœλ˜λŠ” ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œ λ³€ν•˜μ§€ μ•ŠλŠ” 정적 λ¬Έμžμ—΄ ν• λ‹Ήμ΄λ‚˜ 무거운 μ—°μ‚°(예: SHA-256 ν•΄μ‹œ 계산)을 μˆ˜ν–‰ν•˜λ©΄ 맀번 호좜 μ‹œλ§ˆλ‹€ μ€‘λ³΅λœ λ©”λͺ¨λ¦¬ ν• λ‹Ή 및 처리 λΉ„μš©μ΄ λ°œμƒν•©λ‹ˆλ‹€. +**쑰치:** λΆˆλ³€ 정적 λ¬Έμžμ—΄κ³Ό λΉ„μš©μ΄ 큰 연산듀은 자주 ν˜ΈμΆœλ˜λŠ” ν•¨μˆ˜ λ°”κΉ₯(μ΅œμƒμœ„ 레벨)으둜 ν˜Έμ΄μŠ€νŒ…ν•˜μ—¬ `private val` μƒμˆ˜λ‘œ μ„ μ–Έν•¨μœΌλ‘œμ¨ λΆˆν•„μš”ν•œ 반볡 μ˜€λ²„ν—€λ“œλ₯Ό μ œκ±°ν•©λ‹ˆλ‹€. Kotlinμ—μ„œ `private val`을 μ‚¬μš©ν•˜λ©΄ 기본적으둜 μƒμ„±λ˜λŠ” public getter λ©”μ„œλ“œλ₯Ό λ°©μ§€ν•˜μ—¬ 컀버리지(Jacoco) κ°μ†Œλ„ 막을 수 μžˆμŠ΅λ‹ˆλ‹€. diff --git a/src/main/kotlin/html4tree/main.kt b/src/main/kotlin/html4tree/main.kt index b455862..70f3c90 100644 --- a/src/main/kotlin/html4tree/main.kt +++ b/src/main/kotlin/html4tree/main.kt @@ -240,11 +240,9 @@ fun write_index_file(curr_dir: File, content: String) { } } -fun process_dir(curr_dir: File, excludeSet: Set? = null, dirFiles: Array? = null){ - - val exclude: Set = excludeSet ?: process_ignore_file(curr_dir) - - val cssContent = """ +// ⚑ Bolt Performance Optimization: Hoisted static CSS strings and expensive SHA-256 computation +// to top-level `private val`s to prevent redundant allocations and processing overhead per directory. +private val cssContent = """ body { font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; line-height: 1.5; @@ -310,13 +308,17 @@ fun process_dir(curr_dir: File, excludeSet: Set? = null, dirFiles: Array } """ - val styleHash = "sha256-" + Base64.getEncoder().encodeToString(MessageDigest.getInstance("SHA-256").digest(cssContent.toByteArray(Charsets.UTF_8))) +private val styleHash = "sha256-" + Base64.getEncoder().encodeToString(MessageDigest.getInstance("SHA-256").digest(cssContent.toByteArray(Charsets.UTF_8))) - val css = """ +private val css = """ """ +fun process_dir(curr_dir: File, excludeSet: Set? = null, dirFiles: Array? = null){ + + val exclude: Set = excludeSet ?: process_ignore_file(curr_dir) + val index_top = """