redesign profiler

This commit is contained in:
Vladimir Mandic
2023-12-03 11:27:24 -05:00
parent 54ef5f8683
commit 439542d3df
22 changed files with 172 additions and 109 deletions
+8 -22
View File
@@ -1,22 +1,16 @@
import re
import gradio as gr
from fastapi import FastAPI
import network
import networks
import lora # noqa:F401 # pylint: disable=unused-import
# import lora_patches
import extra_networks_lora
import ui_extra_networks_lora
from network import NetworkOnDisk
from ui_extra_networks_lora import ExtraNetworksPageLora
from extra_networks_lora import ExtraNetworkLora
# import lora # noqa:F401 # pylint: disable=unused-import
from modules import script_callbacks, ui_extra_networks, extra_networks, shared
# def unload():
# networks.originals.undo()
def before_ui():
ui_extra_networks.register_page(ui_extra_networks_lora.ExtraNetworksPageLora())
networks.extra_network_lora = extra_networks_lora.ExtraNetworkLora()
ui_extra_networks.register_page(ExtraNetworksPageLora())
networks.extra_network_lora = ExtraNetworkLora()
extra_networks.register_extra_network(networks.extra_network_lora)
# extra_networks.register_extra_network_alias(networks.extra_network_lora, "lyco")
@@ -28,15 +22,7 @@ script_callbacks.on_before_ui(before_ui)
script_callbacks.on_infotext_pasted(networks.infotext_pasted)
shared.options_templates.update(shared.options_section(('extra_networks', "Extra Networks"), {
# "sd_lora": shared.OptionInfo("None", "Add network to prompt", gr.Dropdown, lambda: {"choices": ["None", *networks.available_networks], "visible": False}, refresh=networks.list_available_networks),
"sd_lora": shared.OptionInfo("None", "Add network to prompt", gr.Dropdown, {"choices": ["None"], "visible": False}),
# "lora_show_all": shared.OptionInfo(False, "Always show all networks on the Lora page").info("otherwise, those detected as for incompatible version of Stable Diffusion will be hidden"),
# "lora_hide_unknown_for_versions": shared.OptionInfo([], "Hide networks of unknown versions for model versions", gr.CheckboxGroup, {"choices": ["SD1", "SD2", "SDXL"]}),
}))
def create_lora_json(obj: network.NetworkOnDisk):
def create_lora_json(obj: NetworkOnDisk):
return {
"name": obj.name,
"alias": obj.alias,
@@ -45,7 +31,7 @@ def create_lora_json(obj: network.NetworkOnDisk):
}
def api_networks(_: gr.Blocks, app: FastAPI):
def api_networks(_, app: FastAPI):
@app.get("/sdapi/v1/loras")
async def get_loras():
return [create_lora_json(obj) for obj in networks.available_networks.values()]
@@ -91,7 +91,7 @@ class ExtraNetworksPageLora(ui_extra_networks.ExtraNetworksPage):
return None
def list_items(self):
with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor:
with concurrent.futures.ThreadPoolExecutor(max_workers=shared.max_workers) as executor:
future_items = {executor.submit(self.create_item, net): net for net in networks.available_networks}
for future in concurrent.futures.as_completed(future_items):
item = future.result()
+5 -15
View File
@@ -6,8 +6,6 @@ import shutil
import logging
import platform
import subprocess
import io
import pstats
import cProfile
import pkg_resources
@@ -29,6 +27,7 @@ opts = {}
args = Dot({
'debug': False,
'reset': False,
'profile': False,
'upgrade': False,
'skip_extensions': False,
'skip_requirements': False,
@@ -143,19 +142,9 @@ def print_dict(d):
return ' '.join([f'{k}={v}' for k, v in d.items()])
def print_profile(profile: cProfile.Profile, msg: str):
try:
from rich import print # pylint: disable=redefined-builtin
except Exception:
pass
profile.disable()
stream = io.StringIO()
ps = pstats.Stats(profile, stream=stream)
ps.sort_stats(pstats.SortKey.CUMULATIVE).print_stats(15)
profile = None
lines = stream.getvalue().split('\n')
lines = [line for line in lines if '<frozen' not in line and '{built-in' not in line and '/logging' not in line and '/rich' not in line]
print(f'Profile {msg}:', '\n'.join(lines))
def print_profile(profiler: cProfile.Profile, msg: str):
from modules.errors import profile
profile(profiler, msg)
# check if package is installed
@@ -768,6 +757,7 @@ def set_environment():
os.environ.setdefault('TF_ENABLE_ONEDNN_OPTS', '0')
os.environ.setdefault('USE_TORCH', '1')
os.environ.setdefault('UVICORN_TIMEOUT_KEEP_ALIVE', '60')
os.environ.setdefault('KINETO_LOG_LEVEL', '3')
os.environ.setdefault('HF_HUB_CACHE', opts.get('hfcache_dir', os.path.join(os.path.expanduser('~'), '.cache', 'huggingface', 'hub')))
log.debug(f'Cache folder: {os.environ.get("HF_HUB_CACHE")}')
if sys.platform == 'darwin':
+1 -7
View File
@@ -2,9 +2,6 @@ import html
import threading
import time
import cProfile
import pstats
import io
from rich import print # pylint: disable=redefined-builtin
from modules import shared, progress, errors
queue_lock = threading.Lock()
@@ -62,10 +59,7 @@ def wrap_gradio_call(func, extra_outputs=None, add_stats=False, name=None):
else:
res = list(res)
if shared.cmd_opts.profile:
pr.disable()
s = io.StringIO()
pstats.Stats(pr, stream=s).sort_stats(pstats.SortKey.CUMULATIVE).print_stats(15)
print('Profile Exec:', s.getvalue())
errors.profile(pr, 'Wrap')
except Exception as e:
errors.display(e, 'gradio call')
if extra_outputs_array is None:
+22
View File
@@ -150,6 +150,25 @@ def torch_gc(force=False):
log.debug(f'gc: collected={collected} device={torch.device(get_optimal_device_name())} {memstats.memory_stats()}')
def set_cuda_sync_mode(mode):
"""
Set the CUDA device synchronization mode: auto, spin, yield or block.
auto: Chooses spin or yield depending on the number of available CPU cores.
spin: Runs one CPU core per GPU at 100% to poll for completed operations.
yield: Gives control to other threads between polling, if any are waiting.
block: Lets the thread sleep until the GPU driver signals completion.
"""
if mode == -1 or mode == 'none' or not cuda_ok:
return
try:
import ctypes
log.info(f'Set cuda synch: mode={mode}')
torch.cuda.set_device(torch.device(get_optimal_device_name()))
ctypes.CDLL('libcudart.so').cudaSetDeviceFlags({'auto': 0, 'spin': 1, 'yield': 2, 'block': 4}[mode])
except Exception:
pass
def test_fp16():
if shared.cmd_opts.experimental:
return True
@@ -272,6 +291,9 @@ dtype = torch.float16
dtype_vae = torch.float16
dtype_unet = torch.float16
unet_needs_upcast = False
if args.profile:
log.info(f'Torch build config: {torch.__config__.show()}')
# set_cuda_sync_mode('block') # none/auto/spin/yield/block
def cond_cast_unet(tensor):
+31
View File
@@ -55,3 +55,34 @@ def run(code, task):
def exception(suppress=[]): # noqa: B006
console.print_exception(show_locals=False, max_frames=10, extra_lines=2, suppress=suppress, theme="ansi_dark", word_wrap=False, width=min([console.width, 200]))
def profile(profiler, msg: str):
profiler.disable()
import io
import pstats
stream = io.StringIO() # pylint: disable=abstract-class-instantiated
p = pstats.Stats(profiler, stream=stream)
p.sort_stats(pstats.SortKey.CUMULATIVE)
p.print_stats(100)
# p.print_title()
# p.print_call_heading(10, 'time')
# p.print_callees(10)
# p.print_callers(10)
profiler = None
lines = stream.getvalue().split('\n')
lines = [l for l in lines if '<frozen' not in l and '{built-in' not in l and '/logging' not in l and 'Ordered by' not in l and 'List reduced' not in l and '_lsprof' not in l and '/profiler' not in l and 'rich' not in l and l.strip() != '']
txt = '\n'.join(lines[:min(5, len(lines))])
log.debug(f'Profile {msg}: {txt}')
def profile_torch(profiler, msg: str):
profiler.stop()
from rich import print # pylint: disable=redefined-builtin
# lines = profiler.key_averages().table(sort_by="self_cuda_time_total", row_limit=6)
lines = profiler.key_averages().table(sort_by="self_cpu_time_total", row_limit=12)
lines = lines.split('\n')
lines = [l for l in lines if '/profiler' not in l and '---' not in l]
txt = '\n'.join(lines)
# print(f'Torch {msg}:', txt)
log.debug(f'Torch profile {msg}: \n{txt}')
+13
View File
@@ -42,3 +42,16 @@ errors.install([gradio])
import diffusers # pylint: disable=W0611,C0411
timer.startup.record("diffusers")
errors.log.info(f'Load packages: torch={getattr(torch, "__long_version__", torch.__version__)} diffusers={diffusers.__version__} gradio={gradio.__version__}')
try:
import os
import math
cores = os.cpu_count()
affinity = len(os.sched_getaffinity(0))
threads = torch.get_num_threads()
if threads < (affinity / 2):
torch.set_num_threads(math.floor(affinity / 2))
threads = torch.get_num_threads()
errors.log.debug(f'Detected: cores={cores} affinity={affinity} set threads={threads}')
except Exception as e:
pass
+3 -1
View File
@@ -574,6 +574,7 @@ def move_files(src_path: str, dest_path: str, ext_filter: str = None):
def load_upscalers():
# We can only do this 'magic' method to dynamically load upscalers if they are referenced, so we'll try to import any _model.py files before looking in __subclasses__
t0 = time.time()
modules_dir = os.path.join(shared.script_path, "modules", "postprocess")
for file in os.listdir(modules_dir):
if "_model.py" in file:
@@ -602,4 +603,5 @@ def load_upscalers():
datas += scaler.scalers
names.append(name[8:])
shared.sd_upscalers = sorted(datas, key=lambda x: x.name.lower() if not isinstance(x.scaler, (UpscalerNone, UpscalerLanczos, UpscalerNearest)) else "") # Special case for UpscalerNone keeps it at the beginning of the list.
shared.log.debug(f"Load upscalers: total={len(shared.sd_upscalers)} downloaded={len([x for x in shared.sd_upscalers if x.data_path is not None and os.path.isfile(x.data_path)])} user={len([x for x in shared.sd_upscalers if x.custom])} {names}")
t1 = time.time()
shared.log.debug(f"Load upscalers: total={len(shared.sd_upscalers)} downloaded={len([x for x in shared.sd_upscalers if x.data_path is not None and os.path.isfile(x.data_path)])} user={len([x for x in shared.sd_upscalers if x.custom])} time={t1-t0:.2f} {names}")
+15 -41
View File
@@ -18,7 +18,7 @@ from ldm.models.diffusion.ddpm import LatentDepth2ImageDiffusion
from einops import repeat, rearrange
from blendmodes.blend import blendLayers, BlendType
from installer import git_commit
from modules import shared, devices
from modules import shared, devices, errors
import modules.memstats
import modules.lowvram
import modules.masking
@@ -666,36 +666,6 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts=None, all_seeds=No
return infotext
"""
def print_profile(profile, msg: str):
try:
from rich import print # pylint: disable=redefined-builtin
except Exception:
pass
lines = profile.key_averages().table(sort_by="cuda_time_total", row_limit=20)
lines = lines.split('\n')
lines = [l for l in lines if '/profiler' not in l]
print(f'Profile {msg}:', '\n'.join(lines))
"""
def print_profile(profile, msg: str):
import io
import pstats
try:
from rich import print # pylint: disable=redefined-builtin
except Exception:
pass
profile.disable()
stream = io.StringIO() # pylint: disable=abstract-class-instantiated
ps = pstats.Stats(profile, stream=stream)
ps.sort_stats(pstats.SortKey.CUMULATIVE).print_stats(15)
profile = None
lines = stream.getvalue().split('\n')
lines = [line for line in lines if '<frozen' not in line and '{built-in' not in line and '/logging' not in line and '/rich' not in line]
print(f'Profile {msg}:', '\n'.join(lines))
def process_images(p: StableDiffusionProcessing) -> Processed:
if not hasattr(p.sd_model, 'sd_checkpoint_info'):
return None
@@ -743,22 +713,26 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
modules.script_callbacks.before_process_callback(p)
if shared.cmd_opts.profile:
"""
import torch.profiler # pylint: disable=redefined-outer-name
with torch.profiler.profile(profile_memory=True, with_modules=True) as prof:
with torch.profiler.record_function("process_images"):
res = process_images_inner(p)
print_profile(prof, 'process_images')
"""
import cProfile
pr = cProfile.Profile()
pr.enable()
profile_python = cProfile.Profile()
profile_python.enable()
with context_hypertile_vae(p), context_hypertile_unet(p):
import torch.profiler # pylint: disable=redefined-outer-name
activities=[torch.profiler.ProfilerActivity.CPU]
if torch.cuda.is_available():
activities.append(torch.profiler.ProfilerActivity.CUDA)
shared.log.debug(f'Torch profile: activities={activities}')
if shared.profiler is None:
shared.profiler = torch.profiler.profile(activities=activities, profile_memory=True, with_modules=True)
shared.profiler.start()
shared.profiler.step()
res = process_images_inner(p)
print_profile(pr, 'Torch')
errors.profile_torch(shared.profiler, 'Process')
errors.profile(profile_python, 'Process')
else:
with context_hypertile_vae(p), context_hypertile_unet(p):
res = process_images_inner(p)
finally:
if not shared.opts.cuda_compile:
modules.sd_models.apply_token_merging(p.sd_model, 0)
+14
View File
@@ -85,6 +85,8 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro
return kwargs
kwargs = correction_callback(p, timestep, kwargs)
shared.state.current_latent = kwargs['latents']
if shared.cmd_opts.profile and shared.profiler is not None:
shared.profiler.step()
return kwargs
def full_vae_decode(latents, model):
@@ -139,6 +141,7 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro
return encoded
def vae_decode(latents, model, output_type='np', full_quality=True):
t0 = time.time()
prev_job = shared.state.job
shared.state.job = 'vae'
if not torch.is_tensor(latents): # already decoded
@@ -163,6 +166,9 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro
# decoded = validate_sample(decoded)
imgs = model.image_processor.postprocess(decoded, output_type=output_type)
shared.state.job = prev_job
if shared.cmd_opts.profile:
t1 = time.time()
shared.log.debug(f'Profile: VAE decode: {t1-t0:.2f}')
return imgs
def vae_encode(image, model, full_quality=True): # pylint: disable=unused-variable
@@ -269,6 +275,7 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro
return task_args
def set_pipeline_args(model, prompts: list, negative_prompts: list, prompts_2: typing.Optional[list]=None, negative_prompts_2: typing.Optional[list]=None, desc:str='', **kwargs):
t0 = time.time()
if hasattr(model, "set_progress_bar_config"):
model.set_progress_bar_config(bar_format='Progress {rate_fmt}{postfix} {bar} {percentage:3.0f}% {n_fmt}/{total_fmt} {elapsed} {remaining} ' + '\x1b[38;5;71m' + desc, ncols=80, colour='#327fba')
args = {}
@@ -379,6 +386,9 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro
shared.log.debug(txt)
# components = [{ k: getattr(v, 'device', None) } for k, v in model.components.items()]
# shared.log.debug(f'Diffuser pipeline components: {components}')
if shared.cmd_opts.profile:
t1 = time.time()
shared.log.debug(f'Profile: pipeline args: {t1-t0:.2f}')
return args
def recompile_model(hires=False):
@@ -502,7 +512,11 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro
p.extra_generation_params['Pipeline'] = shared.sd_model.__class__.__name__
p.extra_generation_params["Sampler Eta"] = shared.opts.scheduler_eta if shared.opts.scheduler_eta is not None and shared.opts.scheduler_eta > 0 and shared.opts.scheduler_eta < 1 else None
try:
t0 = time.time()
output = shared.sd_model(**base_args) # pylint: disable=not-callable
if shared.cmd_opts.profile:
t1 = time.time()
shared.log.debug(f'Profile: pipeline call: {t1-t0:.2f}')
if not hasattr(output, 'images') and hasattr(output, 'frames'):
shared.log.debug(f'Generated: frames={len(output.frames[0])}')
output.images = output.frames[0]
+1 -1
View File
@@ -329,7 +329,7 @@ def before_ui_callback():
def add_callback(callbacks, fun):
stack = [x for x in inspect.stack() if x.filename != __file__]
stack = [x for x in inspect.stack(0) if x.filename != __file__]
filename = stack[0].filename if len(stack) > 0 else 'unknown file'
callbacks.append(ScriptCallback(filename, fun))
+7 -1
View File
@@ -3,7 +3,7 @@ import os
import contextlib
import importlib.util
import modules.errors as errors
from installer import setup_logging
from installer import setup_logging, args
preloaded = []
@@ -12,6 +12,10 @@ preloaded = []
def load_module(path):
module_spec = importlib.util.spec_from_file_location(os.path.basename(path), path)
module = importlib.util.module_from_spec(module_spec)
if args.profile:
import cProfile
pr = cProfile.Profile()
pr.enable()
try:
if '/sd-extension-' in path: # safe extensions without stdout intercept
module_spec.loader.exec_module(module)
@@ -25,6 +29,8 @@ def load_module(path):
errors.log.info(f"Extension: script='{os.path.relpath(path)}' {line.strip()}")
except Exception as e:
errors.display(e, f'Module load: {path}')
if args.profile:
errors.profile(pr, f'Scripts: {path}')
return module
+1 -2
View File
@@ -261,6 +261,7 @@ def load_scripts():
elif issubclass(script_class, scripts_postprocessing.ScriptPostprocessing):
postprocessing_scripts_data.append(ScriptClassData(script_class, scriptfile.path, scriptfile.basedir, module))
from installer import args
for scriptfile in scripts_list:
try:
if scriptfile.basedir != paths.script_path:
@@ -274,12 +275,10 @@ def load_scripts():
current_basedir = paths.script_path
t.record(os.path.basename(scriptfile.basedir))
sys.path = syspath
global scripts_txt2img, scripts_img2img, scripts_postproc # pylint: disable=global-statement
scripts_txt2img = ScriptRunner()
scripts_img2img = ScriptRunner()
scripts_postproc = scripts_postprocessing.ScriptPostprocessingRunner()
return t, time.time()-t0
+6
View File
@@ -760,6 +760,10 @@ def set_diffuser_options(sd_model, vae, op: str):
def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=None, op='model'): # pylint: disable=unused-argument
import torch # pylint: disable=reimported,redefined-outer-name
if shared.cmd_opts.profile:
import cProfile
pr = cProfile.Profile()
pr.enable()
if timer is None:
timer = Timer()
logging.getLogger("diffusers").setLevel(logging.ERROR)
@@ -976,6 +980,8 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No
timer.record("load")
devices.torch_gc(force=True)
if shared.cmd_opts.profile:
errors.profile(pr, 'Load')
script_callbacks.model_loaded_callback(sd_model)
shared.log.info(f"Load {op}: time={timer.summary()} native={get_native(sd_model)} {memory_stats()}")
+2
View File
@@ -781,6 +781,7 @@ class Options:
value = expected_type(value)
return value
profiler = None
opts = Options()
config_filename = cmd_opts.config
opts.load(config_filename)
@@ -804,6 +805,7 @@ device = devices.device
batch_cond_uncond = opts.always_batch_cond_uncond or not (cmd_opts.lowvram or cmd_opts.medvram)
parallel_processing_allowed = not cmd_opts.lowvram
mem_mon = modules.memmon.MemUsageMonitor("MemMon", devices.device)
max_workers = 2
if devices.backend == "directml":
directml_do_hijack()
+25 -12
View File
@@ -4,6 +4,7 @@ import re
import os
import csv
import json
import time
from installer import log
@@ -87,6 +88,7 @@ class StyleDatabase:
def load_style(self, fn, prefix=None):
with open(fn, 'r', encoding='utf-8') as f:
new_style = None
try:
all_styles = json.load(f)
if type(all_styles) is dict:
@@ -100,7 +102,7 @@ class StyleDatabase:
name = os.path.join(prefix, name)
else:
name = os.path.join(os.path.dirname(os.path.relpath(fn, self.path)), name)
self.styles[style["name"]] = Style(
new_style = Style(
name=name,
desc=style.get('description', name),
prompt=style.get("prompt", ""),
@@ -110,26 +112,37 @@ class StyleDatabase:
filename=fn,
mtime=os.path.getmtime(fn),
)
self.styles[style["name"]] = new_style
except Exception as e:
log.error(f'Failed to load style: file={fn} error={e}')
return new_style
def reload(self):
t0 = time.time()
self.styles.clear()
def list_folder(folder):
for filename in os.listdir(folder):
fn = os.path.abspath(os.path.join(folder, filename))
if os.path.isfile(fn) and fn.lower().endswith(".json"):
self.load_style(fn)
elif os.path.isdir(fn) and not fn.startswith('.'):
list_folder(fn)
import concurrent
future_items = {}
with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor:
for filename in os.listdir(folder):
fn = os.path.abspath(os.path.join(folder, filename))
if os.path.isfile(fn) and fn.lower().endswith(".json"):
future_items[executor.submit(self.load_style, fn, None)] = fn
# self.load_style(fn)
elif os.path.isdir(fn) and not fn.startswith('.'):
list_folder(fn)
self.styles = dict(sorted(self.styles.items(), key=lambda style: style[1].filename))
if self.built_in:
fn = os.path.join('html', 'art-styles.json')
future_items[executor.submit(self.load_style, fn, 'built-in')] = fn
for future in concurrent.futures.as_completed(future_items):
future.result()
list_folder(self.path)
self.styles = dict(sorted(self.styles.items(), key=lambda style: style[1].filename))
if self.built_in:
self.load_style(os.path.join('html', 'art-styles.json'), 'built-in')
log.debug(f'Load styles: folder="{self.path}" items={len(self.styles.keys())}')
t1 = time.time()
log.debug(f'Load styles: folder="{self.path}" items={len(self.styles.keys())} time={t1-t0:.2f}')
def find_style(self, name):
found = [style for style in self.styles.values() if style.name == name]
+10 -2
View File
@@ -15,7 +15,7 @@ from collections import OrderedDict
import gradio as gr
from PIL import Image
from starlette.responses import FileResponse, JSONResponse
from modules import paths, shared, scripts, modelloader
from modules import paths, shared, scripts, modelloader, errors
from modules.ui_components import ToolButton
import modules.ui_symbols as symbols
@@ -270,7 +270,7 @@ class ExtraNetworksPage:
self.html = f"<div id='{tabname}_{self_name_id}_subdirs' class='extra-network-subdirs'>{subdirs_html}</div><div id='{tabname}_{self_name_id}_cards' class='extra-network-cards'>{self.html}</div>"
else:
return ''
shared.log.debug(f"Extra networks: page='{self.name}' items={len(self.items)} subfolders={len(subdirs)} tab={tabname} folders={self.allowed_directories_for_previews()} list={self.list_time:.2f} desc={self.desc_time:.2f} info={self.info_time:.2f}")
shared.log.debug(f"Extra networks: page='{self.name}' items={len(self.items)} subfolders={len(subdirs)} tab={tabname} folders={self.allowed_directories_for_previews()} list={self.list_time:.2f} desc={self.desc_time:.2f} info={self.info_time:.2f} workers={shared.max_workers}")
if len(self.missing_thumbs) > 0:
threading.Thread(target=self.create_thumb).start()
return self.html
@@ -463,6 +463,10 @@ def create_ui(container, button_parent, tabname, skip_indexing = False):
ui.tabs = gr.Tabs(elem_id=tabname+"_extra_tabs")
ui.button_details = gr.Button('Details', elem_id=tabname+"_extra_details_btn", visible=False)
state = {}
if shared.cmd_opts.profile:
import cProfile
pr = cProfile.Profile()
pr.enable()
def get_item(state, params = None):
if params is not None and type(params) == dict:
@@ -567,6 +571,10 @@ def create_ui(container, button_parent, tabname, skip_indexing = False):
page_html = gr.HTML(page.html, elem_id=f'{tabname}{page.name}_extra_page', elem_classes="extra-networks-page")
ui.pages.append(page_html)
tab.select(ui_tab_change, _js="getENActivePage", inputs=[ui.button_details], outputs=[ui.button_scan, ui.button_save, ui.button_model])
if shared.cmd_opts.profile:
errors.profile(pr, 'ExtraNetworks')
pr.disable()
# ui.tabs.change(fn=ui_tab_change, inputs=[], outputs=[ui.button_scan, ui.button_save])
def fn_save_img(image):
+1 -1
View File
@@ -64,7 +64,7 @@ class ExtraNetworksPageCheckpoints(ui_extra_networks.ExtraNetworksPage):
return record
def list_items(self):
with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor:
with concurrent.futures.ThreadPoolExecutor(max_workers=shared.max_workers) as executor:
future_items = {executor.submit(self.create_item, cp): cp for cp in list(sd_models.checkpoints_list.copy())}
for future in concurrent.futures.as_completed(future_items):
item = future.result()
+1 -1
View File
@@ -95,7 +95,7 @@ class ExtraNetworksPageStyles(ui_extra_networks.ExtraNetworksPage):
return item
def list_items(self):
with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor:
with concurrent.futures.ThreadPoolExecutor(max_workers=shared.max_workers) as executor:
future_items = {executor.submit(self.create_item, style): style for style in list(shared.prompt_styles.styles)}
for future in concurrent.futures.as_completed(future_items):
item = future.result()
@@ -68,7 +68,7 @@ class ExtraNetworksPageTextualInversion(ui_extra_networks.ExtraNetworksPage):
self.embeddings = []
self.embeddings = sorted(self.embeddings, key=lambda emb: emb.filename)
with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor:
with concurrent.futures.ThreadPoolExecutor(max_workers=shared.max_workers) as executor:
future_items = {executor.submit(self.create_item, net): net for net in self.embeddings}
for future in concurrent.futures.as_completed(future_items):
item = future.result()
+3
View File
@@ -311,6 +311,9 @@ def webui(restart=False):
modules.sd_models.write_metadata()
load_model()
shared.opts.save(shared.config_filename)
if cmd_opts.profile:
for k, v in modules.script_callbacks.callback_map.items():
shared.log.debug(f'Registered callbacks: {k}={len(v)} {[c.script for c in v]}')
log.info(f"Startup time: {timer.startup.summary()}")
debug = log.info if os.environ.get('SD_SCRIPT_DEBUG', None) is not None else lambda *args, **kwargs: None
debug('Loaded scripts:')