Interval Timer Start
The Pass-Through Node That Turns Any Workflow Section Into a Stopwatch
- anything
- anything
- timer_handle
Interval Timer Start does absolutely nothing to your image. That's the point. It's the stamping-in half of a stopwatch - place it right before a section of your graph, connect the matching Interval Timer End after it, and you finally get a straight answer to "how long did the upscaler actually take?" It's from the tiny MIT-licensed pack aoiro0X0/ComfyUI-Interval-Timer ("Interval Timer"), and once you've benchmarked one checkpoint format against another, you'll wonder why you were eyeballing the server console before.
ComfyUI does have built-in profiling, but it reports per-node times, and "what did this whole stage cost, including the bits running in parallel" is exactly the question per-node numbers answer badly. This pack measures wall-clock time between two checkpoints instead - real elapsed time, parallel branches included. If you're comparing two samplers, an upscaler setting, or a batch size, this is the honest way to do it.
How it works
When the Start node executes, it grabs a high-resolution timestamp (time.perf_counter_ns(), nanosecond precision), packages it into a timer_handle, and hands back whatever value you fed it, unchanged. That's the entire mechanism. The clever part is ComfyUI's caching: it's aggressive about skipping nodes whose inputs haven't changed, and a timer that got cache-hit would report garbage. So Interval Timer Start declares itself always-changed via the classic IS_CHANGED returning NaN trick - not equal to anything, even itself - which forces it to re-execute on every queue.
The other thing you have to know is that ComfyUI executes a dependency graph, not left-to-right canvas order. Dropping Start next to the section you want to time and leaving it unwired establishes nothing. It has to sit in the data path, so the scheduler is forced to run it before the first node you're measuring.
The inputs and outputs that matter
This is a two-port node, which is refreshingly short:
- anything (required, any type) - connect the value that feeds the first node of the section. It's passed through unchanged, so Start slots into the middle of an existing wire without breaking anything.
- Output anything - the same value, on its way to the first measured node.
- Output timer_handle (
INTERVAL_TIMER_HANDLE) - the pairing token. Wire this to the matching Interval Timer End, and only to it. Each Start mints a fresh handle per run, so you can have several independent timers in one workflow without them colliding.
That's the whole surface. No widgets, no optional inputs, nothing to tune.
The honest gotcha: you just turned off caching
Because Start is always-changed, everything downstream of it re-runs on every queue even if its inputs are identical. For benchmarking that's the point - you want a fresh clock, and a cached section can't be timed. But leave the timer wired into a workflow you're iterating on for fast previews and you've silently disabled caching for that whole stretch, which the node-plumbing docs flag as the classic always-dirty footgun. Measure, note the number, then delete the timer. Cheap to remove, easy to re-add.
Install
Through ComfyUI Manager, search "Interval Timer" and install - or do it by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/aoiro0X0/ComfyUI-Interval-Timer.git
Then restart ComfyUI. The pyproject.toml lists zero Python dependencies, so there's nothing to pip-install and no model files to download. You'll find both nodes under utils/timing in the node list. Pair this with Interval Timer End and the elapsed readout appears right on the End node.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| anything | * | Connect a value that feeds the first measured node. The same value is passed through unchanged. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| anything | * | — |
| timer_handle | INTERVAL_TIMER_HANDLE | — |