Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions packages/web/src/lib/server/daily-rollup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -438,16 +438,16 @@ export async function getDailyRollupsForProjects(
const userSet = userSetsByDate.get(r.date)!
for (const u of r.activeUserIds) userSet.add(u)

// [Bolt: Performance Optimization] Use Object.keys() instead of Object.entries() in hot paths.
// Impact: Avoids array allocation for each key-value pair, significantly reducing GC overhead when aggregating large daily rollups.
for (const k of Object.keys(r.skillCounts)) {
prev.skillCounts[k] = (prev.skillCounts[k] ?? 0) + r.skillCounts[k]!
// [Bolt: Performance Optimization] Use for...in instead of Object.keys() in hot paths.
// Impact: Completely avoids array allocation for each key set, significantly reducing GC overhead when aggregating large daily rollups.
for (const k in r.skillCounts) {
if (Object.hasOwn(r.skillCounts, k)) prev.skillCounts[k] = (prev.skillCounts[k] ?? 0) + r.skillCounts[k]!
}
for (const k of Object.keys(r.agentCounts)) {
prev.agentCounts[k] = (prev.agentCounts[k] ?? 0) + r.agentCounts[k]!
for (const k in r.agentCounts) {
if (Object.hasOwn(r.agentCounts, k)) prev.agentCounts[k] = (prev.agentCounts[k] ?? 0) + r.agentCounts[k]!
}
for (const k of Object.keys(r.modelTokens)) {
prev.modelTokens[k] = (prev.modelTokens[k] ?? 0) + r.modelTokens[k]!
for (const k in r.modelTokens) {
if (Object.hasOwn(r.modelTokens, k)) prev.modelTokens[k] = (prev.modelTokens[k] ?? 0) + r.modelTokens[k]!
Comment on lines +443 to +450

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Own-key behavior remains equivalent

for...in with Object.hasOwn preserves Object.keys coverage. Key order cannot alter these sums, and ranked results are sorted afterward.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

}

// userStats: userId 기준 sum (지연된 Map 변환)
Expand Down Expand Up @@ -622,10 +622,10 @@ export function aggregateSummary(
totals.cacheCreationTokens += r.cacheCreationTokens
totals.estimatedCostUsd += r.estimatedCostUsd
for (const u of r.activeUserIds) activeUsers.add(u)
// [Bolt: Performance Optimization] Object.keys() iterations avoid internal array tuples, reducing heap thrashing
for (const k of Object.keys(r.skillCounts)) skillCounts[k] = (skillCounts[k] ?? 0) + r.skillCounts[k]!
for (const k of Object.keys(r.agentCounts)) agentCounts[k] = (agentCounts[k] ?? 0) + r.agentCounts[k]!
for (const k of Object.keys(r.modelTokens)) modelTokens[k] = (modelTokens[k] ?? 0) + r.modelTokens[k]!
// [Bolt: Performance Optimization] for...in iterations avoid internal array tuples and keys array allocation, reducing heap thrashing
for (const k in r.skillCounts) if (Object.hasOwn(r.skillCounts, k)) skillCounts[k] = (skillCounts[k] ?? 0) + r.skillCounts[k]!
for (const k in r.agentCounts) if (Object.hasOwn(r.agentCounts, k)) agentCounts[k] = (agentCounts[k] ?? 0) + r.agentCounts[k]!
for (const k in r.modelTokens) if (Object.hasOwn(r.modelTokens, k)) modelTokens[k] = (modelTokens[k] ?? 0) + r.modelTokens[k]!
}

// Deterministic tie-break: callCount DESC, skillName ASC (codepoint binary —
Expand Down
16 changes: 9 additions & 7 deletions packages/web/src/lib/server/weekly-report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -394,19 +394,21 @@ export async function getWeeklyReport(
// Insights — delegation
// ⚡ Bolt Optimization:
// 병목 지점: 기존 코드는 `thisWeekRollups`를 3번 순회하고, 매 순회마다 Object.values()로 중간 배열을 생성하여 메모리 할당 비용이 발생했습니다.
// 최적화 방법: 단일 for...of 루프와 Object.keys() 순회를 결합하여 N+1 순회를 1회 순회로 통합하고 중간 배열 할당을 제거했습니다.
// 기대 효과: `thisWeekRollups`의 크기가 클 경우, 불필요한 배열 생성 오버헤드와 O(N) 순회를 1/3로 줄여 리포트 생성 성능이 향상됩니다.
// 최적화 방법: 단일 for...of 루프와 for...in 순회를 결합하여 배열 할당을 완전히 제거하고 N+1 순회를 1회로 통합했습니다.
// 기대 효과: `thisWeekRollups`의 크기가 클 경우, 불필요한 배열 생성 오버헤드 및 O(N) 순회를 1/3로 줄이고 GC 오버헤드를 대폭 감소시켜 리포트 생성 성능이 향상됩니다.
Comment on lines +397 to +398

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Performance comments overstate the change

These comments claim all array allocation disappears and several traversals become one. The patch only removes key arrays from an already-unified loop.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

let totalAgentCalls = 0
let totalSkillCalls = 0
const distinctSkillsThisWeek = new Set<string>()

for (const r of thisWeekRollups) {
for (const k of Object.keys(r.agentCounts)) {
totalAgentCalls += r.agentCounts[k]
for (const k in r.agentCounts) {
if (Object.hasOwn(r.agentCounts, k)) totalAgentCalls += r.agentCounts[k]
}
for (const k of Object.keys(r.skillCounts)) {
totalSkillCalls += r.skillCounts[k]
distinctSkillsThisWeek.add(k)
for (const k in r.skillCounts) {
if (Object.hasOwn(r.skillCounts, k)) {
totalSkillCalls += r.skillCounts[k]
distinctSkillsThisWeek.add(k)
}
}
}

Expand Down
Loading