perf: avoid intermediate Date objects in trace aggregation loop
Store timestamps as numbers during the aggregation loop instead of creating 2 Date objects per LLM call per existing trace entry. Convert to Date once per trace at the end. Also sort on numeric timestamps instead of calling .getTime() in the comparator, and use a for-of loop instead of .forEach for slightly less overhead.
This commit is contained in:
parent
1ef61d1e76
commit
bcaf08b508
1 changed files with 28 additions and 16 deletions
|
|
@ -359,12 +359,13 @@ async function TracesPageContent({
|
|||
const orgs = await getUniqueOrganizations()
|
||||
|
||||
// Group by trace_id and calculate aggregates
|
||||
const traceMap = new Map<
|
||||
// Use numeric timestamps during aggregation to avoid creating Date objects per iteration
|
||||
const traceAggMap = new Map<
|
||||
string,
|
||||
{
|
||||
trace_id: string
|
||||
first_seen: Date
|
||||
last_seen: Date
|
||||
first_seen_ms: number
|
||||
last_seen_ms: number
|
||||
call_count: number
|
||||
total_cost: number
|
||||
total_tokens: number
|
||||
|
|
@ -375,11 +376,11 @@ async function TracesPageContent({
|
|||
}
|
||||
>()
|
||||
|
||||
llmCalls.forEach(call => {
|
||||
if (!call.trace_id) return
|
||||
for (const call of llmCalls) {
|
||||
if (!call.trace_id) continue
|
||||
|
||||
const callTimestamp = new Date(call.created_at).getTime()
|
||||
const existing = traceMap.get(call.trace_id)
|
||||
const existing = traceAggMap.get(call.trace_id)
|
||||
const { cost: callCost, tokens: callTokens } = safeCostTokens(
|
||||
call.llm_cost,
|
||||
call.total_tokens,
|
||||
|
|
@ -392,13 +393,13 @@ async function TracesPageContent({
|
|||
if (call.status === "failed") existing.failed_calls++
|
||||
if (call.status === "partial_success") existing.hasPartial = true
|
||||
if (call.call_type) existing.call_types.add(call.call_type)
|
||||
existing.first_seen = new Date(Math.min(existing.first_seen.getTime(), callTimestamp))
|
||||
existing.last_seen = new Date(Math.max(existing.last_seen.getTime(), callTimestamp))
|
||||
if (callTimestamp < existing.first_seen_ms) existing.first_seen_ms = callTimestamp
|
||||
if (callTimestamp > existing.last_seen_ms) existing.last_seen_ms = callTimestamp
|
||||
} else {
|
||||
traceMap.set(call.trace_id, {
|
||||
traceAggMap.set(call.trace_id, {
|
||||
trace_id: call.trace_id,
|
||||
first_seen: new Date(callTimestamp),
|
||||
last_seen: new Date(callTimestamp),
|
||||
first_seen_ms: callTimestamp,
|
||||
last_seen_ms: callTimestamp,
|
||||
call_count: 1,
|
||||
total_cost: callCost,
|
||||
total_tokens: callTokens,
|
||||
|
|
@ -408,13 +409,24 @@ async function TracesPageContent({
|
|||
call_types: new Set(call.call_type ? [call.call_type] : []),
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Convert to array and sort by last_seen desc
|
||||
// Convert to final shape with Date objects and sort by last_seen desc
|
||||
// No need to paginate here - already done at database level
|
||||
const traces = Array.from(traceMap.values()).sort(
|
||||
(a, b) => b.last_seen.getTime() - a.last_seen.getTime(),
|
||||
)
|
||||
const traces = Array.from(traceAggMap.values())
|
||||
.sort((a, b) => b.last_seen_ms - a.last_seen_ms)
|
||||
.map(t => ({
|
||||
trace_id: t.trace_id,
|
||||
first_seen: new Date(t.first_seen_ms),
|
||||
last_seen: new Date(t.last_seen_ms),
|
||||
call_count: t.call_count,
|
||||
total_cost: t.total_cost,
|
||||
total_tokens: t.total_tokens,
|
||||
failed_calls: t.failed_calls,
|
||||
hasPartial: t.hasPartial,
|
||||
status: t.status,
|
||||
call_types: t.call_types,
|
||||
}))
|
||||
const totalPages = Math.ceil(totalTracesCount / pageSize)
|
||||
|
||||
return (
|
||||
|
|
|
|||
Loading…
Reference in a new issue