mirror of
https://github.com/vladmandic/sdnext.git
synced 2026-01-27 15:02:48 +03:00
150 lines
5.1 KiB
Python
Executable File
150 lines
5.1 KiB
Python
Executable File
#!/usr/bin/env python
|
|
"""
|
|
sd api txt2img benchmark
|
|
"""
|
|
import os
|
|
import asyncio
|
|
import base64
|
|
import io
|
|
import json
|
|
import time
|
|
import argparse
|
|
from PIL import Image
|
|
import sdapi
|
|
from util import Map, log
|
|
|
|
|
|
oom = 0
|
|
args = None
|
|
options = None
|
|
|
|
|
|
async def txt2img():
|
|
t0 = time.perf_counter()
|
|
data = {}
|
|
try:
|
|
data = await sdapi.post('/sdapi/v1/txt2img', options)
|
|
except Exception:
|
|
return -1
|
|
if 'error' in data:
|
|
return -1
|
|
if 'info' in data:
|
|
info = Map(json.loads(data['info']))
|
|
else:
|
|
return 0
|
|
log.debug({ 'info': info })
|
|
if options['batch_size'] != len(data['images']):
|
|
log.error({ 'requested': options['batch_size'], 'received': len(data['images']) })
|
|
return 0
|
|
for i in range(len(data['images'])):
|
|
data['images'][i] = Image.open(io.BytesIO(base64.b64decode(data['images'][i].split(',',1)[0])))
|
|
if args.save:
|
|
fn = os.path.join(args.save, f'benchmark-{i}-{len(data["images"])}.png')
|
|
data["images"][i].save(fn)
|
|
log.debug({ 'save': fn })
|
|
log.debug({ "images": data["images"] })
|
|
t1 = time.perf_counter()
|
|
return t1 - t0
|
|
|
|
|
|
def memstats():
|
|
mem = sdapi.getsync('/sdapi/v1/memory')
|
|
cpu = mem.get('ram', 'unavailable')
|
|
gpu = mem.get('cuda', 'unavailable')
|
|
if 'active' in gpu:
|
|
gpu['session'] = gpu.pop('active')
|
|
if 'reserved' in gpu:
|
|
gpu.pop('allocated')
|
|
gpu.pop('reserved')
|
|
gpu.pop('inactive')
|
|
if 'events' in gpu:
|
|
global oom # pylint: disable=global-statement
|
|
oom = gpu['events']['oom']
|
|
gpu.pop('events')
|
|
return cpu, gpu
|
|
|
|
|
|
def gb(val: float):
|
|
return round(val / 1024 / 1024 / 1024, 2)
|
|
|
|
|
|
async def main():
|
|
sdapi.quiet = True
|
|
await sdapi.session()
|
|
await sdapi.interrupt()
|
|
ver = await sdapi.get("/sdapi/v1/version")
|
|
log.info({ 'version': ver})
|
|
platform = await sdapi.get("/sdapi/v1/platform")
|
|
log.info({ 'platform': platform })
|
|
opts = await sdapi.get('/sdapi/v1/options')
|
|
opts = Map(opts)
|
|
log.info({ 'model': opts.sd_model_checkpoint })
|
|
cpu, gpu = memstats()
|
|
log.info({ 'system': { 'cpu': cpu, 'gpu': gpu }})
|
|
batch = [1, 1, 2, 4, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256]
|
|
batch = [b for b in batch if b <= args.maxbatch]
|
|
log.info({"batch-sizes": batch})
|
|
for i in range(len(batch)):
|
|
if oom > 0:
|
|
continue
|
|
options['batch_size'] = batch[i]
|
|
warmup = await txt2img()
|
|
ts = await txt2img()
|
|
if i == 0:
|
|
ts += warmup
|
|
if ts > 0.01: # cannot be faster than 10ms per run
|
|
await asyncio.sleep(0)
|
|
cpu, gpu = memstats()
|
|
if i == 0:
|
|
log.info({ 'warmup': round(ts, 2) })
|
|
else:
|
|
peak = gpu['system']['used'] # gpu['session']['peak'] if 'session' in gpu else 0
|
|
log.info({ 'batch': batch[i], 'its': round(options.steps / (ts / batch[i]), 2), 'img': round(ts / batch[i], 2), 'wall': round(ts, 2), 'peak': gb(peak), 'oom': oom > 0 })
|
|
else:
|
|
await asyncio.sleep(10)
|
|
cpu, gpu = memstats()
|
|
log.info({ 'batch': batch[i], 'result': 'error', 'gpu': gpu, 'oom': oom > 0 })
|
|
break
|
|
if oom > 0:
|
|
log.info({ 'benchmark': 'ended with oom so you should probably restart your automatic server now' })
|
|
await sdapi.close()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
log.info({ 'run-benchmark' })
|
|
parser = argparse.ArgumentParser(description = 'run-benchmark')
|
|
parser.add_argument("--steps", type=int, default=50, required=False, help="steps")
|
|
parser.add_argument("--sampler", type=str, default='Euler a', required=False, help="Use specific sampler")
|
|
parser.add_argument("--prompt", type=str, default='photo of two dice on a table', required=False, help="prompt")
|
|
parser.add_argument("--negative", type=str, default='foggy, blurry', required=False, help="prompt")
|
|
parser.add_argument("--maxbatch", type=int, default=16, required=False, help="max batch size")
|
|
parser.add_argument("--width", type=int, default=512, required=False, help="width")
|
|
parser.add_argument("--height", type=int, default=512, required=False, help="height")
|
|
parser.add_argument('--debug', default = False, action='store_true', help = 'debug logging')
|
|
parser.add_argument('--taesd', default = False, action='store_true', help = 'use taesd as vae')
|
|
parser.add_argument("--save", type=str, default='', required=False, help="save images to folder")
|
|
args = parser.parse_args()
|
|
if args.debug:
|
|
log.setLevel('DEBUG')
|
|
options = Map(
|
|
{
|
|
"prompt": args.prompt,
|
|
"negative_prompt": args.negative,
|
|
"steps": args.steps,
|
|
"sampler_name": args.sampler,
|
|
"width": args.width,
|
|
"height": args.height,
|
|
"vae_type": 'Tiny' if args.taesd else 'Full',
|
|
"cfg_scale": 0,
|
|
"batch_size": 1,
|
|
"n_iter": 1,
|
|
"seed": -1,
|
|
}
|
|
)
|
|
log.info({"options": options})
|
|
try:
|
|
asyncio.run(main())
|
|
except KeyboardInterrupt:
|
|
log.warning({ 'interrupted': 'keyboard request' })
|
|
sdapi.interruptsync()
|