From 0c983215dc1d4178aee248577d93b6e9320e9a91 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sun, 16 Aug 2026 21:19:09 +0000 Subject: [PATCH 1/3] =?UTF-8?q?=E2=9A=A1=20Bolt:=20Replace=20padStart=20wi?= =?UTF-8?q?th=20inline=20ternary=20for=20Date=20formatters?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Removed `String.padStart(2, '0')` in hot-path date formatters (`formatDateInput`, `formatLocalDateInput`, `formatCompactDate`). - Implemented inline ternary logic (`m < 10 ? '0' + m : m`) to eliminate unnecessary string allocations and JS-to-C++ bridge overhead. - Documented findings and actions in `.jules/bolt.md`. --- .jules/bolt.md | 3 +++ app.js | 18 +++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index b08b203a..fc42cc4c 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -4,3 +4,6 @@ ## 2026-07-12 - Optimize renderTaskRow DOM allocations **Learning:** Caching unattached template nodes and instantiating them via `.cloneNode(false)` reduces DOM instantiation overhead in O(N) render loops significantly. **Action:** Apply this optimization to other hot-path rendering elements such as rows, cells, and stack containers. +## 2026-07-12 - Eliminate padStart in hot-path Date formatters +**Learning:** Using `String.padStart()` in hot loops (e.g., date formatting functions repeatedly called during `computeTaskMetrics` or timeline generation) causes unnecessary string allocations and JS-to-C++ bridge overhead. +**Action:** Prefer using inline ternary string concatenation (e.g., `value < 10 ? '0' + value : value`) for zero-padding in performance-critical sections to reduce GC pressure. diff --git a/app.js b/app.js index a04aae71..9ed08ebd 100644 --- a/app.js +++ b/app.js @@ -2684,20 +2684,28 @@ function clamp(value, min, max) { function formatDateInput(date) { const year = date.getUTCFullYear(); - const month = String(date.getUTCMonth() + 1).padStart(2, '0'); - const day = String(date.getUTCDate()).padStart(2, '0'); + const m = date.getUTCMonth() + 1; + const d = date.getUTCDate(); + const month = m < 10 ? '0' + m : m; + const day = d < 10 ? '0' + d : d; return `${year}-${month}-${day}`; } function formatLocalDateInput(date) { const year = date.getFullYear(); - const month = String(date.getMonth() + 1).padStart(2, '0'); - const day = String(date.getDate()).padStart(2, '0'); + const m = date.getMonth() + 1; + const d = date.getDate(); + const month = m < 10 ? '0' + m : m; + const day = d < 10 ? '0' + d : d; return `${year}-${month}-${day}`; } function formatCompactDate(date) { - return `${date.getFullYear()}${String(date.getMonth() + 1).padStart(2, '0')}${String(date.getDate()).padStart(2, '0')}`; + const m = date.getMonth() + 1; + const d = date.getDate(); + const month = m < 10 ? '0' + m : m; + const day = d < 10 ? '0' + d : d; + return `${date.getFullYear()}${month}${day}`; } function formatPercent(value, digits) { From d23c3e02e4642cdfa2a5abc2c0f4ceb7f21a0cf3 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sun, 16 Aug 2026 23:01:52 +0000 Subject: [PATCH 2/3] =?UTF-8?q?=E2=9A=A1=20Bolt:=20Replace=20padStart=20wi?= =?UTF-8?q?th=20inline=20ternary=20for=20Date=20formatters?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Removed `String.padStart(2, '0')` in hot-path date formatters (`formatDateInput`, `formatLocalDateInput`, `formatCompactDate`). - Implemented inline ternary logic (`m < 10 ? '0' + m : m`) to eliminate unnecessary string allocations and JS-to-C++ bridge overhead. - Documented findings and actions in `.jules/bolt.md`. From 8345c4f1b8cb4b40b1be074f21563c1d34840201 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sun, 16 Aug 2026 23:17:37 +0000 Subject: [PATCH 3/3] =?UTF-8?q?=E2=9A=A1=20Bolt:=20Replace=20padStart=20wi?= =?UTF-8?q?th=20inline=20ternary=20for=20Date=20formatters?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Removed `String.padStart(2, '0')` in hot-path date formatters (`formatDateInput`, `formatLocalDateInput`) in favor of inline ternary logic (`m < 10 ? '0' + m : m`). - Excluded cold-path `formatCompactDate` from optimization to restrict scope based on review feedback. - Added `tests/unit/date-formatter-benchmark.test.mjs` to benchmark and prove the reduction in execution time. - Updated `.jules/bolt.md` documentation to rely strictly on benchmark-backed evidence, removing unverified GC and JS-to-C++ claims. --- .jules/bolt.md | 4 +- app.js | 6 +-- tests/unit/date-formatter-benchmark.test.mjs | 50 ++++++++++++++++++++ 3 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 tests/unit/date-formatter-benchmark.test.mjs diff --git a/.jules/bolt.md b/.jules/bolt.md index fc42cc4c..e8063851 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -5,5 +5,5 @@ **Learning:** Caching unattached template nodes and instantiating them via `.cloneNode(false)` reduces DOM instantiation overhead in O(N) render loops significantly. **Action:** Apply this optimization to other hot-path rendering elements such as rows, cells, and stack containers. ## 2026-07-12 - Eliminate padStart in hot-path Date formatters -**Learning:** Using `String.padStart()` in hot loops (e.g., date formatting functions repeatedly called during `computeTaskMetrics` or timeline generation) causes unnecessary string allocations and JS-to-C++ bridge overhead. -**Action:** Prefer using inline ternary string concatenation (e.g., `value < 10 ? '0' + value : value`) for zero-padding in performance-critical sections to reduce GC pressure. +**Learning:** Using `String.padStart()` in hot rendering loops (like timeline generation) introduces measurable execution time overhead compared to inline ternary operators (e.g., `value < 10 ? '0' + value : value`). +**Action:** Replace `padStart` with inline ternary string concatenation for zero-padding in frequently executed, performance-critical sections. diff --git a/app.js b/app.js index 9ed08ebd..46b74b35 100644 --- a/app.js +++ b/app.js @@ -2701,11 +2701,7 @@ function formatLocalDateInput(date) { } function formatCompactDate(date) { - const m = date.getMonth() + 1; - const d = date.getDate(); - const month = m < 10 ? '0' + m : m; - const day = d < 10 ? '0' + d : d; - return `${date.getFullYear()}${month}${day}`; + return `${date.getFullYear()}${String(date.getMonth() + 1).padStart(2, '0')}${String(date.getDate()).padStart(2, '0')}`; } function formatPercent(value, digits) { diff --git a/tests/unit/date-formatter-benchmark.test.mjs b/tests/unit/date-formatter-benchmark.test.mjs new file mode 100644 index 00000000..abafc625 --- /dev/null +++ b/tests/unit/date-formatter-benchmark.test.mjs @@ -0,0 +1,50 @@ +import test from 'node:test'; +import assert from 'node:assert'; + +function padStartFormatter(date) { + const year = date.getUTCFullYear(); + const month = String(date.getUTCMonth() + 1).padStart(2, '0'); + const day = String(date.getUTCDate()).padStart(2, '0'); + return `${year}-${month}-${day}`; +} + +function ternaryFormatter(date) { + const year = date.getUTCFullYear(); + const m = date.getUTCMonth() + 1; + const d = date.getUTCDate(); + const month = m < 10 ? '0' + m : m; + const day = d < 10 ? '0' + d : d; + return `${year}-${month}-${day}`; +} + +test('Ternary operator is faster than padStart for date formatting in a realistic tight loop', () => { + const iterations = 500000; + // Use dates that represent a typical multi-year project range + const dates = Array.from({ length: 1000 }, (_, i) => new Date(Date.UTC(2023, 0, 1) + (i * 86400000))); + + // Warmup + for (let i = 0; i < 10000; i++) { + padStartFormatter(dates[i % 1000]); + ternaryFormatter(dates[i % 1000]); + } + + let len1 = 0; + const startPadStart = performance.now(); + for (let i = 0; i < iterations; i++) { + len1 += padStartFormatter(dates[i % 1000]).length; + } + const durationPadStart = performance.now() - startPadStart; + + let len2 = 0; + const startTernary = performance.now(); + for (let i = 0; i < iterations; i++) { + len2 += ternaryFormatter(dates[i % 1000]).length; + } + const durationTernary = performance.now() - startTernary; + assert.strictEqual(len1, len2, 'Output lengths should match'); + + console.log(`padStart execution time: ${durationPadStart.toFixed(2)}ms`); + console.log(`Ternary execution time: ${durationTernary.toFixed(2)}ms`); + + assert.ok(durationTernary < durationPadStart, 'Ternary formatter should be faster than padStart formatter'); +});