chialoops 1.0.0__tar.gz → 2.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {chialoops-1.0.0 → chialoops-2.0.0}/PKG-INFO +31 -22
- {chialoops-1.0.0 → chialoops-2.0.0}/README.md +30 -21
- chialoops-2.0.0/chia/aws/__init__.py +3 -0
- chialoops-2.0.0/chia/aws/manager.py +180 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/aws/s3.py +8 -1
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/ChiaFunction.py +14 -0
- chialoops-2.0.0/chia/base/chia_log.py +34 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/chisel_build_node.py +32 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/firemarshal_node.py +21 -7
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/riscv_build_node.py +11 -6
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/state_def.py +87 -19
- chialoops-2.0.0/chia/chipyard/test/test_firemarshal_artifact.py +41 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/verilator_run_node.py +30 -1
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cli/down.py +17 -3
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cli/up.py +58 -18
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cluster/aws_nodes.py +109 -119
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cluster/config.py +48 -12
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cluster/docker.py +4 -1
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cluster/gcp_nodes.py +288 -162
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cluster/node_setup.py +204 -21
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cluster/ssh.py +1 -1
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cluster/tailnet.py +407 -72
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cluster/test/tailnet/test_tailnet.py +3 -3
- chialoops-2.0.0/chia/cluster/test/tailnet/test_tailnet_add.py +698 -0
- chialoops-2.0.0/chia/cluster/test/tailnet/test_tailnet_add_live.py +291 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cluster/test/tunnel/test_gcp_nodes.py +25 -36
- chialoops-2.0.0/chia/cluster/test/vpc/test_vpc_cluster.py +142 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cluster/tunnel.py +10 -16
- chialoops-2.0.0/chia/firesim/bitstream_build_node.py +184 -0
- chialoops-2.0.0/chia/firesim/fs_bitstream.py +114 -0
- chialoops-2.0.0/chia/firesim/manager_node.py +224 -0
- chialoops-2.0.0/chia/firesim/render.py +86 -0
- chialoops-2.0.0/chia/firesim/specs.py +81 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/firesim/state_def.py +84 -0
- chialoops-2.0.0/chia/firesim/test/test_render.py +68 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/antigravity.py +10 -2
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/bedrock.py +4 -3
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/claude.py +19 -24
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/codex.py +6 -2
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/copilot.py +6 -2
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/openai_compat.py +4 -3
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/opencode.py +8 -7
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/tests/test_vertex.py +34 -3
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/vertex.py +19 -7
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/simulators/champsim.py +13 -5
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/simulators/tests/test_champsim_live.py +20 -0
- chialoops-2.0.0/chia/simulators/tests/test_champsim_trace_cache.py +108 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/trace/profiler.py +11 -1
- chialoops-2.0.0/chia/trace/status.py +113 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/trace/test/test_profiler.py +39 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chialoops.egg-info/PKG-INFO +31 -22
- {chialoops-1.0.0 → chialoops-2.0.0}/chialoops.egg-info/SOURCES.txt +14 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/pyproject.toml +1 -1
- chialoops-1.0.0/chia/vlsi/tests/__init__.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/LICENSE +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/analysis/__init__.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/analysis/sustainability/__init__.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/analysis/sustainability/focal.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/analysis/sustainability/pfas.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/aws/config.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/aws/ec2.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/aws/host.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/aws/test/test_s3.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/aws/test/test_s3_e2e.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/bypass.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/cache.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/chia_kv_store.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/chia_wait.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/colocated.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/dispatch_proxy.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/llm_call.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/pid_registry.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/test/ChiaFunction_tb.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/test/chia_wait_tb.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/test/pid_registry_tb.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/test/ray_job_stop_helper.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/test/sigterm_cleanup_helper.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/test/test_bypass_tags.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/test/test_cache_tags.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/test/test_chia_remote_blocking.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/test/test_colocated_live.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/test/test_dispatch_proxy_live.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/tools/AsyncBashTool.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/tools/AsyncJobTool.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/tools/BashTool.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/tools/ChiaTool.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/tools/ChiaToolTemplate.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/tools/test/test_tool.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/base/tools/util.py +0 -0
- {chialoops-1.0.0/chia/aws → chialoops-2.0.0/chia/chipyard}/__init__.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/chipyard_hammer.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/circt.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/cosim_node.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/macrocompiler.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/numa_prefix.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/riscv_dv_gen_node.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/riscv_objdump_node.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/spike_build_node.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/test/cluster/macrocompiler_e2e_test.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/test/riscv_dv_gen_e2e_driver.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/test/spike_cosim_e2e_driver.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/test/test_build_program.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/test/test_chipyard_hammer_live.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/test/test_chisel_riscv_verilator_e2e.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/test/test_firemarshal_node.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/test/test_firesim_metasim_run.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/test/test_riscv_build_failure.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/test/test_riscv_timeout_output_decode.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/test/test_spike_build_node.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/test/test_spike_golden_model.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/test/torture_e2e_driver.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/test/torture_run_node_tb.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/chipyard/torture_run_node.py +0 -0
- {chialoops-1.0.0/chia/chipyard → chialoops-2.0.0/chia/cli}/__init__.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cli/firesim_cmds.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cli/job.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cli/main.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cli/ray_passthrough.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cli/viz_cmd.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cli/viz_profile_cmd.py +0 -0
- {chialoops-1.0.0/chia/cli → chialoops-2.0.0/chia/cluster}/__init__.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cluster/log.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cluster/ray_stop.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cluster/test/down/test_scoped_down_live.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cluster/test/multi_cluster/test_multi_cluster_add.py +0 -0
- {chialoops-1.0.0/chia/cluster → chialoops-2.0.0/chia/cluster/test/tailnet}/__init__.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cluster/test/tunnel/test_aws_nodes.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cluster/test/tunnel/test_cross_machine.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cluster/test/tunnel/test_dispatch_proxy.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cluster/test/tunnel/test_ec2_cluster.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cluster/test/tunnel/test_ec2_concurrency.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cluster/test/tunnel/test_ec2_tool.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cluster/test/tunnel/test_gcp_cluster.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/cluster/worker_provisioner.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/database/__init__.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/database/base.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/database/postgres_node.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/database/sqlite_node.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/database/test/test_postgres_node_live.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/database/test/test_sqlite_node_live.py +0 -0
- {chialoops-1.0.0/chia/cluster/test/tailnet → chialoops-2.0.0/chia/esp}/__init__.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/esp/esp_workspace.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/esp/state_def.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/esp/test/cluster/accel_e2e_test.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/esp/test/cluster/accel_loop_e2e_test.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/esp/test/cluster/fpga_e2e_test.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/esp/test/cluster/hls_loop_e2e_test.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/esp/test/cluster/soft_build_e2e_test.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/esp/test/cluster/xmsim_e2e_test.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/esp/test/test_esp_local.py +0 -0
- {chialoops-1.0.0/chia/esp → chialoops-2.0.0/chia/firesim}/__init__.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/firesim/build_node.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/firesim/chia_functions.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/firesim/config.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/firesim/run_node.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/firesim/spec_parser.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/firesim/suite_runner.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/firesim/test/test_firesim_build_e2e.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/firesim/test/test_firesim_build_megaboom_all.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/firesim/test/test_firesim_build_ray.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/firesim/test/test_firesim_metasim_build.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/firesim/test/test_firesim_run_e2e.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/firesim/test/test_firesim_suite_e2e.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/firesim/workloads.py +0 -0
- {chialoops-1.0.0/chia/firesim → chialoops-2.0.0/chia/github}/__init__.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/github/github_client.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/github/github_issues_node.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/github/github_pulls_node.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/github/state_def.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/github/test/test_github_issues_e2e.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/ollama.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/openai_providers.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/tests/cluster/ollama_e2e_test.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/tests/cluster/ollama_tool_hammer.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/tests/cluster/vllm_e2e_test.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/tests/conftest.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/tests/fixtures/bedrock/capture_real_fixtures.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/tests/fixtures/make_synthetic_fixtures.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/tests/fixtures/vertex/capture_real_fixtures.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/tests/test_antigravity.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/tests/test_bedrock.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/tests/test_claude_api.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/tests/test_codex.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/tests/test_copilot.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/tests/test_ollama.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/tests/test_openai_compat.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/tests/test_openai_providers.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/tests/test_opencode.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/tests/test_vllm.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/models/vllm.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/simulators/__init__.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/simulators/gem5.py +0 -0
- {chialoops-1.0.0/chia/github → chialoops-2.0.0/chia/simulators/tests}/__init__.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/simulators/tests/test_champsim_smoke_trace.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/simulators/tests/test_gem5_live.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/simulators/tests/traces/generate_smoke_trace.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/trace/__init__.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/trace/metrics.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/trace/profile_table.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/trace/profile_template.html +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/trace/profile_viz.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/trace/profile_viz_html.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/trace/test/test_metrics_logger.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/trace/viz.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/vlsi/__init__.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/vlsi/hammer.py +0 -0
- {chialoops-1.0.0/chia/simulators/tests → chialoops-2.0.0/chia/vlsi/sram_cacti}/__init__.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/vlsi/sram_cacti/cacti_macrocompiler.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/vlsi/sram_cacti/cacti_runner.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/vlsi/sram_cacti/cluster/cacti_smoke_test.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/vlsi/sram_cacti/lef_gen.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/vlsi/sram_cacti/liberty_gen.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/vlsi/sram_cacti/sram_characterize.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/vlsi/sram_cacti/test/conftest.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/vlsi/sram_cacti/test/test_cacti_macrocompiler.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/vlsi/sram_cacti/test/test_cacti_runner.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/vlsi/sram_cacti/test/test_file_validation.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/vlsi/sram_cacti/test/test_integration.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/vlsi/sram_cacti/test/test_lef_gen.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/vlsi/sram_cacti/test/test_liberty_gen.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/vlsi/sram_cacti/test/test_sram_characterize.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/vlsi/sram_cacti/test_nport.py +0 -0
- {chialoops-1.0.0/chia/vlsi/sram_cacti → chialoops-2.0.0/chia/vlsi/tests}/__init__.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chia/vlsi/tests/test_hammer_live.py +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chialoops.egg-info/dependency_links.txt +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chialoops.egg-info/entry_points.txt +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chialoops.egg-info/requires.txt +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/chialoops.egg-info/top_level.txt +0 -0
- {chialoops-1.0.0 → chialoops-2.0.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: chialoops
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0
|
|
4
4
|
Summary: The Chia agentic AI flow for hardware
|
|
5
5
|
Author: UC Berkeley Architecture Research
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -50,7 +50,7 @@ Dynamic: license-file
|
|
|
50
50
|
<p align="center">
|
|
51
51
|
<picture>
|
|
52
52
|
<source media="(prefers-color-scheme: dark)" srcset="docs/_static/chia-logo-inv.png">
|
|
53
|
-
<img alt="CHIA" src="docs/_static/chia-logo.png" width="420"/>
|
|
53
|
+
<img alt="CHIA" src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/chia-logo.png" width="420"/>
|
|
54
54
|
</picture>
|
|
55
55
|
</p>
|
|
56
56
|
|
|
@@ -77,9 +77,18 @@ CHIA requires **Python 3.10.19** (matching the Python in the Docker images). Wit
|
|
|
77
77
|
```bash
|
|
78
78
|
conda create -n chia_env python=3.10.19
|
|
79
79
|
conda activate chia_env
|
|
80
|
-
pip install
|
|
80
|
+
pip install chialoops
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
+
If you are actively developing CHIA, install from a clone in editable mode instead:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
git clone https://github.com/ucb-bar/chia.git
|
|
87
|
+
pip install -e ./chia
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
See the [installation guide](https://docs.chialoops.ai/en/latest/getting-started/installation.html) for optional extras.
|
|
91
|
+
|
|
83
92
|
## Learn more about CHIA
|
|
84
93
|
|
|
85
94
|
- **[CHIA Basics](https://docs.chialoops.ai/en/latest/getting-started/chia-basics.html)** — the core ideas, start here.
|
|
@@ -97,7 +106,7 @@ User guides:
|
|
|
97
106
|
## Overview of CHIA and Early Case Studies
|
|
98
107
|
|
|
99
108
|
<p align="center">
|
|
100
|
-
<img src="docs/_static/overviewfig.png" alt="CHIA overview" width="820"/>
|
|
109
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/overviewfig.png" alt="CHIA overview" width="820"/>
|
|
101
110
|
</p>
|
|
102
111
|
|
|
103
112
|
## Integrations & Ecosystem
|
|
@@ -105,23 +114,23 @@ User guides:
|
|
|
105
114
|
CHIA workflows compose the tools you already use across the hardware/software co-design stack:
|
|
106
115
|
|
|
107
116
|
<p align="center">
|
|
108
|
-
<img src="docs/_static/project-logos/claude-code.svg" alt="Claude Code" height="40"/>
|
|
109
|
-
<img src="docs/_static/project-logos/openai-codex.svg" alt="OpenAI Codex" height="40"/>
|
|
110
|
-
<img src="docs/_static/project-logos/github-copilot.svg" alt="GitHub Copilot" height="40"/>
|
|
111
|
-
<img src="docs/_static/project-logos/google-antigravity.svg" alt="Google Antigravity" height="40"/>
|
|
112
|
-
<img src="docs/_static/project-logos/alphaevolve.svg" alt="AlphaEvolve" height="40"/>
|
|
113
|
-
<img src="docs/_static/project-logos/openevolve.png" alt="OpenEvolve" height="40"/>
|
|
114
|
-
<img src="docs/_static/project-logos/adaevolve.svg" alt="AdaEvolve" height="40"/>
|
|
115
|
-
<img src="docs/_static/project-logos/skydiscover.png" alt="SkyDiscover" height="40"/>
|
|
116
|
-
<img src="docs/_static/project-logos/chisel.svg" alt="Chisel" height="40"/>
|
|
117
|
-
<img src="docs/_static/project-logos/chipyard.svg" alt="Chipyard" height="40"/>
|
|
118
|
-
<img src="docs/_static/project-logos/circt.svg" alt="CIRCT" height="40"/>
|
|
119
|
-
<img src="docs/_static/project-logos/hammer.png" alt="Hammer" height="40"/>
|
|
120
|
-
<img src="docs/_static/project-logos/gem5.png" alt="gem5" height="40"/>
|
|
121
|
-
<img src="docs/_static/project-logos/firesim.png" alt="FireSim" height="40"/>
|
|
122
|
-
<img src="docs/_static/project-logos/verilator.png" alt="Verilator" height="40"/>
|
|
123
|
-
<img src="docs/_static/project-logos/spike.svg" alt="Spike" height="40"/>
|
|
124
|
-
<img src="docs/_static/project-logos/champsim.svg" alt="ChampSim" height="40"/>
|
|
117
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/claude-code.svg" alt="Claude Code" height="40"/>
|
|
118
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/openai-codex.svg" alt="OpenAI Codex" height="40"/>
|
|
119
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/github-copilot.svg" alt="GitHub Copilot" height="40"/>
|
|
120
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/google-antigravity.svg" alt="Google Antigravity" height="40"/>
|
|
121
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/alphaevolve.svg" alt="AlphaEvolve" height="40"/>
|
|
122
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/openevolve.png" alt="OpenEvolve" height="40"/>
|
|
123
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/adaevolve.svg" alt="AdaEvolve" height="40"/>
|
|
124
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/skydiscover.png" alt="SkyDiscover" height="40"/>
|
|
125
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/chisel.svg" alt="Chisel" height="40"/>
|
|
126
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/chipyard.svg" alt="Chipyard" height="40"/>
|
|
127
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/circt.svg" alt="CIRCT" height="40"/>
|
|
128
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/hammer.png" alt="Hammer" height="40"/>
|
|
129
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/gem5.png" alt="gem5" height="40"/>
|
|
130
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/firesim.png" alt="FireSim" height="40"/>
|
|
131
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/verilator.png" alt="Verilator" height="40"/>
|
|
132
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/spike.svg" alt="Spike" height="40"/>
|
|
133
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/champsim.svg" alt="ChampSim" height="40"/>
|
|
125
134
|
</p>
|
|
126
135
|
|
|
127
136
|
<p align="center">
|
|
@@ -129,7 +138,7 @@ CHIA workflows compose the tools you already use across the hardware/software co
|
|
|
129
138
|
</p>
|
|
130
139
|
|
|
131
140
|
<p align="center">
|
|
132
|
-
<img src="docs/_static/project-logos/ray.png" alt="Ray" height="40"/>
|
|
141
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/ray.png" alt="Ray" height="40"/>
|
|
133
142
|
</p>
|
|
134
143
|
|
|
135
144
|
## Attribution
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<p align="center">
|
|
2
2
|
<picture>
|
|
3
3
|
<source media="(prefers-color-scheme: dark)" srcset="docs/_static/chia-logo-inv.png">
|
|
4
|
-
<img alt="CHIA" src="docs/_static/chia-logo.png" width="420"/>
|
|
4
|
+
<img alt="CHIA" src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/chia-logo.png" width="420"/>
|
|
5
5
|
</picture>
|
|
6
6
|
</p>
|
|
7
7
|
|
|
@@ -28,9 +28,18 @@ CHIA requires **Python 3.10.19** (matching the Python in the Docker images). Wit
|
|
|
28
28
|
```bash
|
|
29
29
|
conda create -n chia_env python=3.10.19
|
|
30
30
|
conda activate chia_env
|
|
31
|
-
pip install
|
|
31
|
+
pip install chialoops
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
+
If you are actively developing CHIA, install from a clone in editable mode instead:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
git clone https://github.com/ucb-bar/chia.git
|
|
38
|
+
pip install -e ./chia
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
See the [installation guide](https://docs.chialoops.ai/en/latest/getting-started/installation.html) for optional extras.
|
|
42
|
+
|
|
34
43
|
## Learn more about CHIA
|
|
35
44
|
|
|
36
45
|
- **[CHIA Basics](https://docs.chialoops.ai/en/latest/getting-started/chia-basics.html)** — the core ideas, start here.
|
|
@@ -48,7 +57,7 @@ User guides:
|
|
|
48
57
|
## Overview of CHIA and Early Case Studies
|
|
49
58
|
|
|
50
59
|
<p align="center">
|
|
51
|
-
<img src="docs/_static/overviewfig.png" alt="CHIA overview" width="820"/>
|
|
60
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/overviewfig.png" alt="CHIA overview" width="820"/>
|
|
52
61
|
</p>
|
|
53
62
|
|
|
54
63
|
## Integrations & Ecosystem
|
|
@@ -56,23 +65,23 @@ User guides:
|
|
|
56
65
|
CHIA workflows compose the tools you already use across the hardware/software co-design stack:
|
|
57
66
|
|
|
58
67
|
<p align="center">
|
|
59
|
-
<img src="docs/_static/project-logos/claude-code.svg" alt="Claude Code" height="40"/>
|
|
60
|
-
<img src="docs/_static/project-logos/openai-codex.svg" alt="OpenAI Codex" height="40"/>
|
|
61
|
-
<img src="docs/_static/project-logos/github-copilot.svg" alt="GitHub Copilot" height="40"/>
|
|
62
|
-
<img src="docs/_static/project-logos/google-antigravity.svg" alt="Google Antigravity" height="40"/>
|
|
63
|
-
<img src="docs/_static/project-logos/alphaevolve.svg" alt="AlphaEvolve" height="40"/>
|
|
64
|
-
<img src="docs/_static/project-logos/openevolve.png" alt="OpenEvolve" height="40"/>
|
|
65
|
-
<img src="docs/_static/project-logos/adaevolve.svg" alt="AdaEvolve" height="40"/>
|
|
66
|
-
<img src="docs/_static/project-logos/skydiscover.png" alt="SkyDiscover" height="40"/>
|
|
67
|
-
<img src="docs/_static/project-logos/chisel.svg" alt="Chisel" height="40"/>
|
|
68
|
-
<img src="docs/_static/project-logos/chipyard.svg" alt="Chipyard" height="40"/>
|
|
69
|
-
<img src="docs/_static/project-logos/circt.svg" alt="CIRCT" height="40"/>
|
|
70
|
-
<img src="docs/_static/project-logos/hammer.png" alt="Hammer" height="40"/>
|
|
71
|
-
<img src="docs/_static/project-logos/gem5.png" alt="gem5" height="40"/>
|
|
72
|
-
<img src="docs/_static/project-logos/firesim.png" alt="FireSim" height="40"/>
|
|
73
|
-
<img src="docs/_static/project-logos/verilator.png" alt="Verilator" height="40"/>
|
|
74
|
-
<img src="docs/_static/project-logos/spike.svg" alt="Spike" height="40"/>
|
|
75
|
-
<img src="docs/_static/project-logos/champsim.svg" alt="ChampSim" height="40"/>
|
|
68
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/claude-code.svg" alt="Claude Code" height="40"/>
|
|
69
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/openai-codex.svg" alt="OpenAI Codex" height="40"/>
|
|
70
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/github-copilot.svg" alt="GitHub Copilot" height="40"/>
|
|
71
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/google-antigravity.svg" alt="Google Antigravity" height="40"/>
|
|
72
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/alphaevolve.svg" alt="AlphaEvolve" height="40"/>
|
|
73
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/openevolve.png" alt="OpenEvolve" height="40"/>
|
|
74
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/adaevolve.svg" alt="AdaEvolve" height="40"/>
|
|
75
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/skydiscover.png" alt="SkyDiscover" height="40"/>
|
|
76
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/chisel.svg" alt="Chisel" height="40"/>
|
|
77
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/chipyard.svg" alt="Chipyard" height="40"/>
|
|
78
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/circt.svg" alt="CIRCT" height="40"/>
|
|
79
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/hammer.png" alt="Hammer" height="40"/>
|
|
80
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/gem5.png" alt="gem5" height="40"/>
|
|
81
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/firesim.png" alt="FireSim" height="40"/>
|
|
82
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/verilator.png" alt="Verilator" height="40"/>
|
|
83
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/spike.svg" alt="Spike" height="40"/>
|
|
84
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/champsim.svg" alt="ChampSim" height="40"/>
|
|
76
85
|
</p>
|
|
77
86
|
|
|
78
87
|
<p align="center">
|
|
@@ -80,7 +89,7 @@ CHIA workflows compose the tools you already use across the hardware/software co
|
|
|
80
89
|
</p>
|
|
81
90
|
|
|
82
91
|
<p align="center">
|
|
83
|
-
<img src="docs/_static/project-logos/ray.png" alt="Ray" height="40"/>
|
|
92
|
+
<img src="https://raw.githubusercontent.com/ucb-bar/chia/main/docs/_static/project-logos/ray.png" alt="Ray" height="40"/>
|
|
84
93
|
</p>
|
|
85
94
|
|
|
86
95
|
## Attribution
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"""Bring a given EC2 node up as a Chia worker at runtime, and take it down.
|
|
2
|
+
|
|
3
|
+
The node is given, not discovered: a ``(NodeTypeConfig, AWSNodeConfig)`` pair,
|
|
4
|
+
the same classes a cluster file's node type and ``aws_nodes:`` entry parse
|
|
5
|
+
into. Each step is the code ``chia up`` runs for AWS nodes:
|
|
6
|
+
|
|
7
|
+
provision_aws_nodes launch the instances
|
|
8
|
+
run_aws_setup install docker (and chia's other defaults), synchronously
|
|
9
|
+
add_nodes_to_cluster ssh tunnel, container, ray start
|
|
10
|
+
|
|
11
|
+
With ``connection: tunnel``, the tunnel carries every Ray connection between the
|
|
12
|
+
worker and the head, so the head needs no inbound ports and may sit anywhere. Its
|
|
13
|
+
ports are read from the running cluster rather than from the cluster file. With
|
|
14
|
+
``connection: vpc``, the default, they use private IPs in the head's VPC instead.
|
|
15
|
+
|
|
16
|
+
AWSManager runs as a Ray actor on the head (:func:`start_aws_manager`): the
|
|
17
|
+
tunnels are processes on the head, and the head raylet's ports are read from
|
|
18
|
+
its ``/proc``.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
import copy
|
|
24
|
+
import os
|
|
25
|
+
from dataclasses import dataclass, replace
|
|
26
|
+
|
|
27
|
+
import ray
|
|
28
|
+
|
|
29
|
+
from chia.aws.config import AWSConfig
|
|
30
|
+
from chia.aws.ec2 import get_default_ami, terminate_ec2_instances
|
|
31
|
+
from chia.base.ChiaFunction import chia_actor
|
|
32
|
+
from chia.cluster.aws_nodes import AWSNodeConfig, provision_aws_nodes, run_aws_setup
|
|
33
|
+
from chia.cluster.config import (ClusterConfig, NodeTypeConfig, SSHAuthConfig,
|
|
34
|
+
TunnelConfig, assign_nodes)
|
|
35
|
+
from chia.cluster.log import get_logger, setup_logging
|
|
36
|
+
from chia.cluster.node_setup import add_nodes_to_cluster
|
|
37
|
+
|
|
38
|
+
logger = get_logger("aws.manager")
|
|
39
|
+
|
|
40
|
+
AWSWorker = tuple[NodeTypeConfig, AWSNodeConfig]
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def worker_resources(worker: AWSWorker) -> dict[str, float]:
|
|
44
|
+
# The resources that a machine of this definition advertises when it joins the cluster.
|
|
45
|
+
return dict(worker[0].resources)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dataclass
|
|
49
|
+
class Farm:
|
|
50
|
+
"""The instances one :meth:`AWSManager.launch` brought up, and that manager."""
|
|
51
|
+
name: str
|
|
52
|
+
region: str
|
|
53
|
+
ips: list[str]
|
|
54
|
+
manager: "ray.actor.ActorHandle | None" = None
|
|
55
|
+
|
|
56
|
+
def teardown(self) -> None:
|
|
57
|
+
"""Close the farm's tunnels and terminate its instances, through its manager."""
|
|
58
|
+
ray.get(self.manager.teardown.remote(self))
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class AWSManager:
|
|
62
|
+
"""Adds a given EC2 node to a running cluster, and removes it."""
|
|
63
|
+
|
|
64
|
+
def __init__(self, cluster_config: ClusterConfig, aws_config: AWSConfig):
|
|
65
|
+
"""
|
|
66
|
+
Args:
|
|
67
|
+
cluster_config: The running cluster the node joins.
|
|
68
|
+
aws_config: Account values the node definition leaves out: region,
|
|
69
|
+
EC2 key pair, and the ssh user and key for it.
|
|
70
|
+
"""
|
|
71
|
+
setup_logging() # an actor process has no log handler; chia's CLIs set one up
|
|
72
|
+
self.cluster_config = cluster_config
|
|
73
|
+
self.aws_config = aws_config
|
|
74
|
+
self._tunnels = {} # farm ips -> the TunnelManager carrying their Ray traffic
|
|
75
|
+
if cluster_config.connection not in ("tunnel", "vpc"):
|
|
76
|
+
raise ValueError(f"AWSManager supports connection tunnel or vpc, not {cluster_config.connection}")
|
|
77
|
+
self._vpc_id = cluster_config.aws_config.vpc_id if cluster_config.aws_config else None
|
|
78
|
+
# The head's private IP with connection "vpc"; None means SSH tunnels.
|
|
79
|
+
self._vpc_head_ip = cluster_config.head_ip if cluster_config.connection == "vpc" else None
|
|
80
|
+
|
|
81
|
+
def launch(self, worker: AWSWorker, count: int = 1) -> Farm:
|
|
82
|
+
"""Bring up ``count`` instances of ``worker`` and join them to the cluster."""
|
|
83
|
+
node_type, machine = self._configured(worker)
|
|
84
|
+
aws = self.aws_config
|
|
85
|
+
machine = replace(machine, count=count, KeyName=aws.key_name,
|
|
86
|
+
ssh_user=aws.ssh_user, ssh_private_key=aws.ssh_private_key,
|
|
87
|
+
ImageId=machine.ImageId or get_default_ami(aws.region))
|
|
88
|
+
nodes = {node_type.name: machine}
|
|
89
|
+
|
|
90
|
+
ips = provision_aws_nodes(self.cluster_config.cluster_name, nodes, aws.region,
|
|
91
|
+
self._vpc_id, self._vpc_head_ip)[node_type.name]
|
|
92
|
+
farm = Farm(node_type.name, aws.region, ips, ray.get_runtime_context().current_actor)
|
|
93
|
+
try:
|
|
94
|
+
# A copy: this launch's machines stay out of the manager's config.
|
|
95
|
+
config = copy.deepcopy(self.cluster_config)
|
|
96
|
+
tunnel = None if self._vpc_head_ip else self._head_tunnel_config()
|
|
97
|
+
for ip in ips:
|
|
98
|
+
config.auth_overrides[ip] = SSHAuthConfig(
|
|
99
|
+
ssh_user=aws.ssh_user, ssh_private_key=aws.ssh_private_key,
|
|
100
|
+
tunnel=tunnel)
|
|
101
|
+
run_aws_setup(nodes, {node_type.name: ips}, config.get_ssh_auth)
|
|
102
|
+
|
|
103
|
+
# add_nodes_to_cluster allocates tunnels across the whole config, keyed
|
|
104
|
+
# by assign_nodes' worker indexes, so the node joins the copy first
|
|
105
|
+
# and its assignments come from assign_nodes.
|
|
106
|
+
config.worker_ips = config.worker_ips + ips
|
|
107
|
+
# The container's AWS calls (F2_VIVADO's aws_create_afi) need a region.
|
|
108
|
+
docker = node_type.docker and replace(node_type.docker, run_options=[
|
|
109
|
+
*node_type.docker.run_options, "-e", f"AWS_DEFAULT_REGION={aws.region}"])
|
|
110
|
+
config.node_types[node_type.name] = replace(
|
|
111
|
+
node_type, num_workers=count, compatible_ips=ips, docker=docker)
|
|
112
|
+
self._tunnels[tuple(ips)] = add_nodes_to_cluster(
|
|
113
|
+
config, [a for a in assign_nodes(config) if a.ip in ips])
|
|
114
|
+
except Exception:
|
|
115
|
+
self.teardown(farm)
|
|
116
|
+
raise
|
|
117
|
+
logger.info(f"{len(ips)} '{node_type.name}' worker(s) joined")
|
|
118
|
+
return farm
|
|
119
|
+
|
|
120
|
+
def _configured(self, worker: AWSWorker) -> AWSWorker:
|
|
121
|
+
"""``worker`` with the changes of its entry in the cluster file's ``aws: workers:``."""
|
|
122
|
+
node_type, machine = worker
|
|
123
|
+
aws = self.cluster_config.aws_config
|
|
124
|
+
changes = dict(aws.workers.get(node_type.name, {})) if aws else {}
|
|
125
|
+
if "image" in changes:
|
|
126
|
+
node_type = replace(node_type, docker=replace(node_type.docker, image=changes.pop("image")))
|
|
127
|
+
return node_type, replace(machine, **changes)
|
|
128
|
+
|
|
129
|
+
def teardown(self, farm: Farm) -> None:
|
|
130
|
+
"""Close the farm's tunnels and terminate its instances."""
|
|
131
|
+
# TODO: tunnels are kept per launch, so a farm with part of a launch's machines
|
|
132
|
+
# (one FPGA taken down early) closes none; each exits when its machine goes.
|
|
133
|
+
tunnels = self._tunnels.pop(tuple(farm.ips), None)
|
|
134
|
+
if tunnels is not None:
|
|
135
|
+
tunnels.stop_all()
|
|
136
|
+
if farm.ips:
|
|
137
|
+
import boto3
|
|
138
|
+
|
|
139
|
+
# With connection "vpc", the farm's IPs are private ones.
|
|
140
|
+
address = "private-ip-address" if self._vpc_head_ip else "ip-address"
|
|
141
|
+
reservations = boto3.client("ec2", region_name=farm.region).describe_instances(
|
|
142
|
+
Filters=[{"Name": address, "Values": farm.ips}])["Reservations"]
|
|
143
|
+
ids = [i["InstanceId"] for r in reservations for i in r["Instances"]]
|
|
144
|
+
if ids:
|
|
145
|
+
logger.info(f"Terminating {len(ids)} '{farm.name}' instance(s)")
|
|
146
|
+
terminate_ec2_instances(ids, region=farm.region)
|
|
147
|
+
|
|
148
|
+
def _head_tunnel_config(self) -> TunnelConfig:
|
|
149
|
+
"""Tunnel ports for the running head, all read from the running cluster:
|
|
150
|
+
GCS and raylet ports as Ray reports them, and the worker-port range from
|
|
151
|
+
the head raylet's arguments (this runs on the head)."""
|
|
152
|
+
gcs_port = int(ray.get_runtime_context().gcs_address.rsplit(":", 1)[1])
|
|
153
|
+
head = next(n for n in ray.nodes() if "node:__internal_head__" in n["Resources"])
|
|
154
|
+
# Sorted: the workers' iptables rule takes the two as one low:high range.
|
|
155
|
+
low, high = sorted((head["NodeManagerPort"], head["ObjectManagerPort"]))
|
|
156
|
+
args = next(a for a in (_cmdline(p) for p in os.listdir("/proc") if p.isdigit())
|
|
157
|
+
if f"--node_id={head['NodeID']}" in a)
|
|
158
|
+
worker = {k: int(next(a.split("=", 1)[1] for a in args
|
|
159
|
+
if a.startswith(f"--{k}_worker_port=")))
|
|
160
|
+
for k in ("min", "max")}
|
|
161
|
+
return TunnelConfig(gcs_tunnel_port=gcs_port,
|
|
162
|
+
head_node_manager_port=low, head_object_manager_port=high,
|
|
163
|
+
head_worker_port_min=worker["min"],
|
|
164
|
+
head_worker_port_max=worker["max"])
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def start_aws_manager(cluster_config: ClusterConfig, aws_config: AWSConfig):
|
|
168
|
+
"""Start an :class:`AWSManager` actor on the head and return its handle."""
|
|
169
|
+
# TODO: read the cluster file that `chia up` used, so loops need not pass it.
|
|
170
|
+
actor = ray.remote(AWSManager).options(
|
|
171
|
+
num_cpus=0, resources={"node:__internal_head__": 0.001})
|
|
172
|
+
return chia_actor(actor.remote(cluster_config, aws_config))
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _cmdline(pid: str) -> list[str]:
|
|
176
|
+
try:
|
|
177
|
+
with open(f"/proc/{pid}/cmdline", "rb") as f:
|
|
178
|
+
return f.read().decode().split("\0")
|
|
179
|
+
except OSError:
|
|
180
|
+
return []
|
|
@@ -21,6 +21,7 @@ drop down to the raw boto3 client via ``node._client``.
|
|
|
21
21
|
|
|
22
22
|
from __future__ import annotations
|
|
23
23
|
|
|
24
|
+
import io
|
|
24
25
|
import logging
|
|
25
26
|
import time
|
|
26
27
|
from dataclasses import dataclass
|
|
@@ -206,7 +207,13 @@ class S3Node:
|
|
|
206
207
|
)
|
|
207
208
|
|
|
208
209
|
def put_bytes(self, key: str, data: bytes, content_type: str | None = None) -> None:
|
|
209
|
-
"""Write ``data`` to ``key
|
|
210
|
+
"""Write ``data`` to ``key``, in parts above 1 GiB (one PUT takes 5 GB at most)."""
|
|
211
|
+
if len(data) > 2**30:
|
|
212
|
+
extra = {"ContentType": content_type} if content_type is not None else {}
|
|
213
|
+
self._call(f"upload_fileobj s3://{self.bucket}/{key}",
|
|
214
|
+
lambda: self._client.upload_fileobj(io.BytesIO(data), self.bucket, key,
|
|
215
|
+
ExtraArgs=extra))
|
|
216
|
+
return
|
|
210
217
|
kwargs: dict[str, Any] = {"Bucket": self.bucket, "Key": key, "Body": data}
|
|
211
218
|
if content_type is not None:
|
|
212
219
|
kwargs["ContentType"] = content_type
|
|
@@ -384,6 +384,18 @@ def _try_proxy(func, opts, bypass_state, hooks, args, kwargs, display_name):
|
|
|
384
384
|
func, full_opts, bypass_state, hooks, profile, args, kwargs)
|
|
385
385
|
|
|
386
386
|
|
|
387
|
+
def _setup_worker_logging() -> None:
|
|
388
|
+
"""Show a task's INFO logs: a Ray worker has no log handler, so Python drops
|
|
389
|
+
everything below WARNING. Adds one handler per worker."""
|
|
390
|
+
root = logging.getLogger()
|
|
391
|
+
if not root.handlers:
|
|
392
|
+
handler = logging.StreamHandler()
|
|
393
|
+
handler.setLevel(logging.INFO)
|
|
394
|
+
handler.setFormatter(logging.Formatter("%(levelname)s [%(name)s] %(message)s"))
|
|
395
|
+
root.addHandler(handler)
|
|
396
|
+
root.setLevel(logging.INFO)
|
|
397
|
+
|
|
398
|
+
|
|
387
399
|
def _chia_trampoline(func, _chia_bypass_state_, _chia_hooks_, *args, **kwargs):
|
|
388
400
|
"""Trampoline function used by ChiaFunction to dispatch remote calls.
|
|
389
401
|
|
|
@@ -393,6 +405,7 @@ def _chia_trampoline(func, _chia_bypass_state_, _chia_hooks_, *args, **kwargs):
|
|
|
393
405
|
callables. Both are attached by chia_remote() and named with underscores to
|
|
394
406
|
avoid collisions with user function parameters.
|
|
395
407
|
"""
|
|
408
|
+
_setup_worker_logging()
|
|
396
409
|
_restore_bypass(_chia_bypass_state_)
|
|
397
410
|
from chia.base.pid_registry import _pid_tracking_scope
|
|
398
411
|
_run_chia_setup(_chia_hooks_)
|
|
@@ -410,6 +423,7 @@ def _chia_trampoline_profiled(func, call_id, dispatch_meta, _chia_bypass_state_,
|
|
|
410
423
|
event at function end, both from the worker. Returns a
|
|
411
424
|
``_ProfiledResult`` that ``get()`` unwraps transparently.
|
|
412
425
|
"""
|
|
426
|
+
_setup_worker_logging()
|
|
413
427
|
_restore_bypass(_chia_bypass_state_)
|
|
414
428
|
import time as _time
|
|
415
429
|
from chia.trace.profiler import _ProfiledResult, get_profiler
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from chia.base.ChiaFunction import ChiaFunction, get
|
|
6
|
+
|
|
7
|
+
HEAD = "node:__internal_head__"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@ChiaFunction(num_cpus=0)
|
|
11
|
+
def _append(data: bytes, path: str) -> str:
|
|
12
|
+
if path.startswith("s3://"):
|
|
13
|
+
from chia.aws.s3 import S3Node
|
|
14
|
+
bucket, key = path.removeprefix("s3://").split("/", 1)
|
|
15
|
+
s3 = S3Node(bucket)
|
|
16
|
+
s3.put_bytes(key, (s3.get_bytes(key) if s3.exists(key) else b"") + data)
|
|
17
|
+
else:
|
|
18
|
+
Path(path).parent.mkdir(parents=True, exist_ok=True)
|
|
19
|
+
with open(path, "ab") as f:
|
|
20
|
+
f.write(data)
|
|
21
|
+
return path
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def chia_log(data: bytes | str, path: str, resource: str | None = None) -> str:
|
|
25
|
+
"""Add ``data`` to the end of ``path`` on a machine with ``resource``, the head when
|
|
26
|
+
``None``, and return ``path``. A path that starts with ``s3://bucket/key`` is an S3
|
|
27
|
+
object, written with that machine's AWS credentials.
|
|
28
|
+
|
|
29
|
+
Do not pass a resource that the calling task holds: the write would wait for that task
|
|
30
|
+
to end. Writing on the caller's own machine needs a local option, not supported yet.
|
|
31
|
+
"""
|
|
32
|
+
if isinstance(data, str):
|
|
33
|
+
data = data.encode()
|
|
34
|
+
return get(_append.options(resources={resource or HEAD: 0.001}).chia_remote(data, path))
|
|
@@ -4,10 +4,13 @@ import re
|
|
|
4
4
|
import shlex
|
|
5
5
|
import subprocess
|
|
6
6
|
import logging
|
|
7
|
+
import uuid
|
|
8
|
+
from datetime import datetime
|
|
7
9
|
from chia.chipyard.state_def import BuildArtifact, BuildTarget, SpikeBuildArtifact
|
|
8
10
|
from chia.chipyard.spike_build_node import STATIC_ARCHIVES, stage_golden_model
|
|
9
11
|
from chia.trace.profiler import get_profiler
|
|
10
12
|
from chia.base.ChiaFunction import ChiaFunction
|
|
13
|
+
from chia.base.chia_log import chia_log
|
|
11
14
|
|
|
12
15
|
# Maximum number of WF_SCOPES paths supported by the Makefile and TestDriver.v
|
|
13
16
|
# (the .v file has WF_SCOPE_1 ... WF_SCOPE_8 ifdef branches).
|
|
@@ -51,6 +54,8 @@ class ChiselBuildNode:
|
|
|
51
54
|
wf_scopes: list[str] | tuple[str, ...] = (),
|
|
52
55
|
clean_wf_stamp: bool = True,
|
|
53
56
|
logging_level: int = logging.DEBUG,
|
|
57
|
+
log_dir: str | None = None,
|
|
58
|
+
logging_resource: str | None = None,
|
|
54
59
|
name: str = "chipyard",
|
|
55
60
|
):
|
|
56
61
|
"""Configure a single Chipyard Verilator build.
|
|
@@ -122,6 +127,10 @@ class ChiselBuildNode:
|
|
|
122
127
|
re-applies the scope filter even when it would otherwise
|
|
123
128
|
consider nothing changed (mirrors ``run_wave.sh``).
|
|
124
129
|
logging_level: Python logging level for this node's logger.
|
|
130
|
+
log_dir: A folder, or an ``s3://`` prefix, for this node's build
|
|
131
|
+
logs. ``None`` keeps none; the result has them either way.
|
|
132
|
+
logging_resource: The resource of the machine that writes into
|
|
133
|
+
``log_dir``; ``None`` means the head.
|
|
125
134
|
name: Label copied into the resulting ``BuildArtifact.name``;
|
|
126
135
|
purely for downstream identification/traceability.
|
|
127
136
|
"""
|
|
@@ -143,6 +152,8 @@ class ChiselBuildNode:
|
|
|
143
152
|
self.wf_scopes = list(wf_scopes)
|
|
144
153
|
self.clean_wf_stamp = clean_wf_stamp
|
|
145
154
|
self.logging_level = logging_level
|
|
155
|
+
self.log_dir = log_dir
|
|
156
|
+
self.logging_resource = logging_resource
|
|
146
157
|
self.name = name
|
|
147
158
|
self.logger = logging.getLogger(self.logging_name)
|
|
148
159
|
self.logger.setLevel(self.logging_level)
|
|
@@ -300,6 +311,24 @@ class ChiselBuildNode:
|
|
|
300
311
|
needed.append((name, path if path and path != "not found" else None))
|
|
301
312
|
return needed
|
|
302
313
|
|
|
314
|
+
def _log(self, cmd: str, sims_dir: str, returncode: int,
|
|
315
|
+
stdout: str, stderr: str) -> None:
|
|
316
|
+
"""Write this build's output to its own file in ``log_dir``, when
|
|
317
|
+
``log_dir`` is set. One file per call, so parallel builds never share
|
|
318
|
+
a file."""
|
|
319
|
+
if not self.log_dir:
|
|
320
|
+
return
|
|
321
|
+
name = f"{self.config}_{datetime.now().strftime('%Y%m%d-%H%M%S')}_{uuid.uuid4().hex[:8]}.log"
|
|
322
|
+
chia_log(
|
|
323
|
+
"=" * 80 + "\n"
|
|
324
|
+
f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] {self.config} "
|
|
325
|
+
f"returncode={returncode}\n"
|
|
326
|
+
+ "=" * 80 + "\n\n"
|
|
327
|
+
f"[Command] {cmd} (in {sims_dir})\n\n"
|
|
328
|
+
f"[stdout]\n{stdout}\n\n"
|
|
329
|
+
f"[stderr]\n{stderr}\n",
|
|
330
|
+
f"{self.log_dir}/{name}", self.logging_resource)
|
|
331
|
+
|
|
303
332
|
@ChiaFunction(resources={"chipyard": 1})
|
|
304
333
|
def build(self) -> BuildArtifact:
|
|
305
334
|
"""Run the Chipyard Make flow and return the compiled simulator.
|
|
@@ -437,6 +466,7 @@ class ChiselBuildNode:
|
|
|
437
466
|
self.logger.info(f"Build timed out after {self.timeout_seconds} seconds")
|
|
438
467
|
stdout = e.stdout.decode(errors="replace") if e.stdout else ""
|
|
439
468
|
stderr = e.stderr.decode(errors="replace") if e.stderr else ""
|
|
469
|
+
self._log(cmd, sims_dir, -1, stdout, stderr + "\nBuild timed out")
|
|
440
470
|
return BuildArtifact(
|
|
441
471
|
name=self.name,
|
|
442
472
|
simulator_binary_content=b"",
|
|
@@ -453,6 +483,7 @@ class ChiselBuildNode:
|
|
|
453
483
|
if result.returncode != 0:
|
|
454
484
|
self.logger.info(f"Build failed stderr: {result.stderr[-500:]}")
|
|
455
485
|
self.logger.info(f"Build failed stdout: {result.stdout[-500:]}")
|
|
486
|
+
self._log(cmd, sims_dir, result.returncode, result.stdout, result.stderr)
|
|
456
487
|
return BuildArtifact(
|
|
457
488
|
name=self.name,
|
|
458
489
|
simulator_binary_content=b"",
|
|
@@ -476,6 +507,7 @@ class ChiselBuildNode:
|
|
|
476
507
|
runtime_libs = (self._collect_runtime_libs(binary_path)
|
|
477
508
|
if self.bundle_runtime_libs else [])
|
|
478
509
|
|
|
510
|
+
self._log(cmd, sims_dir, result.returncode, result.stdout, result.stderr)
|
|
479
511
|
return BuildArtifact(
|
|
480
512
|
name=self.name,
|
|
481
513
|
simulator_binary_content=binary_content,
|
|
@@ -144,6 +144,7 @@ class FireMarshalNode:
|
|
|
144
144
|
work_dir: str = "/tmp/fm",
|
|
145
145
|
config: "dict | None" = None,
|
|
146
146
|
rootfs_size_mib: int = 0,
|
|
147
|
+
overlay_modes: "dict[str, int] | None" = None,
|
|
147
148
|
) -> FireMarshalArtifact:
|
|
148
149
|
"""Compose ``overlay_files`` onto the stored base ``base_name`` and return
|
|
149
150
|
the workload image(s) + FireSim descriptor as sparse-tar bytes.
|
|
@@ -161,10 +162,13 @@ class FireMarshalNode:
|
|
|
161
162
|
config: Workload options as a dict (the marshal-config run knobs):
|
|
162
163
|
``command`` (str, baked as the boot run-script), ``jobs`` (list of
|
|
163
164
|
``{"name","command","outputs"}`` — one image per job, emitted as the
|
|
164
|
-
FireSim descriptor's ``workloads
|
|
165
|
+
FireSim descriptor's ``workloads``; a job's ``files``, keys of
|
|
166
|
+
``overlay_files``, limit its image to them), ``outputs`` (default guest
|
|
165
167
|
paths), ``post_run_hook`` (str), ``simulation_outputs`` (default
|
|
166
168
|
``["uartlog"]``).
|
|
167
169
|
rootfs_size_mib: Grow the rootfs before composing (``0`` keeps base size).
|
|
170
|
+
overlay_modes: Permission bits of ``overlay_files``, same keys (e.g.
|
|
171
|
+
``0o755`` for an executable). A file without one gets the default.
|
|
168
172
|
"""
|
|
169
173
|
config = config or {}
|
|
170
174
|
json_path = os.path.join(self._dir(name), f"{name}.json")
|
|
@@ -175,7 +179,8 @@ class FireMarshalNode:
|
|
|
175
179
|
b"", "", "", f"{name}.json", success=False, stdout="",
|
|
176
180
|
stderr=f"base '{base_name}' not found in {self.image_store}", returncode=1)
|
|
177
181
|
returncode, stdout, stderr = self._compose_workload(
|
|
178
|
-
base_name, name, overlay_files,
|
|
182
|
+
base_name, name, overlay_files, overlay_modes or {}, config,
|
|
183
|
+
rootfs_size_mib, work_dir)
|
|
179
184
|
|
|
180
185
|
archive = b""
|
|
181
186
|
if returncode == 0 and os.path.isfile(json_path):
|
|
@@ -259,12 +264,11 @@ class FireMarshalNode:
|
|
|
259
264
|
|
|
260
265
|
# ---- compose internals --------------------------------------------------
|
|
261
266
|
|
|
262
|
-
def _compose_workload(self, base_name, name, overlay_files, config,
|
|
267
|
+
def _compose_workload(self, base_name, name, overlay_files, overlay_modes, config,
|
|
263
268
|
rootfs_size_mib, work_dir) -> "tuple[int, str, str]":
|
|
264
269
|
os.makedirs(work_dir, exist_ok=True)
|
|
265
270
|
work = os.path.join(work_dir, f".fm-{uuid.uuid4().hex[:8]}")
|
|
266
271
|
overlay_dir = os.path.join(work, "overlay")
|
|
267
|
-
self._write_overlay(overlay_files, overlay_dir)
|
|
268
272
|
dst = self._dir(name)
|
|
269
273
|
os.makedirs(dst, exist_ok=True)
|
|
270
274
|
base_img = os.path.join(self._dir(base_name), f"{base_name}.img")
|
|
@@ -277,7 +281,13 @@ class FireMarshalNode:
|
|
|
277
281
|
else [(name, config.get("command"), config.get("outputs", []))])
|
|
278
282
|
|
|
279
283
|
stdout, stderr = "", ""
|
|
280
|
-
|
|
284
|
+
written = None # the overlay files now in overlay_dir
|
|
285
|
+
for (target, command, _outs), job in zip(targets, jobs or [{}]):
|
|
286
|
+
files = job.get("files", list(overlay_files))
|
|
287
|
+
if files != written:
|
|
288
|
+
shutil.rmtree(overlay_dir, ignore_errors=True)
|
|
289
|
+
self._write_overlay({p: overlay_files[p] for p in files}, overlay_modes, overlay_dir)
|
|
290
|
+
written = files
|
|
281
291
|
self._set_run_script(overlay_dir, command)
|
|
282
292
|
self.logger.info(f"Composing {target} from base {base_name}")
|
|
283
293
|
out, err, rc = self._run(
|
|
@@ -308,14 +318,18 @@ class FireMarshalNode:
|
|
|
308
318
|
os.remove(path)
|
|
309
319
|
|
|
310
320
|
@staticmethod
|
|
311
|
-
def _write_overlay(overlay_files: dict[str, bytes],
|
|
312
|
-
|
|
321
|
+
def _write_overlay(overlay_files: dict[str, bytes], overlay_modes: dict[str, int],
|
|
322
|
+
overlay_dir: str) -> None:
|
|
323
|
+
"""Materialize overlay_files into overlay_dir, mirroring the rootfs layout,
|
|
324
|
+
with the permission bits in overlay_modes."""
|
|
313
325
|
os.makedirs(overlay_dir, exist_ok=True)
|
|
314
326
|
for rel_path, content in overlay_files.items():
|
|
315
327
|
dest = os.path.join(overlay_dir, rel_path)
|
|
316
328
|
os.makedirs(os.path.dirname(dest) or overlay_dir, exist_ok=True)
|
|
317
329
|
with open(dest, "wb") as f:
|
|
318
330
|
f.write(content)
|
|
331
|
+
if rel_path in overlay_modes:
|
|
332
|
+
os.chmod(dest, overlay_modes[rel_path])
|
|
319
333
|
|
|
320
334
|
@staticmethod
|
|
321
335
|
def _write_descriptor(path: str, name: str, config: dict, targets: list) -> None:
|