From f6289206d830f875bd1afc102c4e9b33d8d85ece Mon Sep 17 00:00:00 2001 From: vladmandic Date: Sat, 3 Jan 2026 07:54:05 +0100 Subject: [PATCH] startup sequence optimizations Signed-off-by: vladmandic --- CHANGELOG.md | 1 + modules/hashes.py | 17 ++++++++++------- modules/loader.py | 2 +- modules/shared.py | 33 ++++++++++++++++++++++----------- modules/shared_defaults.py | 1 - webui.py | 31 ++++++++++++++++++------------- 6 files changed, 52 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b95bb82b..a51ef653d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - update reference models previews, thanks @liutyi - update models specs page, thanks @alerikaisattera - sdnq improvements + - startup sequence optimizations - **Fixes** - extension tab: update checker, date handling, formatting etc., thanks @awsr - controlnet with non-english ui locales diff --git a/modules/hashes.py b/modules/hashes.py index 423fa51b9..ecfb9c914 100644 --- a/modules/hashes.py +++ b/modules/hashes.py @@ -1,9 +1,11 @@ import hashlib import os.path from rich import progress, errors -from modules import shared +from installer import log, console +from modules.json_helpers import readfile, writefile from modules.paths import data_path + cache_filename = os.path.join(data_path, "cache.json") cache_data = None progress_ok = True @@ -12,17 +14,17 @@ progress_ok = True def init_cache(): global cache_data # pylint: disable=global-statement if cache_data is None: - cache_data = {} if not os.path.isfile(cache_filename) else shared.readfile(cache_filename, lock=True, as_type="dict") + cache_data = {} if not os.path.isfile(cache_filename) else readfile(cache_filename, lock=True, as_type="dict") def dump_cache(): - shared.writefile(cache_data, cache_filename) + writefile(cache_data, cache_filename) def cache(subsection): global cache_data # pylint: disable=global-statement if cache_data is None: - cache_data = {} if not os.path.isfile(cache_filename) else shared.readfile(cache_filename, lock=True, as_type="dict") + cache_data = {} if not os.path.isfile(cache_filename) else readfile(cache_filename, lock=True, as_type="dict") s = cache_data.get(subsection, {}) cache_data[subsection] = s return s @@ -35,11 +37,11 @@ def calculate_sha256(filename, quiet=False): if not quiet: if progress_ok: try: - with progress.open(filename, 'rb', description=f'[cyan]Calculating hash: [yellow]{filename}', auto_refresh=True, console=shared.console) as f: + with progress.open(filename, 'rb', description=f'[cyan]Calculating hash: [yellow]{filename}', auto_refresh=True, console=console) as f: for chunk in iter(lambda: f.read(blksize), b""): hash_sha256.update(chunk) except errors.LiveError: - shared.log.warning('Hash: attempting to use function in a thread') + log.warning('Hash: attempting to use function in a thread') progress_ok = False if not progress_ok: with open(filename, 'rb') as f: @@ -65,6 +67,7 @@ def sha256_from_cache(filename, title, use_addnet_hash=False): def sha256(filename, title, use_addnet_hash=False): + from modules import shared global progress_ok # pylint: disable=global-statement hashes = cache("hashes-addnet") if use_addnet_hash else cache("hashes") sha256_value = sha256_from_cache(filename, title, use_addnet_hash) @@ -81,7 +84,7 @@ def sha256(filename, title, use_addnet_hash=False): with progress.open(filename, 'rb', description=f'[cyan]Calculating hash: [yellow]{filename}', auto_refresh=True, console=shared.console) as f: sha256_value = addnet_hash_safetensors(f) except errors.LiveError: - shared.log.warning('Hash: attempting to use function in a thread') + log.warning('Hash: attempting to use function in a thread') progress_ok = False if not progress_ok: with open(filename, 'rb') as f: diff --git a/modules/loader.py b/modules/loader.py index 5814baabb..cbd000987 100644 --- a/modules/loader.py +++ b/modules/loader.py @@ -13,7 +13,7 @@ initialized = False errors.install() logging.getLogger("DeepSpeed").disabled = True timer.startup.record("loader") - +errors.log.debug('Initializing: libraries') np = None try: diff --git a/modules/shared.py b/modules/shared.py index 9d6bc157b..3a3bdab5f 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -4,25 +4,27 @@ import os import sys import time import contextlib + from enum import Enum from typing import TYPE_CHECKING import gradio as gr +from installer import log, print_dict, console, get_version # pylint: disable=unused-import +log.debug('Initializing: shared module') + +import modules.memmon +import modules.paths as paths from modules.json_helpers import readfile, writefile # pylint: disable=W0611 from modules.shared_helpers import listdir, walk_files, html_path, html, req, total_tqdm # pylint: disable=W0611 +from modules import errors, devices, shared_state, cmd_args, theme, history, files_cache from modules.shared_defaults import get_default_modes -from modules import errors, devices, shared_items, shared_state, cmd_args, theme, history, files_cache from modules.paths import models_path, script_path, data_path, sd_configs_path, sd_default_config, sd_model_file, default_sd_model_file, extensions_dir, extensions_builtin_dir # pylint: disable=W0611 -from modules.dml import memory_providers, default_memory_provider, directml_do_hijack -from modules.onnx_impl import execution_providers from modules.memstats import memory_stats, ram_stats # pylint: disable=unused-import + +log.debug('Initializing: pipelines') +from modules import shared_items from modules.interrogate.openclip import caption_models, caption_types, get_clip_models, refresh_clip_models from modules.interrogate.vqa import vlm_models, vlm_prompts, vlm_system, vlm_default -from modules.ui_components import DropdownEditable -from modules.options import OptionInfo, options_section -import modules.memmon -import modules.styles -import modules.paths as paths -from installer import log, print_dict, console, get_version # pylint: disable=unused-import + if TYPE_CHECKING: # Behavior modified by __future__.annotations @@ -52,7 +54,6 @@ face_restorers = [] yolo = None tab_names = [] extra_networks: list[ExtraNetworksPage] = [] -options_templates: dict[str, OptionInfo | LegacyOption] = {} hypernetworks = {} settings_components = {} restricted_opts = { @@ -143,8 +144,15 @@ def list_samplers(): modules.sd_samplers.set_samplers() return modules.sd_samplers.all_samplers - +log.debug('Initializing: default modes') startup_offload_mode, startup_offload_min_gpu, startup_offload_max_gpu, startup_cross_attention, startup_sdp_options, startup_sdp_choices, startup_sdp_override_options, startup_sdp_override_choices, startup_offload_always, startup_offload_never = get_default_modes(cmd_opts=cmd_opts, mem_stat=mem_stat) +from modules.dml import memory_providers, default_memory_provider, directml_do_hijack +from modules.onnx_impl import execution_providers + +log.debug('Initializing: settings') +from modules.ui_components import DropdownEditable +from modules.options import OptionInfo, options_section +options_templates: dict[str, OptionInfo | LegacyOption] = {} options_templates.update(options_section(('sd', "Model Loading"), { "sd_backend": OptionInfo('diffusers', "Execution backend", gr.Radio, {"choices": ['diffusers', 'original'], "visible": False }), @@ -836,9 +844,12 @@ opts.data['uni_pc_order'] = max(2, opts.schedulers_solver_order) # compatibility log.info(f'Engine: backend={backend} compute={devices.backend} device={devices.get_optimal_device_name()} attention="{opts.cross_attention_optimization}" mode={devices.inference_context.__name__}') profiler = None +import modules.styles prompt_styles = modules.styles.StyleDatabase(opts) reference_models = readfile(os.path.join('html', 'reference.json'), as_type="dict") if opts.extra_network_reference_enable else {} cmd_opts.disable_extension_access = (cmd_opts.share or cmd_opts.listen or (cmd_opts.server_name or False)) and not cmd_opts.insecure + +log.debug('Initializing: devices') devices.args = cmd_opts devices.opts = opts devices.onnx = [opts.onnx_execution_provider] diff --git a/modules/shared_defaults.py b/modules/shared_defaults.py index 59058b566..8755f63c1 100644 --- a/modules/shared_defaults.py +++ b/modules/shared_defaults.py @@ -58,7 +58,6 @@ def get_default_modes(cmd_opts, mem_stat): elif devices.backend in {"directml", "cpu", "mps"}: default_sdp_override_options = ['Dynamic attention'] - return ( default_offload_mode, default_diffusers_offload_min_gpu_memory, diff --git a/webui.py b/webui.py index db1e2bb22..9cc17df28 100644 --- a/webui.py +++ b/webui.py @@ -9,13 +9,18 @@ import logging import importlib import contextlib from threading import Thread +from installer import log, git_commit, custom_excepthook, version +from modules import timer import modules.loader import modules.hashes - -from installer import log, git_commit, custom_excepthook, version -from modules import timer, paths, shared, extensions, gr_tempdir, modelloader, modeldata -from modules.call_queue import queue_lock, wrap_queued_call, wrap_gradio_gpu_call # pylint: disable=unused-import +import modules.paths import modules.devices +from modules import shared +from modules.call_queue import queue_lock, wrap_queued_call, wrap_gradio_gpu_call # pylint: disable=unused-import +import modules.gr_tempdir +import modules.modeldata +import modules.extensions +import modules.modelloader import modules.sd_checkpoint import modules.sd_samplers import modules.scripts_manager @@ -63,7 +68,7 @@ fastapi_args = { def initialize(): - log.debug('Initializing') + log.debug('Initializing: modules') modules.sd_checkpoint.init_metadata() modules.hashes.init_cache() @@ -80,7 +85,7 @@ def initialize(): modules.model_te.refresh_te_list() timer.startup.record("te") - modelloader.cleanup_models() + modules.modelloader.cleanup_models() modules.sd_models.setup_model() timer.startup.record("models") @@ -100,7 +105,7 @@ def initialize(): yolo.initialize() timer.startup.record("detailer") - extensions.list_extensions() + modules.extensions.list_extensions() timer.startup.record("extensions") log.info('Load extensions') @@ -110,7 +115,7 @@ def initialize(): timer.startup.records["extensions"] = t_total # scripts can reset the time log.debug(f'Extensions init time: {t_timer.summary()}') - modelloader.load_upscalers() + modules.modelloader.load_upscalers() timer.startup.record("upscalers") modules.ui_extra_networks.initialize() @@ -151,7 +156,7 @@ def initialize(): def load_model(): - modeldata.model_data.locked = False + modules.modeldata.model_data.locked = False autoload = shared.opts.sd_checkpoint_autoload or shared.cmd_opts.ckpt is not None log.info(f'Model: autoload={autoload} selected="{shared.opts.sd_model_checkpoint}"') if autoload: @@ -169,7 +174,7 @@ def load_model(): shared.opts.onchange("sd_vae", wrap_queued_call(lambda: modules.sd_vae.reload_vae_weights()), call=False) shared.opts.onchange("sd_unet", wrap_queued_call(lambda: modules.sd_unet.load_unet(shared.sd_model)), call=False) shared.opts.onchange("sd_text_encoder", wrap_queued_call(lambda: modules.sd_models.reload_text_encoder()), call=False) - shared.opts.onchange("temp_dir", gr_tempdir.on_tmpdir_changed) + shared.opts.onchange("temp_dir", modules.gr_tempdir.on_tmpdir_changed) timer.startup.record("onchange") @@ -232,7 +237,7 @@ def start_common(): log.info(f'Base path: data="{shared.cmd_opts.data_dir}"') if shared.cmd_opts.models_dir is not None and len(shared.cmd_opts.models_dir) > 0 and shared.cmd_opts.models_dir != 'models': log.info(f'Base path: models="{shared.cmd_opts.models_dir}"') - paths.create_paths(shared.opts) + modules.paths.create_paths(shared.opts) async_policy() initialize() if shared.cmd_opts.backend == 'original': @@ -245,7 +250,7 @@ def start_common(): except Exception: pass if shared.opts.clean_temp_dir_at_start: - gr_tempdir.cleanup_tmpdr() + modules.gr_tempdir.cleanup_tmpdr() timer.startup.record("cleanup") @@ -317,7 +322,7 @@ def start_ui(): _frontend=True and shared.cmd_opts.share, ) if shared.cmd_opts.data_dir is not None: - gr_tempdir.register_tmp_file(shared.demo, os.path.join(shared.cmd_opts.data_dir, 'x')) + modules.gr_tempdir.register_tmp_file(shared.demo, os.path.join(shared.cmd_opts.data_dir, 'x')) shared.log.info(f'Local URL: {local_url}') if shared.cmd_opts.listen: if not gradio_auth_creds: