Skip to content

Commit

Permalink
show progress while rendering (#111)
Browse files Browse the repository at this point in the history
  • Loading branch information
seveibar authored Jan 8, 2025
1 parent 8eed6b6 commit c38d20a
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 17 deletions.
21 changes: 21 additions & 0 deletions lib/components/CircuitJsonPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import {
EllipsisIcon,
EllipsisVerticalIcon,
FullscreenIcon,
LoaderCircleIcon,
LoaderIcon,
MinimizeIcon,
} from "lucide-react"
import {
Expand Down Expand Up @@ -153,6 +155,25 @@ export const CircuitJsonPreview = ({
isRunningCode={isRunningCode}
/> */}
{!leftHeaderContent && <div className="flex-grow" />}
{renderLog && renderLog.progress !== 1 && (
<div className="flex items-center gap-2">
{renderLog.lastRenderEvent && (
<div className="text-xs text-gray-500">
{
renderLog.lastRenderEvent?.type
.split("renderable:renderLifecycle:")[1]
.split(":")[0]
}
</div>
)}
<div className="w-4 h-4 bg-blue-500 opacity-50 rounded-full text-white">
<LoaderCircleIcon className="w-4 h-4 animate-spin" />
</div>
<div className="text-xs font-bold text-gray-700 tabular-nums">
{((renderLog.progress ?? 0) * 100).toFixed(1)}%
</div>
</div>
)}
<TabsList>
{showCodeTab && <TabsTrigger value="code">Code</TabsTrigger>}
<TabsTrigger value="pcb" className="whitespace-nowrap">
Expand Down
41 changes: 35 additions & 6 deletions lib/components/RunFrame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import { CircuitJsonPreview, type TabId } from "./CircuitJsonPreview"
import { useEffect, useRef, useState } from "react"
import Debug from "debug"

// TODO waiting for core PR: https://github.com/tscircuit/core/pull/489
// import { orderedRenderPhases } from "@tscircuit/core"

const numRenderPhases = 26

const debug = Debug("run-frame:RunFrame")

declare global {
Expand Down Expand Up @@ -155,14 +160,36 @@ export const RunFrame = (props: Props) => {
return
}

if (activeTab === "render_log") {
worker.on("renderable:renderLifecycle:anyEvent", (event: any) => {
const renderIds = new Set<string>()
worker.on("renderable:renderLifecycle:anyEvent", (event: any) => {
renderLog.lastRenderEvent = event
renderLog.eventsProcessed = (renderLog.eventsProcessed ?? 0) + 1
if (!renderIds.has(event.renderId)) {
renderIds.add(event.renderId)
}
const estTotalRenderEvents = renderIds.size * numRenderPhases * 2
const hasProcessedEnoughToEstimateProgress =
renderLog.eventsProcessed > renderIds.size * 2

// This estimated progress goes over 100% because of repeated render
// events, so we use a exponential decay to make it appear [0, 100%]
const estProgressLinear =
renderLog.eventsProcessed / estTotalRenderEvents

const estProgress = 1 - Math.exp(-estProgressLinear * 3)

renderLog.progress = hasProcessedEnoughToEstimateProgress
? estProgress
: 0

if (activeTab === "render_log") {
renderLog.renderEvents = renderLog.renderEvents ?? []
event.createdAt = Date.now()
renderLog.renderEvents.push(event)
setRenderLog(renderLog)
})
}
}

setRenderLog({ ...renderLog })
})

const evalResult = await worker
.executeWithFsMap({
Expand Down Expand Up @@ -207,8 +234,10 @@ export const RunFrame = (props: Props) => {
renderLog.phaseTimings = getPhaseTimingsFromRenderEvents(
renderLog.renderEvents ?? [],
)
setRenderLog(renderLog)
}
renderLog.progress = 1

setRenderLog({ ...renderLog })
}
runWorker()
}, [props.fsMap, props.entrypoint])
Expand Down
18 changes: 17 additions & 1 deletion lib/render-logging/RenderLog.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
export type RenderEvent = {
type:
| `renderable:renderLifecycle:${string}:start`
| `renderable:renderLifecycle:${string}:end`
/**
* Corresponds to the element that was rendered
*/
renderId: string
eventsProcessed: number
createdAt: number
}

export interface RenderLog {
renderEvents?: any[]
lastRenderEvent?: RenderEvent
eventsProcessed?: number
progress?: number

renderEvents?: RenderEvent[]

// Not sure if we can do this because of async
phaseTimings?: Record<string, number>
Expand Down
12 changes: 2 additions & 10 deletions lib/render-logging/getPhaseTimingsFromRenderEvents.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
type RenderEvent = {
type:
| `renderable:renderLifecycle:${string}:start`
| `renderable:renderLifecycle:${string}:end`
/**
* Corresponds to the element that was rendered
*/
renderId: string
createdAt: number
}
import type { RenderEvent } from "./RenderLog"

/**
* Given a list of render events, return a map of how much time was spent in each
* render phase.
Expand Down

0 comments on commit c38d20a

Please sign in to comment.