File size: 4,236 Bytes
6bc44d6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
"""The live Space through its Gradio API: the configuration's first preset at SNR 30 with the tissue panel's defaults,
then a custom two-shell protocol on the configuration's first timing class; prints the headline, the timings and the
seconds the worker spent on the packs' responses the page had not cached and, with ``--stream``, every stage update as it
arrives; downloads the figures and files to ``$LIVE_OUT``. ``--config`` is the configuration the Space serves
(``DISCO_CONFIG``: ``config.toml`` for the DiSCo Spaces, ``brain.toml`` for ``rfick/brain-zero``): the inputs are
built from its source's panel, presets and knobs, not spelled here.

    python tools/live.py [space] [--config brain.toml] [--stream] [--preset NAME] [--no-ladder] [--knob CHOICE]
"""
import argparse
import os
import sys
import time


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("space", nargs="?", default="rfick/disco")
    ap.add_argument("--config", default=os.environ.get("DISCO_CONFIG", "config.toml"), help="the configuration in space/ the Space serves")
    ap.add_argument("--stream", action="store_true", help="print every stage update as it arrives")
    ap.add_argument("--preset", action="append", help="an acquisition to run (default: the first preset, then custom shells)")
    ap.add_argument("--no-ladder", action="store_true", help="skip the explorer's tier ladder (the shortest GPU reservation)")
    ap.add_argument("--knob", default=None, help="B: the same run with this knob changed (a choice of the page's dropdown)")
    a = ap.parse_args()
    os.environ["DISCO_CONFIG"] = a.config                     # before the page module reads its configuration
    sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
    from gradio_client import Client
    from huggingface_hub import get_token
    from space import app as A, pipeline as P, sources

    cfg = P.config()
    S = sources.source_class(cfg)
    panel = S.panel(cfg)
    defaults = {c.name: c.value for row in panel.rows for c in row}
    tc = S.tracking_controls(cfg)
    shapes = list(S.shapes_of(cfg))
    physics = [defaults[name] for name in panel.fields]

    def inputs(preset, *, knob, n_keys=1, ladder=True):
        shells = [True, shapes[0], 1000, 30, 12.0, 24.0, 53.5, True, shapes[0], 3000, 45, 8.0, 20.0, 53.5,
                  False, shapes[0], 3000, 90, 17.0, 30.0, 53.5, False, shapes[0], 6000, 60, 17.0, 30.0, 53.5]
        return [preset, 2, True, 30, tc["density"][2], tc["max_angle"][2], tc["step"][2], 0, None, knob, A.IDEAL, n_keys, ladder, *physics, *shells]

    c = Client(a.space, token=get_token(), verbose=False, download_files=os.environ.get("LIVE_OUT", "/tmp/disco-live"), httpx_kwargs={"timeout": 900})
    for preset in a.preset or (S.presets(cfg)[0], A.CUSTOM):
        t0 = time.perf_counter()
        args = inputs(preset, knob=a.knob or A.NO_KNOB, ladder=not a.no_ladder)
        print(f"{preset}: the client's own estimate {A.estimated_seconds(*args)} s (the page's cache is not known here; the Space prices "
              f"the responses it has not cached on top)", flush=True)
        job = c.submit(*args, api_name="/run_pipeline")
        seen = 0
        while a.stream and not job.done():
            outs = job.outputs()
            for o in outs[seen:]:
                print(f"  +{time.perf_counter() - t0:5.1f} s: {str(o[1])[:100]}", flush=True)
            seen = len(outs)
            time.sleep(1)
        out = job.result()
        print(f"{preset}: {time.perf_counter() - t0:.1f} s wall; result received at unix {time.time():.1f}", flush=True)
        named = dict(zip([n for n in A.OUTPUTS if n not in ("result", "b_row")], out))   # the API returns neither the gr.State nor the gr.Row
        print(named["headline"]); print(named["timings"])
        rows = named["timings"]["data"] if isinstance(named["timings"], dict) else named["timings"]
        responses = [r[1] for r in rows if r[0] == A.RESPONSES_ROW]
        print(f"the packs' responses on the worker: {responses[0] if responses else 'none (the source prepares nothing)'} s", flush=True)
        print("tck", named["tck"], "volumes", named["volumes"], flush=True)


if __name__ == "__main__":
    main()