diff --git a/CHANGELOG.md b/CHANGELOG.md index 22244b029..96cfb75d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -115,12 +115,13 @@ For full details, see [ChangeLog](https://github.com/vladmandic/automatic/blob/m - refactor `hash-cache` management, thanks @awsr - validate all `reference` jsons and backfill all fields - sticter `js` linting, thanks @awsr + - ui: add profiling info - ui: remove non-passive event listeners - ui: add debounce to ui updates - ui: utilize requestanimationframe for paint optimizations - ui: profile callbacks - ui: validate callbacks before use, thanks @awsr - - ui: log formatting + - ui: log formatting - **Fixes** - Prohibit `python==3.14` unless `--experimental` - UI CSS fixes, thanks @awsr @@ -139,6 +140,7 @@ For full details, see [ChangeLog](https://github.com/vladmandic/automatic/blob/m - controlnet processor error handling - error handling for same-device check - error handling for undefined pipeline + - erorr handling for `scripts` loader - patch `z-image` for fp16 compatibility, thanks @resonantsky - patch `unipc` for timesteps device placement, thanks @resonantsky - `civitai` search and base-model discovery improvements diff --git a/eslint.config.mjs b/eslint.config.mjs index 2f247dafa..8efc252d1 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -35,6 +35,7 @@ const jsConfig = defineConfig([ log: 'readonly', debug: 'readonly', error: 'readonly', + timer: 'readonly', xhrGet: 'readonly', xhrPost: 'readonly', gradioApp: 'readonly', @@ -52,6 +53,7 @@ const jsConfig = defineConfig([ getUICurrentTabContent: 'readonly', waitForFlag: 'readonly', logFn: 'readonly', + logTimers: 'readonly', generateForever: 'readonly', showContributors: 'readonly', opts: 'writable', diff --git a/extensions-builtin/sdnext-modernui b/extensions-builtin/sdnext-modernui index 055eb67c2..fe25f9a0b 160000 --- a/extensions-builtin/sdnext-modernui +++ b/extensions-builtin/sdnext-modernui @@ -1 +1 @@ -Subproject commit 055eb67c2b042ddc0dd333c35a7239b755acf32c +Subproject commit fe25f9a0b23f764a6a05022e84a8538c02e6f53f diff --git a/javascript/aspectRatioOverlay.js b/javascript/aspectRatioOverlay.js index 380ebef80..293c41a4d 100644 --- a/javascript/aspectRatioOverlay.js +++ b/javascript/aspectRatioOverlay.js @@ -48,7 +48,7 @@ function dimensionChange(e, is_width, is_height) { } } -onAfterUiUpdate(() => { +function aspectRatioCallback() { const arPreviewRect = gradioApp().querySelector('#imageARPreview'); if (arPreviewRect) arPreviewRect.style.display = 'none'; const tabImg2img = gradioApp().querySelector('#tab_img2img'); @@ -68,4 +68,6 @@ onAfterUiUpdate(() => { }); } } -}); +} + +onAfterUiUpdate(aspectRatioCallback); diff --git a/javascript/autocomplete.js b/javascript/autocomplete.js index 9d4eab9c0..32bc505db 100644 --- a/javascript/autocomplete.js +++ b/javascript/autocomplete.js @@ -148,6 +148,7 @@ const engine = { this.indices.clear(); return; } + const t0 = performance.now(); const toLoad = enabled.filter((n) => !this.indices.has(n)); const toRemove = [...this.indices.keys()].filter((n) => !enabled.includes(n)); toRemove.forEach((n) => this.indices.delete(n)); @@ -164,7 +165,9 @@ const engine = { if (cat.name) this.categoryNames[id] = cat.name; }); } - log('autoComplete', { loaded: name, tags: data.tags?.length || 0 }); + const t1 = performance.now(); + log('autoComplete', { loaded: name, tags: data.tags?.length || 0, time: Math.round(t1 - t0) }); + timer(`autocompleteLoad:${name}`, t1 - t0); } catch (e) { log('autoComplete', { failed: name, error: e }); } @@ -508,6 +511,7 @@ function patchConfigBridge() { // -- Initialization -- async function initAutocomplete() { + const t0 = performance.now(); const enabled = window.opts?.autocomplete_enabled || []; active = window.opts?.autocomplete_active || false; log('autoComplete', { active, enabled }); @@ -543,9 +547,9 @@ async function initAutocomplete() { attached++; } }); - log('autoComplete', { attached, dicts: engine.indices.size }); // Reload when settings change - onOptionsChanged(async () => { + + async function optionsChangedCallback() { const newActive = window.opts?.autocomplete_active || false; const newEnabled = window.opts?.autocomplete_enabled || []; const currentKeys = [...engine.indices.keys()].sort().join(','); @@ -556,9 +560,13 @@ async function initAutocomplete() { active = newActive; patchActiveButton(); } - }); + } + onOptionsChanged(optionsChangedCallback); // Watch for config updates from the script UI bridge patchConfigBridge(); patchActiveButton(); - onAfterUiUpdate(() => patchConfigBridge()); + onAfterUiUpdate(patchConfigBridge); + const t1 = performance.now(); + log('autoComplete', { attached, dicts: engine.indices.size, time: Math.round(t1 - t0) }); + timer('autocompleteInit', t1 - t0); } diff --git a/javascript/control.js b/javascript/control.js index 4d94fc643..06da73910 100644 --- a/javascript/control.js +++ b/javascript/control.js @@ -17,6 +17,7 @@ function controlInputMode(inputMode, ...args) { } async function setupControlUI() { + const t0 = performance.now(); const tabs = ['input', 'output', 'preview']; for (const tab of tabs) { const btn = gradioApp().getElementById(`control-${tab}-button`); @@ -46,5 +47,7 @@ async function setupControlUI() { }); intersectionObserver.observe(el); // monitor visibility of tab - log('initControlUI'); + const t1 = performance.now(); + log('setupControlUI', Math.round(t1 - t0)); + timer('setupControlUI', t1 - t0); } diff --git a/javascript/extraNetworks.js b/javascript/extraNetworks.js index eaf516ff2..d0c438671 100644 --- a/javascript/extraNetworks.js +++ b/javascript/extraNetworks.js @@ -217,6 +217,7 @@ async function filterExtraNetworksForTab(searchTerm) { } const t1 = performance.now(); log(`filterExtraNetworks: text="${searchTerm}" items=${items} match=${found} time=${Math.round(t1 - t0)}`); + timer(`filterExtraNetworks:${searchTerm}`, t1 - t0); } function tryToRemoveExtraNetworkFromPrompt(textarea, text) { @@ -282,6 +283,7 @@ function sortExtraNetworks(fixed = 'no') { const desc = sortDesc[sortVal]; const t1 = performance.now(); log('sortNetworks', { name: pagename, val: sortVal, order: desc, fixed: fixed === 'fixed', items: num, time: Math.round(t1 - t0) }); + timer(`sortExtraNetworks:${desc}`, t1 - t0); return desc; } diff --git a/javascript/gallery.js b/javascript/gallery.js index 297a7ef36..377577892 100644 --- a/javascript/gallery.js +++ b/javascript/gallery.js @@ -855,7 +855,8 @@ async function gallerySearch() { } const t1 = performance.now(); - updateStatusWithSort('Filter', ['Images', `${totalFound.toLocaleString()} / ${allFiles.length.toLocaleString()}`], `${iconStopwatch} ${Math.floor(t1 - t0).toLocaleString()}ms`); + updateStatusWithSort('Filter', ['Images', `${totalFound.toLocaleString()} / ${allFiles.length.toLocaleString()}`], `${iconStopwatch} ${Math.round(t1 - t0).toLocaleString()}ms`); + timer(`galleryFilter:${str}`, t1 - t0); refreshGallerySelection(); }, 250); } @@ -936,7 +937,8 @@ async function gallerySort(key) { const t1 = performance.now(); log(`gallerySort: sort=${sortMode.name} len=${arr.length} time=${Math.floor(t1 - t0)}`); - updateStatusWithSort(['Images', arr.length.toLocaleString()], `${iconStopwatch} ${Math.floor(t1 - t0).toLocaleString()}ms`); + updateStatusWithSort(['Images', arr.length.toLocaleString()], `${iconStopwatch} ${Math.round(t1 - t0).toLocaleString()}ms`); + timer(`gallerySort:${sortMode.name}`, t1 - t0); refreshGallerySelection(); } @@ -1025,7 +1027,8 @@ async function thumbCacheCleanup(folder, imgCount, controller, force = false) { await idbFolderCleanup(keptGalleryHashes, recursiveFolder, controller.signal) .then((delcount) => { const t1 = performance.now(); - log(`Thumbnail DB cleanup: folder=${folder} kept=${keptGalleryHashes.size} deleted=${delcount} time=${Math.floor(t1 - t0)}ms`); + log(`Thumbnail DB cleanup: folder=${folder} kept=${keptGalleryHashes.size} deleted=${delcount} time=${Math.round(t1 - t0)}ms`); + timer(`thumbnailDBCleanup:${folder}`, t1 - t0); currentGalleryFolder = null; el.clearCacheFolder.innerText = '