From bcf5477f9977e0cc2c8119825df9221e4616bfe2 Mon Sep 17 00:00:00 2001 From: LuqP2 Date: Wed, 24 Dec 2025 18:45:38 -0300 Subject: [PATCH] fix: registered timestamp on timer node --- README.md | 8 +++++--- metahub_save_node.py | 12 +++++++----- timer_node.py | 46 +++++++++++++++----------------------------- 3 files changed, 27 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index c3a69d8..d0a3b29 100644 --- a/README.md +++ b/README.md @@ -76,19 +76,21 @@ Connect any override input to replace auto-detected values: **MetaHub Timer Node (Recommended for accurate timing):** 1. Add "MetaHub Timer" node to your workflow -2. Connect one of these inputs: +2. Connect one of these inputs (Timer will record a timestamp when it executes): - `clip` - From CLIP loader or CLIPTextEncode (for total workflow time) - `latent` - From KSampler (for sampling + post-processing time) - `image` - From VAEDecode or image loader (for post-processing only) - `conditioning` - From CLIPTextEncode 3. Connect the corresponding output to continue your workflow (e.g., `clip` → CLIPTextEncode) 4. Connect `elapsed_time` output to Save Node's `generation_time_override` + - The Timer records a timestamp when it executes + - The Save Node automatically calculates elapsed time from this timestamp **Multiple Timers (Advanced profiling):** You can add multiple Timer nodes to measure different workflow stages: -- Timer at CLIP → total workflow time +- Timer at CLIP → total workflow time (from CLIP load to save) - Timer after KSampler → sampling + decode time -- Timer after VAEDecode → save/post-processing time +- Timer after VAEDecode → save/post-processing time only **Performance Overrides (Advanced):** For custom benchmarking, connect these hidden inputs: diff --git a/metahub_save_node.py b/metahub_save_node.py index dcc67b0..8fb3def 100644 --- a/metahub_save_node.py +++ b/metahub_save_node.py @@ -3,6 +3,7 @@ MetaHub Save Image Node for ComfyUI Advanced image saving with dual metadata support (A1111/Civitai + Image MetaHub) """ +import time from pathlib import Path from . import metadata_utils as utils from .workflow_extractor import WorkflowExtractor @@ -139,7 +140,7 @@ class MetaHubSaveNode: "generation_time_override": ("FLOAT", { "default": None, "forceInput": True, - "tooltip": "Override generation time (seconds)" + "tooltip": "Timestamp from MetaHub Timer Node (elapsed time calculated automatically)" }), }, "hidden": { @@ -250,11 +251,12 @@ class MetaHubSaveNode: height, width = images[0].shape[0], images[0].shape[1] # Determine final generation time - # Priority: generation_time_override (from MetaHub Timer Node) > legacy generation_time + # generation_time_override is a TIMESTAMP from Timer Node, calculate elapsed time print(f"[MetaHub Save] generation_time_override={generation_time_override}, generation_time={generation_time}") - if generation_time_override is not None: - final_time = generation_time_override - print(f"[MetaHub Save] Using generation_time_override: {final_time}s") + if generation_time_override is not None and generation_time_override > 0: + # Calculate elapsed time from Timer timestamp + final_time = time.time() - generation_time_override + print(f"[MetaHub Save] Calculated elapsed time from Timer: {final_time:.2f}s") elif generation_time > 0: final_time = generation_time print(f"[MetaHub Save] Using legacy generation_time: {final_time}s") diff --git a/timer_node.py b/timer_node.py index c7277ed..5d033dd 100644 --- a/timer_node.py +++ b/timer_node.py @@ -5,20 +5,20 @@ Measures workflow execution time from start to finish import time -# Global storage for workflow timers -_TIMER_START_TIMES = {} - class MetaHubTimerNode: """ - Timer node that measures workflow execution time. + Timer node that records a timestamp for workflow execution timing. Usage: - 1. Place this node at the START of your workflow - 2. Connect any input (image, latent, conditioning, etc.) to trigger it early + 1. Place this node where you want to START measuring time + 2. Connect any input (clip, image, latent, conditioning) to trigger it 3. Connect the 'elapsed_time' output to MetaHub Save Node's 'generation_time_override' - The timer starts when this node first executes in a workflow run. + How it works: + - This node records a timestamp when it executes + - The Save Node calculates elapsed time from this timestamp + - Place multiple timers to measure different workflow stages """ @classmethod @@ -41,8 +41,8 @@ class MetaHubTimerNode: def measure_time(self, clip=None, image=None, latent=None, conditioning=None): """ - Measures elapsed time since this timer node was first executed. - Each timer node instance tracks its own independent timing. + Records the current timestamp when this node executes. + The Save Node will calculate elapsed time from this timestamp. Args: clip: Optional CLIP input (passed through unchanged) @@ -51,30 +51,14 @@ class MetaHubTimerNode: conditioning: Optional CONDITIONING input (passed through unchanged) Returns: - (clip, image, latent, conditioning, elapsed_time): Original inputs and elapsed time in seconds + (clip, image, latent, conditioning, start_timestamp): Original inputs and start timestamp """ - current_time = time.time() + # Return current timestamp - Save Node will calculate elapsed time + start_timestamp = time.time() + print(f"[MetaHub Timer] Recording start timestamp: {start_timestamp}") - # Use this node instance's ID as unique timer identifier - # This allows multiple independent timers in the same workflow - timer_id = id(self) - - # Start timer on first execution of this specific timer instance - if timer_id not in _TIMER_START_TIMES: - _TIMER_START_TIMES[timer_id] = current_time - print(f"[MetaHub Timer] Started timer #{timer_id}") - - # Cleanup old timers (keep only last 50 to support multiple timers) - if len(_TIMER_START_TIMES) > 50: - oldest_key = min(_TIMER_START_TIMES.keys(), key=lambda k: _TIMER_START_TIMES[k]) - del _TIMER_START_TIMES[oldest_key] - - # Calculate elapsed time - elapsed = current_time - _TIMER_START_TIMES[timer_id] - print(f"[MetaHub Timer] Elapsed time: {elapsed:.2f}s") - - # Passthrough the inputs unchanged + return elapsed time - return (clip, image, latent, conditioning, elapsed) + # Passthrough the inputs unchanged + return start timestamp + return (clip, image, latent, conditioning, start_timestamp) NODE_CLASS_MAPPINGS = {