Real workload: lazy TF imports + real-component service driver - #15
Open
andre-merzky wants to merge 25 commits into
Open
andre-merzky wants to merge 25 commits into
andre-merzky wants to merge 25 commits into
Conversation
Lazy imports so the real investigators package/instantiate on the
client and broker without TensorFlow (it loads only in the task bodies,
which run on the endpoint):
- the three surrogate wrappers (fno/pinn/pcr) defer `from .main
import ...` into their task bodies;
- each do_*/__init__.py replaces eager `from .main import *` with a
PEP 562 __getattr__, so importing a submodule no longer drags TF /
scikit-learn in, while `tasks.<pkg>.tk_*` still resolves on access
(wrapper.py's executable path, on the endpoint).
Verified: the three investigators + wind_agent + sink + profiler all
import TF-free (pyspot submodule + dotenv are the only remaining
client/broker deps, both light).
twin_service_real.py mirrors twin.py's graph with the real FNO/PINN/PCR
investigators, real profiler + Pi predictor, real sink, and the
external fake sensor -- experimental, the on-Perlmutter starting point.
setup-hpc-endpoint-real.sh inits the pyspot submodule; README documents
the client deps and the two open items (shared-filesystem topology,
cloudpickle parity).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU
EndpointInvestigator.main_loop runs on the broker, but it appended new rows to data.csv that train_model (an executable task) reads on the endpoint -- different filesystems once broker and endpoint are split. The append moves into a function_task (whose body runs on the endpoint), so data.csv is produced and consumed on the same host. This is the one cross-host file hand-off that is fixable without staging. The rest of the profiler chain uses executable_tasks, whose bodies run on the engine (broker) to build the command while the command runs on the endpoint -- so the .pkl / .json inputs they write are broker-side and the commands read them endpoint-side. Bridging that is the ORBIT staging work (separate), not a filesystem assumption to fix here. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU
andre-merzky
force-pushed
the
feature/dtaas-twin-real
branch
from
September 4, 2026 09:01
f549dc7 to
73eaab5
Compare
…rocess The profiler cloudpickled the inference to a file and ran the standalone profiler.py under a fresh process group. Because an executable task's command-builder runs on the broker while its command runs on the endpoint, that .pkl was written broker-side and read endpoint-side -- a cross-host hand-off needing a shared filesystem. inproc.py runs the call in-process on the endpoint and reads the process's own counters (perf_counter, getrusage, psutil.io_counters), returning the profiler's exact six-key schema so data.csv and endpoint_trainer.py are unchanged. ProfilerInvestigator and EndpointInvestigator now profile via a function-task (endpoint-side, no file, no subprocess). Verified locally: real wall/cpu/mem on a dummy inference; components import clean. Trade-off (no process-group isolation, peak RSS not child PSS) is fine for a comparative fingerprint. PLAN-telemetry-profiling.md captures approach 2 -- read the endpoint's own per-task telemetry instead of re-running -- for later, plus the remaining executable-task input hand-offs in the Pi-predictor (train/eval) that want the same treatment. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU
- EndpointInvestigator.call_inference wrote inf.json in its executable-task command-builder (broker) while endpoint_eval.py reads it on the endpoint. A stage_inf function-task now writes it on the endpoint before the command runs -- the last cross-host file hand-off in the profiler chain. The datastore makedirs in __init__ (broker) is guarded; the endpoint tasks create it. - CUPS_Sink renders the heatmap to bytes and calls record_output so the real driver shows heatmaps in the dashboard Outputs panel (needs digital.twins#38), and imports matplotlib lazily so packaging on the client/broker stays light. Verified locally: all real-driver components import clean, TF-free and matplotlib-free at import. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU
- setup-hpc-endpoint-real.sh checks out feature/dtaas-twin-real for the endpoint tasks tree -- the base branch lacks the in-process profiler, the inf.json staging fix and the output-emitting sink. - PLAYGROUND_DIR -> /pscratch/sd/m/merzky/xgf_playground (a real PM scratch path; the driver reads it from config.sh on the client and ships it to the components, which use it endpoint-side). Demo-specific values; to be generalised later. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU
- setup-hpc-endpoint-real.sh force-reinstalls radical.orbit: a cloned conda env may already carry a stale one that pip treats as satisfied, so the endpoint script (radical-orbit-endpoint.py) never installs. - setup-client.sh installs the light client-side deps the real components import at packaging time (python-dotenv, numpy, pandas) and inits the pyspot submodule; TensorFlow/matplotlib stay lazy. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU
- run-hpc-endpoint.sh points RADICAL_ORBIT_LOG_FILE at scratch and sets the level to WARNING: the default ~/.radical/orbit/logs is on NERSC HOME, whose tiny quota the endpoint log (esp. at debug) blows out -- the registration itself succeeds but every log write then errors. - setup-hpc-endpoint-real.sh backfills orbit's own deps after the --no-deps script reinstall (fastapi/uvicorn/websockets), so a clone missing them still starts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU
…elemetry Two regressions from the conda-clone endpoint: - pip install "$DT_DIR" (digitaltwin) ran after the rhapsody branch pin and pulled a different (main-based) rhapsody over it, reintroducing the Batch(task_logs=...) crash. rhapsody now installs LAST so the dragon-compatible branch wins. - the --no-deps rhapsody install skipped the telemetry extra's opentelemetry. A second, extras install (no --no-deps) backfills opentelemetry + dragonhpc without re-resolving the pinned stack. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU
…pecific) So a plain re-run of setup + run does everything, no one-off commands: - setup-hpc-endpoint-real.sh seeds the Pi dataset at the RUNTIME datastore (PLAYGROUND_DIR/profiler/pi_profiler, where endpoint_trainer reads it), not just the tasks tree; PLAYGROUND_DIR is a script var matching config.sh. - run-hpc-endpoint.sh clears any old HOME orbit log (NERSC quota) on top of redirecting the log to scratch at WARNING. - setup-broker.sh backfills the telemetry extra's deps after the --no-deps rhapsody pin, mirroring the endpoint. Paths are NERSC/demo-specific for now, to be generalised later. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU
Five self-contained scripts, each printing the demo banner and running all-that's-needed for its role (deploy fix + env + data dirs + run): Sep_04_broker.sh radical.3: install stack, pin dragon rhapsody, run broker Sep_04_endpoint_setup.sh PM login node: checkouts, cfdaai clone, runtime, seed data Sep_04_endpoint.sh PM allocation: env + launch endpoint under dragon Sep_04_sensor.sh client: publish davis-wind Sep_04_client.sh client: light deps + drive twin_service_real.py Args are only the broker IP (and 'hpc' endpoint name where relevant); everything else (SCRATCH paths, branch, PLAYGROUND_DIR, conda base env) is baked in for the demo. The endpoint is split because the allocation cannot pip-install; setup runs on a login node first. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU
add_agent failed on the broker with ModuleNotFoundError: no module named 'utils_architecture'. WindFieldAgent references tasks.davis (and tasks.do_simulation, tasks.common.log_formatter), which import the repo-root utils_architecture; the curated register_user_modules list missed them, so they pickled by reference and the broker -- which has no xGFabric checkout -- could not import them. Sweep every already imported tasks.* module plus utils_architecture instead. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU
The DTaaS service builds agents as cls(flow, *args, **engines); the required 'logger' positional made add_agent raise TypeError. Default it to the module logger. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU
script_path was os.path.realpath(__file__) captured at import on the CLIENT; shipped by value, the executable/training commands then pointed at the laptop checkout (/home/merzky/projects/xgfabric/...) while running on Perlmutter. Invoke via 'python3 -m tasks.profiler.endpoint_*' instead -- the endpoint puts XGF_DIR on PYTHONPATH, so the path is resolved on whatever host runs the command. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU
endpoint_trainer.py/endpoint_eval.py import xgboost; the cfdaai clone does not carry it. Install into the endpoint env at setup. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU
The real learners (FNO/PINN/PCR, Pi predictor) run on the default 'inference' engine, so the dashboard showed no learning lane. Add a compact WindTrendLearner that consumes the same sensor stream and routes its training to the 'learning' backend (the @function_task(backend=...) label the service demo's SurrogateInvestigator uses). It publishes to its own WIND_TREND dtype, so it never competes with the WIND_FIELD path feeding the sink. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU
TF fell back to CPU because libcuda.so.1 was not on the task LD_LIBRARY_PATH. module load cudatoolkit + prepend /usr/lib64 (compute node driver) and the env's CUDA libs; log nvidia-smi -L so we can see whether the allocation actually has a GPU. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU
No GPU allocation, so the real TF surrogates (~54s/inference on CPU) are too slow for a live demo. Default the demo client to twin_service.py -- fake SurrogateInvestigators (sleeps + numpy field synthesis, no TF or xgboost) that produce heatmaps in seconds and carry the learning lane (learn_backend='learning'). RUN_REAL=1 still selects twin_service_real.py for a GPU-backed run. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU
main_loop runs on the broker; it built the PNG path from the broker's home (XGF_WORKSPACE unset there -> ~/xgf_twin) and mkdir'd it there, then handed that broker path to render_heatmap, which runs on the endpoint and failed to write it (no such dir on Perlmutter). Resolve XGF_WORKSPACE and mkdir inside the task instead, and wrap the disk copy in try/except so it can never fail the field -- the dashboard copy rides inline regardless. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU
…atch) install.sh installs digitaltwin by exact version string and skips when it is unchanged, so the broker kept pre-record_output code and the sink crashed with AttributeError: RuntimeAPI has no attribute record_output. Force-reinstall the checked-out devel tip after install.sh. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU
Prepending /usr/lib64 to LD_LIBRARY_PATH can shadow the conda env's libs and break the dragon task launch -- the endpoint registers but its engine never comes up, so session init times out. Useless on the CPU/fake path anyway; make it opt-in. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU
Keep the field-probe line as the heartbeat; the state dict is only used for the failed-state check now. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU
Reflects reality after the demo cycle: runs end to end on the DTaaS stack; the shared-FS caveat is resolved (compute + hand-offs are endpoint-side); the TF path is GPU-bound so the demo defaults to the fake driver (RUN_REAL=1 selects this one). Points at the Sep_04 scripts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU
Nothing to enable: the rhapsody plugin on the endpoint already records every task plus a resource poll (the [telemetry] extra) into telemetry-output/session.*.telemetry.jsonl. collect_reports.py points twin.py's existing report generators at those files -- waterfall, dependency wait, stage timers, swimlane, concurrency/resources, and the gantt render unmodified (verified against the service run's 8292 events). Known gap, documented: per-workflow gantt grouping needs asyncflow.workflow_id, which only workflow_scope() stamps -- an engine-side telemetry feature for the DT service, tracked in digital.twins. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The real-workload step for the service twin, stacked on the deploy-kit branch.
Lazy heavy imports so the real investigators package/instantiate on the client and broker without TensorFlow — it loads only in the task bodies, which run on the endpoint:
fno/pinn/pcr) deferfrom .main import …into their task bodies;do_*/__init__.pyswaps eagerfrom .main import *for a PEP 562__getattr__, so importing a submodule no longer drags TF/scikit-learn in, whiletasks.<pkg>.tk_*still resolves on access (thewrapper.pyexecutable path, which runs on the endpoint where TF lives).Verified locally: the three investigators +
wind_agent+sink+profilerall import TF-free; the only remaining client/broker deps are thepyspotsubmodule andpython-dotenv(both light).twin_service_real.pymirrors twin.py's graph with the real FNO/PINN/PCR investigators, real profiler + Pi predictor, real sink, and the external fake sensor. It's marked experimental — the starting point for the on-Perlmutter test cycle, not yet validated end to end.Provisioning:
setup-hpc-endpoint-real.sh(prior branch) clones Ben's cfdaai env and installs our runtime; this commit adds submodule init. Two open items documented inservice/README.md: the shared-filesystem topology (run the broker on Perlmutter too for the real workload) and cloudpickle parity between the conda clone and ve.demo.No behavior change to the faked demo or the standalone
twin.pypath (the__getattr__preserveswrapper.py's contract).🤖 Generated with Claude Code
https://claude.ai/code/session_016Npyz3Hbnwos12ESsdJ2YU