Skip to content

Commit

Permalink
work on startup profile display
Browse files Browse the repository at this point in the history
  • Loading branch information
AUTOMATIC1111 committed May 20, 2023
1 parent 05e6fc9 commit 0cc05fc
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 14 deletions.
2 changes: 2 additions & 0 deletions html/footer.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
 • 
<a href="https://gradio.app">Gradio</a>
 • 
<a href="#" onclick="showProfile('./internal/profile-startup'); return false;">Startup profile</a>
 • 
<a href="/" onclick="javascript:gradioApp().getElementById('settings_restart_gradio').click(); return false">Reload UI</a>
</div>
<br />
Expand Down
91 changes: 91 additions & 0 deletions javascript/profilerVisualization.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@

function createRow(table, cellName, items) {
var tr = document.createElement('tr');
var res = [];

items.forEach(function(x) {
var td = document.createElement(cellName);
td.textContent = x;
tr.appendChild(td);
res.push(td);
});

table.appendChild(tr);

return res;
}

function showProfile(path, cutoff = 0.0005) {
requestGet(path, {}, function(data) {
var table = document.createElement('table');
table.className = 'popup-table';

data.records['total'] = data.total;
var keys = Object.keys(data.records).sort(function(a, b) {
return data.records[b] - data.records[a];
});
var items = keys.map(function(x) {
return {key: x, parts: x.split('/'), time: data.records[x]};
});
var maxLength = items.reduce(function(a, b) {
return Math.max(a, b.parts.length);
}, 0);

var cols = createRow(table, 'th', ['record', 'seconds']);
cols[0].colSpan = maxLength;

function arraysEqual(a, b) {
return !(a < b || b < a);
}

var addLevel = function(level, parent) {
var matching = items.filter(function(x) {
return x.parts[level] && !x.parts[level + 1] && arraysEqual(x.parts.slice(0, level), parent);
});
var sorted = matching.sort(function(a, b) {
return b.time - a.time;
});
var othersTime = 0;
var othersList = [];
sorted.forEach(function(x) {
if (x.time < cutoff) {
othersTime += x.time;
othersList.push(x.parts[level]);
return;
}

var cells = [];
for (var i = 0; i < maxLength; i++) {
cells.push(x.parts[i]);
}
cells.push(x.time.toFixed(3));
var cols = createRow(table, 'td', cells);
for (i = 0; i < level; i++) {
cols[i].className = 'muted';
}

addLevel(level + 1, parent.concat([x.parts[level]]));
});

if (othersTime > 0) {
var cells = [];
for (var i = 0; i < maxLength; i++) {
cells.push(parent[i]);
}
cells.push(othersTime.toFixed(3));
var cols = createRow(table, 'td', cells);
for (i = 0; i < level; i++) {
cols[i].className = 'muted';
}

cols[level].textContent = 'others';
cols[level].title = othersList.join(", ");
}
};

addLevel(0, []);

popup(table);
});
}

2 changes: 1 addition & 1 deletion javascript/ui_settings_hints.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ onOptionsChanged(function() {
function settingsHintsShowQuicksettings() {
requestGet("./internal/quicksettings-hint", {}, function(data) {
var table = document.createElement('table');
table.className = 'settings-value-table';
table.className = 'popup-table';

data.forEach(function(obj) {
var tr = document.createElement('tr');
Expand Down
3 changes: 3 additions & 0 deletions modules/script_callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
from fastapi import FastAPI
from gradio import Blocks

from modules import timer


def report_exception(c, job):
print(f"Error executing callback {job} for {c.script}", file=sys.stderr)
Expand Down Expand Up @@ -123,6 +125,7 @@ def app_started_callback(demo: Optional[Blocks], app: FastAPI):
for c in callback_map['callbacks_app_started']:
try:
c.callback(demo, app)
timer.startup_timer.record(c.script)
except Exception:
report_exception(c, 'app_started_callback')

Expand Down
3 changes: 2 additions & 1 deletion modules/scripts.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import gradio as gr

from modules import shared, paths, script_callbacks, extensions, script_loading, scripts_postprocessing
from modules import shared, paths, script_callbacks, extensions, script_loading, scripts_postprocessing, timer

AlwaysVisible = object()

Expand Down Expand Up @@ -270,6 +270,7 @@ def orderby(basedir):
finally:
sys.path = syspath
current_basedir = paths.script_path
timer.startup_timer.record(scriptfile.filename)

global scripts_txt2img, scripts_img2img, scripts_postproc

Expand Down
46 changes: 42 additions & 4 deletions modules/timer.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,60 @@
import time


class TimerSubcategory:
def __init__(self, timer, category):
self.timer = timer
self.category = category
self.start = None
self.original_base_category = timer.base_category

def __enter__(self):
self.start = time.time()
self.timer.base_category = self.original_base_category + self.category + "/"

def __exit__(self, exc_type, exc_val, exc_tb):
elapsed_for_subcategroy = time.time() - self.start
self.timer.base_category = self.original_base_category
self.timer.add_time_to_record(self.original_base_category + self.category, elapsed_for_subcategroy)
self.timer.record(self.category)


class Timer:
def __init__(self):
self.start = time.time()
self.records = {}
self.total = 0
self.base_category = ''

def elapsed(self):
end = time.time()
res = end - self.start
self.start = end
return res

def record(self, category, extra_time=0):
e = self.elapsed()
def add_time_to_record(self, category, amount):
if category not in self.records:
self.records[category] = 0

self.records[category] += e + extra_time
self.records[category] += amount

def record(self, category, extra_time=0):
e = self.elapsed()

self.add_time_to_record(self.base_category + category, e + extra_time)

self.total += e + extra_time

def subcategory(self, name):
self.elapsed()

subcat = TimerSubcategory(self, name)
return subcat

def summary(self):
res = f"{self.total:.1f}s"

additions = [x for x in self.records.items() if x[1] >= 0.1]
additions = [(category, time_taken) for category, time_taken in self.records.items() if time_taken >= 0.1 and '/' not in category]
if not additions:
return res

Expand All @@ -34,5 +64,13 @@ def summary(self):

return res

def dump(self):
return {'total': self.total, 'records': self.records}

def reset(self):
self.__init__()


startup_timer = Timer()

startup_record = None
4 changes: 3 additions & 1 deletion modules/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from PIL import Image, PngImagePlugin # noqa: F401
from modules.call_queue import wrap_gradio_gpu_call, wrap_queued_call, wrap_gradio_call

from modules import sd_hijack, sd_models, localization, script_callbacks, ui_extensions, deepbooru, sd_vae, extra_networks, ui_common, ui_postprocessing, progress, ui_loadsave
from modules import sd_hijack, sd_models, localization, script_callbacks, ui_extensions, deepbooru, sd_vae, extra_networks, ui_common, ui_postprocessing, progress, ui_loadsave, timer
from modules.ui_components import FormRow, FormGroup, ToolButton, FormHTML
from modules.paths import script_path, data_path

Expand Down Expand Up @@ -1901,3 +1901,5 @@ def quicksettings_hint():
app.add_api_route("/internal/quicksettings-hint", quicksettings_hint, methods=["GET"], response_model=List[QuicksettingsHint])

app.add_api_route("/internal/ping", lambda: {}, methods=["GET"])

app.add_api_route("/internal/profile-startup", lambda: timer.startup_record, methods=["GET"])
8 changes: 6 additions & 2 deletions style.css
Original file line number Diff line number Diff line change
Expand Up @@ -403,19 +403,23 @@ div#extras_scale_to_tab div.form{
margin: 0 1.2em;
}

table.settings-value-table{
table.popup-table{
background: white;
border-collapse: collapse;
margin: 1em;
border: 4px solid white;
}

table.settings-value-table td{
table.popup-table td{
padding: 0.4em;
border: 1px solid #ccc;
max-width: 36em;
}

table.popup-table .muted{
color: #aaa;
}

.ui-defaults-none{
color: #aaa !important;
}
Expand Down
14 changes: 9 additions & 5 deletions webui.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

from modules import paths, timer, import_hook, errors # noqa: F401

startup_timer = timer.Timer()
startup_timer = timer.startup_timer

import torch
import pytorch_lightning # noqa: F401 # pytorch_lightning should be imported after torch, but it re-enables warnings on import so import once to disable them
Expand Down Expand Up @@ -269,8 +269,8 @@ def initialize_rest(*, reload_script_modules=False):

localization.list_localizations(cmd_opts.localizations_dir)

modules.scripts.load_scripts()
startup_timer.record("load scripts")
with startup_timer.subcategory("load scripts"):
modules.scripts.load_scripts()

if reload_script_modules:
for module in [module for name, module in sys.modules.items() if name.startswith("modules.ui")]:
Expand Down Expand Up @@ -416,9 +416,12 @@ def fastapi_setup(self):

ui_extra_networks.add_pages_to_demo(app)

modules.script_callbacks.app_started_callback(shared.demo, app)
startup_timer.record("scripts app_started_callback")
startup_timer.record("add APIs")

with startup_timer.subcategory("app_started_callback"):
modules.script_callbacks.app_started_callback(shared.demo, app)

timer.startup_record = startup_timer.dump()
print(f"Startup time: {startup_timer.summary()}.")

if cmd_opts.subpath:
Expand All @@ -443,6 +446,7 @@ def fastapi_setup(self):
# If we catch a keyboard interrupt, we want to stop the server and exit.
shared.demo.close()
break

print('Restarting UI...')
shared.demo.close()
time.sleep(0.5)
Expand Down

0 comments on commit 0cc05fc

Please sign in to comment.