Nodes/ComfyUI-CustomNodePacks/Execution Timer (C2C)
ComfyUI Node

Execution Timer (C2C)

A stopwatch that lives inside your graph — time each stage without leaving ComfyUI

By Code2Collapse·Created 6 months ago·Updated a day ago· 52
Execution Timer (C2C)
  • passthrough
  • passthrough
  • report
  • elapsed_seconds
labelstage_a
resetfalse

Every serious workflow eventually needs to know where the seconds go. Is the bottleneck the sampler, the upscaler, or the VAE decode? ExecutionTimerMEC answers it with a stopwatch node you drop anywhere in the graph. It returns the number of seconds since the previous execution of the same label, passes whatever you route through it along unchanged, and gives you a readable report string. First tick returns 0 - that's the "I don't know yet, now I'm counting" baseline.

The trick that makes it work in ComfyUI is that the node forces itself to re-execute every run (via an IS_CHANGED hook that hashes its inputs), while normalizing by a label so multiple timer instances in one workflow don't clobber each other's state. Because ComfyUI executes lazily, a timer placed mid-graph measures the elapsed wall-clock time since that same spot last ran - which, in a linear pipeline, is effectively the duration of the stage before it.

How it works

Under the hood it keeps a class-level dict keyed by label, storing time.perf_counter() stamps. On each tick it looks up the previous stamp for that label, computes the delta, stores the new stamp, and returns three outputs: the passthrough payload untouched, a report string like [stage_a] +12.3456s, and the raw elapsed_seconds float you can feed to a display node or use in logic. The reset boolean forces the current tick to be treated as the first, which is your "restart the stopwatch" button.

The inputs and outputs

  • passthrough - any type (*); whatever you route through comes out the other side unchanged.
  • label - the per-timer key, default stage_a. Use distinct labels (stage_a, stage_b, …) for each timer in the graph.
  • reset - if true, this tick is the first (elapsed = 0).

Outputs: passthrough, report (STRING), and elapsed_seconds (FLOAT).

Installing it

Part of Code2Collapse/ComfyUI-CustomNodePacks. ComfyUI Manager → search "CustomNodePacks", or:

cd ComfyUI/custom_nodes
git clone https://github.com/Code2Collapse/ComfyUI-CustomNodePacks.git

Restart ComfyUI. No dependencies, no models - a stopwatch and a passthrough. (Standard pack rule: skip the root pip install -r requirements.txt over ComfyUI's bundled torch/numpy.)

Gotchas

The subtle one is the label. It's the cache key, so if you copy-paste a timer node and forget to change the label, both instances share one stopwatch and your timings go weird - two timers named stage_a measure each other, not their own stages. Give every timer a unique label. Second, the passthrough forces you to route a value through the node to place it in the graph - that's fine (it's the wiring that tells ComfyUI where the timer sits), but it means a timer at the very start of a workflow needs some dummy value to pass. And remember it measures elapsed time since the previous run of this spot, so first run of a fresh workflow always reports 0 - run the pipeline once to seed it, then read real numbers. For profiling a big render, drop these before and after the sampler and you'll finally know what's eating the time.

CategoryC2C/Helpers

Inputs (3)

NameTypeDefaultDescription
passthrough*
labelSTRINGstage_a
resetBOOLEANfalseIf true, this tick is treated as the first.

Outputs (3)

NameTypeDescription
passthrough*
reportSTRING
elapsed_secondsFLOAT