rosotacom-dev 2.5.dev76__tar.gz → 2.5.dev78__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.
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/PKG-INFO +1 -1
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/findings/neither-a-queue-nor-a-burst-tilts-the-size-law.md +60 -17
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/cli.py +180 -14
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/cli_benchmark.py +27 -21
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/profiles.yaml +71 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom_dev.egg-info/PKG-INFO +1 -1
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom_dev.egg-info/SOURCES.txt +1 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom_dev.egg-info/scm_file_list.json +1 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom_dev.egg-info/scm_version.json +2 -2
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_cli_benchmark.py +9 -1
- rosotacom_dev-2.5.dev78/tests/unit/test_ota_benchmark_peer_exec.py +134 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/.devcontainer/devcontainer.json.template +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/.devcontainer/re_generate_devcontainer_json.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/.github/CODEOWNERS +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/.github/ISSUE_TEMPLATE/documentation-audit.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/.github/ISSUE_TEMPLATE/implementation-cleanup.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/.github/ISSUE_TEMPLATE/quality-workflow.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/.github/ISSUE_TEMPLATE/redesign.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/.github/ISSUE_TEMPLATE/release-process.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/.github/ISSUE_TEMPLATE/repository-diagnosis.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/.github/ISSUE_TEMPLATE/test-ci-audit.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/.github/ISSUE_TEMPLATE/work-item.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/.github/actions/setup-just/action.yml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/.github/dependabot.yml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/.github/workflows/benchmark-calibrate.yml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/.github/workflows/benchmark-gate.yml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/.github/workflows/dev-release.yml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/.github/workflows/image-scan.yml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/.github/workflows/nightly-e2e.yml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/.github/workflows/pr-lightweight.yml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/.github/workflows/pr-merge-gate.yml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/.github/workflows/release.yml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/.pre-commit-config.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/AGENTS.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/CONCURRENCY.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/CONTRIBUTING.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/DEVELOPMENT_PRINCIPLES.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/MANIFEST.in +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/README.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/budgets.jsonl +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/calibration/README.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/calibration/capacity-size-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/calibration/probe-loss-gop-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/calibration/probe-loss-nominal-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/calibration/probe-loss-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/calibration/probe-loss-tight-fastdds.json +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/calibration/probe-loss-tight-zenoh.json +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/codecov.yml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/deployment-configuration.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/benchmark-ab.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/benchmark-bag-as-load.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/ci.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/ffmpeg-keyframes.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/findings/README.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/findings/a-fitted-delay-table-never-reached-the-shaper.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/findings/a-shorter-group-does-not-lose-fewer-key-frames.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/findings/a-transport-element-doubles-every-fastdds-sample.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/findings/cyclone-fragment-equal-to-max-drops-fragmented-samples.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/findings/cyclone-spdp-discovery-bursts.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/findings/delay-alone-no-loss.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/findings/fastdds-datagram-cap-drops-large-samples.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/findings/graph-derived-types-block-a-non-graph-transport.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/findings/head-of-line-irregularity.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/findings/jitter-loss-bandwidth-latency.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/findings/keyframe-loss-kills-the-next-deltas.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/findings/lifespan-is-enforced-by-one-reader-and-not-the-other.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/findings/lighter-message-loss.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/findings/one-domain-two-cyclone-configs-stop-interoperating.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/findings/oversubscription-queues-not-losses.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/findings/reorder-becomes-reader-loss.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/findings/repro/decode_chain_repro.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/findings/repro/reorder_drop_repro.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/findings/sender-rows-make-a-dead-link-look-loss-free.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/findings/the-size-law-belongs-to-the-transport-not-the-link.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/findings/zero-loss-boundaries-18kb-20hz.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/forensics-report.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/geo-link-map.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/github-repository-settings.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/link-bandwidth.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/link-trace.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/ota-pcap.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/owner-runbook.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/performance-bands.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/playbooks/README.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/quality-model.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/release-notes/TEMPLATE.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/release-notes/v2.1.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/release-notes/v2.2.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/release-notes/v2.3.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/release-notes/v2.4.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/release.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/rfcs/0001-expectation-driven-test-suite.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/rfcs/0002-expectation-concepts.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/rfcs/0003-metric-backbone.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/rfcs/0004-network-profiles.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/rfcs/0005-benchmark-genres-and-ci.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/rfcs/0006-dynamic-qos.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/rfcs/0007-regression-gate.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/rfcs/README.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/testing.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/docs/work-items.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/install.sh +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/justfile +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/media/control_center.png +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/media/echo_test.png +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/media/forensics-report-example.png +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/media/host.png +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/media/vehicle.png +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/pyproject.toml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/requirements.txt +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/rosotacom.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/session-configuration.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/setup.cfg +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/__init__.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/__main__.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/anonymize.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/bag_ground_truth.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/benched_set.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/benchmark.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/benchmark_delta.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/bundle_check.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/deployment.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/ffmpeg_packet.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/forensics.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/geomap.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/image_cache.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/netem_dist.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/network_preflight.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/network_profiles.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/network_shaper.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/plots.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/py.typed +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/benched-set.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/.gitignore +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/README.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/__init__.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/bags/8_drop_reference/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/deployment.example.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/dist/field-20260817.dist +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/ros2docker.lyrical.json +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/rosotacom.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scenarios/2_native_chatter/scenario-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_a.sh +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_b.sh +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/external.lyrical.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/wait_for_echo_topic.sh +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/external.lyrical.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/foxglove.json +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/foxglove.json +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/sessions/10_restamp/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/sessions/11_trickle/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/sessions/12_content_integrity/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/sessions/13_link_latency/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/sessions/14_remote_assist_anonymized/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/sessions/15_remote_assist_anonymized_costmap/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/sessions/16_remote_assist_anonymized_camera/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/sessions/17_synthetic_camera_quality/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/sessions/1_heartbeat/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/sessions/1_heartbeat_status/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/sessions/2_native_chatter/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/sessions/3_comp_occ_grid/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/sessions/4_comp_occ_grid_zen/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/sessions/5_sized_payload/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/sessions/6_sized_payload_zen/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/sessions/7_latched_static/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/sessions/8_drop/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/sessions/9_throttle/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/sessions/bench_1_1_capacity/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/sessions/bench_1_2_load_sweep/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/sessions/bench_1_3_ramp/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/sessions/bench_1_4_recovery/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/sessions/bench_1_5_camera/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ros2docker.json.example +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ros2docker.lyrical.json.example +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/.vscode/c_cpp_properties.json +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/.vscode/settings.json +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_easy_mode.xml.template +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_initial_peer_list.xml.template +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v2.xml.template +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v3.xml.template +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v4.xml.template +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v5.xml.template +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ota_configs/create_zenoh_json5.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ota_configs/cyclonedds_local_participants.xml.template +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ota_configs/cyclonedds_minimal.xml.template +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ota_configs/cyclonedds_scoped.xml.template +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ota_configs/cyclonedds_tuned.xml.template +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ota_configs/fastdds_easy_mode.xml.template +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ota_configs/fastdds_local.xml.template +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ota_configs/fastdds_tuned.xml.template +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ota_configs/fastdds_unicast.xml.template +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ota_configs/get_ota_xml.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ota_configs/utils.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ota_configs/zenoh.json5.template +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/.gitkeep +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_cpp/CMakeLists.txt +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_cpp/COLCON_IGNORE +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_cpp/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_cpp/package.xml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_cpp/src/hz_monitor.cpp +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_compressor.cpp +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_decompressor.cpp +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_msgs/CMakeLists.txt +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_msgs/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/CompressedData.msg +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/EchoHeartbeat.msg +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/OtaStamped.msg +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/SizedPayload.msg +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_msgs/package.xml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/__init__.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/base_bridge_relay.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_in.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_out.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/ffmpeg_flags.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/heartbeat_echo.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/hz_monitor.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_bandwidth_reducer.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_pixel_capper.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/lanelet_saver.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/latch_relay.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/costmap_remapper.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/marker_remapper.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/speed_test.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/tf_remapper.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/traffic_monitor.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/wifi_network_analysis_1.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_bytes.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_trace.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/local_global_frame_bridge.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/localization_map_split_reduce_saver.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/msg_transform.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/ota_pcap.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pair_management.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/playout_pacer.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/playout_pacer_core.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pub_sub_pair.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/qos.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_in.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_out.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/restamp.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/sized_publisher.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency_core.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview_core.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/tf_map_to_cart_saver.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_monitor.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_resolution.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/trickle.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_compressor.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_decompressor.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_unwrapper.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_wrapper.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/package.xml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/resource/com_py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/setup.cfg +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/setup.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/test/test_copyright.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/test/test_flake8.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/ros2src/com_py/test/test_pep257.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/session/content/base/session_plugin_base.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/session/content/network/up_connectivity.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/session/content/network/wifi_network_analysis_2.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/session/creation/anonymize_bag.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/session/creation/catmux_log_setup.sh +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/session/creation/create_session_yaml.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/session/creation/generate_session_files.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/session/creation/run_session.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/session/creation/run_session_in_external_terminal.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/ws/session/creation/strip_ansi.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/status_eval.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/stream_stats.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/trace_profiles.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/transit.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/video_quality.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom_dev.egg-info/dependency_links.txt +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom_dev.egg-info/entry_points.txt +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom_dev.egg-info/requires.txt +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom_dev.egg-info/top_level.txt +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/terminology.md +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/contract/test_benched_set_registry.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/contract/test_findings.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/contract/test_generated_topics_have_a_producer.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/contract/test_lyrical_runtime_compat.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/contract/test_markdown_links.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/contract/test_ota_source_bundle.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/contract/test_package_metadata.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/contract/test_packaged_resources.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/contract/test_profile_covers_generated_commands.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/contract/test_pytest_policy.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/contract/test_readme_examples.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/contract/test_security_maintenance_config.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/contract/test_session_configuration_doc.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/contract/test_session_template_substitution.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/contract/test_workflow_contracts.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/e2e/conftest.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/e2e/test_anonymize_e2e.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/e2e/test_benchmark_ab.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/e2e/test_benchmark_capacity.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/e2e/test_benchmark_replay.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/e2e/test_parallel_smoke.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/e2e/test_smoke.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/e2e/test_timeline_stepping.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/e2e/test_video_quality_e2e.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/sessions/generate_rmw_matrix.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-local_zenoh-ros2dds-ota/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota-tuned/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/sessions/rmw_matrix/1_heartbeat_fastdds/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/sessions/rmw_matrix/1_heartbeat_fastdds-default/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/sessions/rmw_matrix/1_heartbeat_zen-endpoints/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_anonymize.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_bag_ground_truth.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_benched_set.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_benchmark_delta.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_bundle_check.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_catmux_pane_logging.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_cli.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_concurrency.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_container_shaping.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_deployment.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_ffmpeg_flags.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_ffmpeg_packet.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_field_profiles.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_forensics.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_geomap.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_image_cache.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_link_bytes.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_link_trace.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_netem_dist.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_network_preflight.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_network_profiles.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_network_shaper.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_ota_link_configs.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_ota_pcap.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_ota_unwrapper.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_ota_wrapper.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_ota_xml.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_playout_pacer.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_plots.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_pub_sub_pair_types.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_qos_fallback_logging.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_relay_optional_parameters.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_ros_node_entity_ownership.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_session_pipeline.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_stage_latency.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_status_eval.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_status_overview.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_status_overview_observer.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_stream_stats.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_terminology_stage_ownership.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_trace_profiles.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_transit.py +0 -0
- {rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/tests/unit/test_video_quality.py +0 -0
|
@@ -10,6 +10,7 @@ were emulated against the same measurement chain, and none of them produces it.
|
|
|
10
10
|
| | 300 B | 1.1 kB | 3.1 kB | 6.1 kB | 12.1 kB | 38.1 kB |
|
|
11
11
|
|---|---:|---:|---:|---:|---:|---:|
|
|
12
12
|
| independent per packet | 1.05 % | 1.47 % | 3.47 % | 6.28 % | 11.23 % | 31.92 % |
|
|
13
|
+
| a two-state process, same mean, 105 ms bad runs | 1.47 % | 1.76 % | 2.76 % | 5.09 % | 10.00 % | **21.98 %** |
|
|
13
14
|
| + a token bucket a burst can fill (4 Mbit/s) | 1.14 % | 1.33 % | 2.57 % | 4.99 % | 13.43 % | 32.92 % |
|
|
14
15
|
| a serialisation constraint (1.5 Mbit/s) | — | 1.62 % | — | — | 11.60 % | **97.54 %** |
|
|
15
16
|
|
|
@@ -17,6 +18,16 @@ were emulated against the same measurement chain, and none of them produces it.
|
|
|
17
18
|
law is reproduced with residuals of 1.20, 0.85, 1.01, 1.06, 0.97 and 1.00 —
|
|
18
19
|
flat over three decades of size. Whatever tilts the field, it is not the
|
|
19
20
|
wrapper, the join, or the way the fit is taken.
|
|
21
|
+
- **Clustered loss is not the cause, and it bends the curve the other way.**
|
|
22
|
+
A two-state process at the same 1 % mean, with its chain rescaled per cell so
|
|
23
|
+
that a bad run is the same 105 ms of wall clock in every one of them, makes
|
|
24
|
+
the largest class lose **31 % less** than the independent law rather than
|
|
25
|
+
more: 21.98 % against 31.92 %, intervals 20.3–23.8 against 30.0–33.9. The
|
|
26
|
+
reason is the one that makes it a mechanism rather than a coincidence — a
|
|
27
|
+
38-packet message occupies about the length of one bad run, so its packets
|
|
28
|
+
share a fate and the message is lost once instead of thirty-eight times
|
|
29
|
+
independently. The field's residual has the opposite sign, so burstiness at
|
|
30
|
+
this scale does not explain it; it makes it harder to explain.
|
|
20
31
|
- **A burst meeting a queue is not the cause.** A token bucket at 4 Mbit/s —
|
|
21
32
|
above the largest class's mean offered rate of 3.0 Mbit/s and far below its
|
|
22
33
|
instantaneous one, so a 38-packet message meets a queue and a 1-packet
|
|
@@ -81,17 +92,30 @@ The queued arm on the same ladder: 24, 28, 54, 105, 283 and 693 losses of about
|
|
|
81
92
|
2100 offered, giving the second row of the claim table. The tight arm: 34 of
|
|
82
93
|
2104, 244 of 2103, and 1826 of 1872.
|
|
83
94
|
|
|
84
|
-
**
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
95
|
+
**Measuring the two-state arm took two attempts, and the reason is worth
|
|
96
|
+
recording.** `netem`'s Gilbert–Elliott model advances its chain once per
|
|
97
|
+
*packet*, not once per second, so a size ladder at a fixed message rate runs the
|
|
98
|
+
chain at a different speed in every cell — 10 packets/s for a one-fragment
|
|
88
99
|
message against 380 for a 38-fragment one. The cells then do not share a loss
|
|
89
|
-
process
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
100
|
+
process. The arm measured that way duly reported a per-packet mean of 0.33 % in
|
|
101
|
+
its smallest cell against a stationary 1.00 %, because that cell never sampled
|
|
102
|
+
enough of the chain.
|
|
103
|
+
|
|
104
|
+
Holding the offered *packet* rate constant instead was the obvious fix and it
|
|
105
|
+
measured something else entirely: **the pipeline serves messages, not packets.**
|
|
106
|
+
At 60 messages/s the one-packet cell lost 10.774 % under the bursty profile and
|
|
107
|
+
10.626 % under the independent one, and at 380 messages/s 48.391 % and 48.430 %.
|
|
108
|
+
Two different loss processes cannot agree to three digits; what both were
|
|
109
|
+
reporting is the depth-1 OTA queue overwriting its own backlog before the link
|
|
110
|
+
sees it. That is the depth-1 overwrite of bundled publications, which the
|
|
111
|
+
operator harness's ledger records against a real drive, reached here by
|
|
112
|
+
accident and against a synthetic one.
|
|
113
|
+
|
|
114
|
+
What works is to leave the message rate at the field's 10 Hz and rescale the
|
|
115
|
+
chain: multiplying `p` and `r` by `380/(N × 10)` in each cell leaves the
|
|
116
|
+
stationary bad fraction at 3.92 % and the mean loss at 1 % while making the bad
|
|
117
|
+
run 105 ms of wall clock everywhere, which is the drive's own figure. The six
|
|
118
|
+
`bp-frag-*` profiles are that ladder.
|
|
95
119
|
|
|
96
120
|
Verification: manual, from a source checkout with Docker:
|
|
97
121
|
|
|
@@ -109,9 +133,19 @@ rosotacom benchmark probe --project src/rosotacom/resources/examples/rosotacom.y
|
|
|
109
133
|
--repeats 1 --sudo-mode container --no-plot
|
|
110
134
|
```
|
|
111
135
|
|
|
136
|
+
```bash
|
|
137
|
+
for pair in 200:one 1000:two 3000:four 6000:six 12000:twelve 38000:thirtyeight; do
|
|
138
|
+
rosotacom benchmark probe \
|
|
139
|
+
--project src/rosotacom/resources/examples/rosotacom.yaml \
|
|
140
|
+
--profile "bp-frag-${pair##*:}" --size "${pair%%:*}" --rate-hz 10 \
|
|
141
|
+
--duration 240 --repeats 1 --sudo-mode container --no-plot
|
|
142
|
+
done
|
|
143
|
+
```
|
|
144
|
+
|
|
112
145
|
The independent ladder must fit one `(p, F)` to within about ten per cent at
|
|
113
|
-
every point; the queued ladder must not differ from it systematically;
|
|
114
|
-
|
|
146
|
+
every point; the queued ladder must not differ from it systematically; the
|
|
147
|
+
rescaled two-state ladder must fall below it at the large end and not above; and
|
|
148
|
+
the tight cell at 38 kB must be near-total loss while its 1 kB cell is not.
|
|
115
149
|
|
|
116
150
|
## Status
|
|
117
151
|
|
|
@@ -126,11 +160,20 @@ the tilt is not an artefact of the accounting, it is not what a queue does to a
|
|
|
126
160
|
burst, and it is not a serialisation limit, because a serialisation limit does
|
|
127
161
|
not tilt a curve, it truncates it.
|
|
128
162
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
163
|
+
The clustered arm is the one that changes the reading rather than confirming
|
|
164
|
+
it. A reviewer's first guess for a size-systematic residual is burstiness, and
|
|
165
|
+
burstiness at the drive's own time scale produces the **opposite sign**: it
|
|
166
|
+
protects large messages, because a message long enough to span a bad run is lost
|
|
167
|
+
once rather than in each of its packets. So the field's residual is not
|
|
168
|
+
explained by the mechanism that the field's own two-layer model already
|
|
169
|
+
contains, which is worth saying out loud.
|
|
170
|
+
|
|
171
|
+
What is left to attack is correlation at a scale *shorter* than a large
|
|
172
|
+
message's own time on the wire — short enough that a message straddles a loss
|
|
173
|
+
event more often than a single packet does, without its packets sharing one.
|
|
174
|
+
`netem` cannot express that at all: its chain advances per packet, so a run is
|
|
175
|
+
always measured in packets rather than in milliseconds, and the two coincide
|
|
176
|
+
only at one message size.
|
|
134
177
|
|
|
135
178
|
The serialisation row deserves one sentence wherever a duty-cycled uplink is
|
|
136
179
|
discussed. It shows that the observable signature of such a link — small
|
|
@@ -293,6 +293,12 @@ class OtaSmokePlan:
|
|
|
293
293
|
peers: dict[str, OtaSmokePeer]
|
|
294
294
|
install_mode: str = "source"
|
|
295
295
|
install_pin: str | None = None
|
|
296
|
+
#: Where the peers write session instances, relative to the project file's
|
|
297
|
+
#: own directory. `session-instances` is the default a project that says
|
|
298
|
+
#: nothing gets; a project that sets `session_instances_dir` to anything
|
|
299
|
+
#: else -- `../instances`, say -- used to have its artifacts looked for in a
|
|
300
|
+
#: directory nothing writes to, and the miss was silent.
|
|
301
|
+
instances_rel: str = "session-instances"
|
|
296
302
|
|
|
297
303
|
|
|
298
304
|
@dataclass(frozen=True)
|
|
@@ -1835,6 +1841,26 @@ def _ota_checkout_project_path(project_config: Path) -> tuple[Path, str]:
|
|
|
1835
1841
|
)
|
|
1836
1842
|
|
|
1837
1843
|
|
|
1844
|
+
def _ota_instances_rel(runtime: RuntimeConfig) -> str:
|
|
1845
|
+
"""Where this project writes session instances, relative to its own file.
|
|
1846
|
+
|
|
1847
|
+
The peers resolve the project from their own checkout, so the *relative*
|
|
1848
|
+
answer is the one that travels; an absolute path is the orchestrator's and
|
|
1849
|
+
means nothing on the far side. A project that says nothing gets
|
|
1850
|
+
`session-instances`, which is what the collection used to assume for every
|
|
1851
|
+
project -- and a project that says `../instances` had its artifacts looked
|
|
1852
|
+
for in a directory nothing writes to.
|
|
1853
|
+
"""
|
|
1854
|
+
default = "session-instances"
|
|
1855
|
+
if not runtime.rosotacom_config:
|
|
1856
|
+
return default
|
|
1857
|
+
raw = _load_yaml_file(runtime.rosotacom_config)
|
|
1858
|
+
value = raw.get("session_instances_dir")
|
|
1859
|
+
if not value:
|
|
1860
|
+
return default
|
|
1861
|
+
return str(value)
|
|
1862
|
+
|
|
1863
|
+
|
|
1838
1864
|
def _ota_plan_from_bindings(
|
|
1839
1865
|
bindings: dict[str, PeerBinding],
|
|
1840
1866
|
*,
|
|
@@ -1845,6 +1871,7 @@ def _ota_plan_from_bindings(
|
|
|
1845
1871
|
project: str | None = None,
|
|
1846
1872
|
exec_commands: Mapping[str, str] | None = None,
|
|
1847
1873
|
cpusets: Mapping[str, str] | None = None,
|
|
1874
|
+
instances_rel: str = "session-instances",
|
|
1848
1875
|
) -> OtaSmokePlan:
|
|
1849
1876
|
_ota_validate_install_mode(install_mode)
|
|
1850
1877
|
if cpusets:
|
|
@@ -1923,6 +1950,7 @@ def _ota_plan_from_bindings(
|
|
|
1923
1950
|
peers=peers,
|
|
1924
1951
|
install_mode=install_mode,
|
|
1925
1952
|
install_pin=install_pin,
|
|
1953
|
+
instances_rel=instances_rel,
|
|
1926
1954
|
)
|
|
1927
1955
|
|
|
1928
1956
|
|
|
@@ -1935,6 +1963,7 @@ def _ota_write_state(instance: SessionInstance, plan: OtaSmokePlan) -> OtaSmokeP
|
|
|
1935
1963
|
"project": plan.project,
|
|
1936
1964
|
"install_mode": plan.install_mode,
|
|
1937
1965
|
"install_pin": plan.install_pin,
|
|
1966
|
+
"instances_rel": plan.instances_rel,
|
|
1938
1967
|
"peers": {
|
|
1939
1968
|
name: {
|
|
1940
1969
|
"address": peer.address,
|
|
@@ -1979,6 +2008,7 @@ def _ota_load_state(path_arg: str) -> OtaSmokePlan:
|
|
|
1979
2008
|
peers=peers,
|
|
1980
2009
|
install_mode=_ota_validate_install_mode(str(raw["install_mode"])),
|
|
1981
2010
|
install_pin=str(install_pin) if install_pin else None,
|
|
2011
|
+
instances_rel=str(raw.get("instances_rel") or "session-instances"),
|
|
1982
2012
|
)
|
|
1983
2013
|
|
|
1984
2014
|
|
|
@@ -2404,12 +2434,26 @@ def _ota_stop_parts(
|
|
|
2404
2434
|
return parts
|
|
2405
2435
|
|
|
2406
2436
|
|
|
2437
|
+
#: How a benchmark's load maps onto `publish-test-topics` flags. The keys are
|
|
2438
|
+
#: `_sized_publisher_param_args`'s own, so a load dict travels from the
|
|
2439
|
+
#: benchmark to the peer's publisher without being rewritten on the way.
|
|
2440
|
+
_OTA_LOAD_FLAGS: tuple[tuple[str, str], ...] = (
|
|
2441
|
+
("size", "--load-size"),
|
|
2442
|
+
("pattern", "--load-size-pattern"),
|
|
2443
|
+
("rate", "--load-rate-hz"),
|
|
2444
|
+
("streams", "--load-streams"),
|
|
2445
|
+
("interval_jitter_ms", "--load-interval-jitter-ms"),
|
|
2446
|
+
("interval_jitter_seed", "--load-interval-jitter-seed"),
|
|
2447
|
+
)
|
|
2448
|
+
|
|
2449
|
+
|
|
2407
2450
|
def _ota_publish_parts(
|
|
2408
2451
|
target: InteractiveSmokeTarget,
|
|
2409
2452
|
identity: str,
|
|
2410
2453
|
peer_args: list[str],
|
|
2411
2454
|
*,
|
|
2412
2455
|
stop: bool = False,
|
|
2456
|
+
load: Mapping[str, Any] | None = None,
|
|
2413
2457
|
) -> list[str]:
|
|
2414
2458
|
parts = [
|
|
2415
2459
|
"publish-test-topics",
|
|
@@ -2421,6 +2465,13 @@ def _ota_publish_parts(
|
|
|
2421
2465
|
]
|
|
2422
2466
|
if stop:
|
|
2423
2467
|
parts.append("--stop")
|
|
2468
|
+
else:
|
|
2469
|
+
merged = dict(load or {})
|
|
2470
|
+
if "size" not in merged and merged.get("size_a") is not None:
|
|
2471
|
+
merged["size"] = merged["size_a"]
|
|
2472
|
+
for key, flag in _OTA_LOAD_FLAGS:
|
|
2473
|
+
if merged.get(key) is not None:
|
|
2474
|
+
parts.extend([flag, str(merged[key])])
|
|
2424
2475
|
for override in peer_args:
|
|
2425
2476
|
parts.extend(["--peer-address", override])
|
|
2426
2477
|
return parts
|
|
@@ -2769,6 +2820,7 @@ def _resolve_ota_smoke_context(
|
|
|
2769
2820
|
project=project,
|
|
2770
2821
|
exec_commands=exec_commands,
|
|
2771
2822
|
cpusets=_parse_peer_cpuset_overrides(getattr(args, "peer_cpuset", None)),
|
|
2823
|
+
instances_rel=_ota_instances_rel(runtime),
|
|
2772
2824
|
)
|
|
2773
2825
|
plan_peers = set(plan.peers)
|
|
2774
2826
|
target_peers = set(_peer_keys_from_cfg(target.cfg))
|
|
@@ -3732,14 +3784,41 @@ def _resolve_ota_profile(
|
|
|
3732
3784
|
return name, profile
|
|
3733
3785
|
|
|
3734
3786
|
|
|
3735
|
-
def
|
|
3787
|
+
def _loaded_peer(cfg: dict[str, Any]) -> str | None:
|
|
3788
|
+
"""Which peer's egress carries this session's dominant direction.
|
|
3789
|
+
|
|
3790
|
+
A profile's ``uplink`` leg is the impaired one in almost every profile this
|
|
3791
|
+
project ships, so which peer it lands on decides what the run measures. The
|
|
3792
|
+
session already says: `topics.a_to_b` and `topics.b_to_a` are its two
|
|
3793
|
+
directions, and the one with more topics is the one the load runs over.
|
|
3794
|
+
Reading it here is what keeps a one-host and a two-host run of the *same*
|
|
3795
|
+
session under the *same* profile from shaping opposite directions -- which
|
|
3796
|
+
they did, silently, until 2026-08-31.
|
|
3797
|
+
"""
|
|
3798
|
+
topics = cfg.get("topics")
|
|
3799
|
+
if not isinstance(topics, dict):
|
|
3800
|
+
return None
|
|
3801
|
+
a_to_b = len(topics.get("a_to_b") or ())
|
|
3802
|
+
b_to_a = len(topics.get("b_to_a") or ())
|
|
3803
|
+
if a_to_b == b_to_a:
|
|
3804
|
+
return None
|
|
3805
|
+
return "a" if a_to_b > b_to_a else "b"
|
|
3806
|
+
|
|
3807
|
+
|
|
3808
|
+
def _profile_directions_for(peers: list[str], cfg: dict[str, Any]) -> dict[str, str]:
|
|
3736
3809
|
"""Map each peer to the profile direction its egress carries (RFC 0004).
|
|
3737
3810
|
|
|
3738
|
-
|
|
3739
|
-
``downlink
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3811
|
+
The sender of the session's dominant direction shapes ``uplink``; the other
|
|
3812
|
+
peer shapes ``downlink``. Where the two directions carry the same number of
|
|
3813
|
+
topics the session does not say, and the a/b convention decides: the first
|
|
3814
|
+
peer is the centre and receives, the second is the vehicle and sends.
|
|
3815
|
+
``shared.profile_directions: { a: …, b: … }`` overrides either.
|
|
3816
|
+
"""
|
|
3817
|
+
directions: dict[str, str] = {}
|
|
3818
|
+
if len(peers) == 2:
|
|
3819
|
+
sender = _loaded_peer(cfg) or peers[1]
|
|
3820
|
+
other = next(name for name in peers if name != sender)
|
|
3821
|
+
directions = {sender: "uplink", other: "downlink"}
|
|
3743
3822
|
shared = cfg.get("shared")
|
|
3744
3823
|
override = shared.get("profile_directions") if isinstance(shared, dict) else None
|
|
3745
3824
|
if isinstance(override, dict):
|
|
@@ -3751,6 +3830,11 @@ def _profile_directions(plan: OtaSmokePlan, cfg: dict[str, Any]) -> dict[str, st
|
|
|
3751
3830
|
return directions
|
|
3752
3831
|
|
|
3753
3832
|
|
|
3833
|
+
def _profile_directions(plan: OtaSmokePlan, cfg: dict[str, Any]) -> dict[str, str]:
|
|
3834
|
+
"""`_profile_directions_for` against a plan's peers."""
|
|
3835
|
+
return _profile_directions_for(sorted(plan.peers), cfg)
|
|
3836
|
+
|
|
3837
|
+
|
|
3754
3838
|
def _ota_resolve_interfaces(peer: OtaSmokePeer, peer_addr: str, *, dry_run: bool) -> tuple[str, str | None]:
|
|
3755
3839
|
"""Discover ``(OTA egress, control)`` interfaces on ``peer`` from the kernel, not
|
|
3756
3840
|
guesses: the OTA interface is the route to the other peer's data address; the
|
|
@@ -3935,6 +4019,7 @@ def _ota_start_session_publishers(
|
|
|
3935
4019
|
plan: OtaSmokePlan,
|
|
3936
4020
|
*,
|
|
3937
4021
|
dry_run: bool,
|
|
4022
|
+
load: Mapping[str, Any] | None = None,
|
|
3938
4023
|
) -> None:
|
|
3939
4024
|
if target.target_type != "session":
|
|
3940
4025
|
print("OTA smoke: target is a scenario; using its application publishers.")
|
|
@@ -3942,7 +4027,7 @@ def _ota_start_session_publishers(
|
|
|
3942
4027
|
peer_args = _ota_peer_address_args(plan)
|
|
3943
4028
|
for peer_name in sorted(plan.peers):
|
|
3944
4029
|
peer = plan.peers[peer_name]
|
|
3945
|
-
command = _ota_rosotacom_command(plan, _ota_publish_parts(target, peer_name, peer_args), peer)
|
|
4030
|
+
command = _ota_rosotacom_command(plan, _ota_publish_parts(target, peer_name, peer_args, load=load), peer)
|
|
3946
4031
|
result = _ota_run(peer, command, label=f"{peer_name}: start synthetic publishers", dry_run=dry_run, check=False)
|
|
3947
4032
|
_print_completed_output(result)
|
|
3948
4033
|
if result.returncode != 0:
|
|
@@ -4068,21 +4153,44 @@ def _ota_collect_logs(
|
|
|
4068
4153
|
dry_run: bool,
|
|
4069
4154
|
) -> None:
|
|
4070
4155
|
project = shlex.quote(plan.project)
|
|
4156
|
+
instances_rel = shlex.quote(plan.instances_rel)
|
|
4071
4157
|
instance_suffix = shlex.quote(f"*_{instance.instance_id}")
|
|
4158
|
+
collected = 0
|
|
4072
4159
|
for peer in plan.peers.values():
|
|
4073
4160
|
script = (
|
|
4074
4161
|
f"cd {shlex.quote(_ota_peer_workdir(plan, peer))} && "
|
|
4075
4162
|
f"project_dir=$(dirname {project}) && "
|
|
4076
|
-
f'
|
|
4163
|
+
f'instances_root=$(cd "$project_dir" && cd "$(dirname {instances_rel})" 2>/dev/null '
|
|
4164
|
+
f'&& printf %s "$PWD/$(basename {instances_rel})") && '
|
|
4165
|
+
f'instance_dir=$(find "$instances_root" -mindepth 2 -maxdepth 2 '
|
|
4077
4166
|
f"-type d -name {instance_suffix} -print -quit 2>/dev/null) && "
|
|
4078
4167
|
'if [ -n "$instance_dir" ]; then '
|
|
4079
|
-
'
|
|
4080
|
-
'
|
|
4168
|
+
'root=$(dirname "$(dirname "$instance_dir")"); '
|
|
4169
|
+
'relative=${instance_dir#"$root"/}; '
|
|
4170
|
+
'tar cz -C "$root" "$relative" 2>/dev/null | base64; fi'
|
|
4081
4171
|
)
|
|
4082
4172
|
result = _ota_run(peer, script, label=f"{peer.name}: collect session-instances", dry_run=dry_run, check=False)
|
|
4083
|
-
if dry_run
|
|
4173
|
+
if dry_run:
|
|
4174
|
+
continue
|
|
4175
|
+
if not result.stdout.strip():
|
|
4176
|
+
# Silence here used to end as "no status/events.jsonl files found"
|
|
4177
|
+
# after the run was already over, which describes the symptom and
|
|
4178
|
+
# not the cause. Say which peer, and where it was looked for.
|
|
4179
|
+
print(
|
|
4180
|
+
f"OTA smoke: peer {peer.name} returned no session instance matching "
|
|
4181
|
+
f"*_{instance.instance_id} under its {plan.instances_rel!r} "
|
|
4182
|
+
f"(relative to {plan.project!r}).",
|
|
4183
|
+
file=sys.stderr,
|
|
4184
|
+
)
|
|
4084
4185
|
continue
|
|
4085
4186
|
_ota_extract_peer_artifacts(instance, peer, result.stdout)
|
|
4187
|
+
collected += 1
|
|
4188
|
+
if not dry_run and not collected:
|
|
4189
|
+
print(
|
|
4190
|
+
"OTA smoke: nothing was collected from any peer -- the run produced no local records. "
|
|
4191
|
+
"Check that the project's session_instances_dir is the one the peers write to.",
|
|
4192
|
+
file=sys.stderr,
|
|
4193
|
+
)
|
|
4086
4194
|
|
|
4087
4195
|
|
|
4088
4196
|
def _ota_extract_peer_artifacts(instance: SessionInstance, peer: OtaSmokePeer, encoded: str) -> None:
|
|
@@ -7372,9 +7480,30 @@ def _smoke_topic_pub_qos_args(qos: dict[str, Any] | None) -> str:
|
|
|
7372
7480
|
return " ".join(shlex.quote(arg) for arg in args) + (" " if args else "")
|
|
7373
7481
|
|
|
7374
7482
|
|
|
7375
|
-
def _smoke_publisher_command(
|
|
7483
|
+
def _smoke_publisher_command(
|
|
7484
|
+
spec: SmokeTopicSpec,
|
|
7485
|
+
ros_setup: str,
|
|
7486
|
+
duration: float,
|
|
7487
|
+
load: Mapping[str, Any] | None = None,
|
|
7488
|
+
) -> str:
|
|
7489
|
+
"""The publisher command for one crossed topic.
|
|
7490
|
+
|
|
7491
|
+
`load` overrides what the session's own `expect` says, and only for a
|
|
7492
|
+
`SizedPayload` stream: a benchmark chooses its load, and a session that also
|
|
7493
|
+
declares one is describing what it expects to see rather than what a
|
|
7494
|
+
measurement should offer. Without this the benchmark's `--size` and
|
|
7495
|
+
`--rate-hz` reached the local runner and stopped there, so a two-host run
|
|
7496
|
+
measured the session's defaults while reporting the load that was asked for.
|
|
7497
|
+
"""
|
|
7376
7498
|
assert spec.publish_topic is not None and spec.publish_type is not None
|
|
7377
7499
|
if spec.publish_type == "com_msgs/msg/SizedPayload":
|
|
7500
|
+
from .cli_benchmark import _sized_publisher_param_args
|
|
7501
|
+
|
|
7502
|
+
if load:
|
|
7503
|
+
args = " ".join(
|
|
7504
|
+
shlex.quote(str(part)) for part in _sized_publisher_param_args(spec.publish_topic, dict(load))
|
|
7505
|
+
)
|
|
7506
|
+
return f"{ros_setup} && timeout {duration} ros2 run com_py sized_publisher --ros-args {args}"
|
|
7378
7507
|
size = spec.expected_size or SMOKE_SIZED_PAYLOAD_BYTES
|
|
7379
7508
|
return (
|
|
7380
7509
|
f"{ros_setup} && timeout {duration} ros2 run com_py sized_publisher --ros-args "
|
|
@@ -7427,16 +7556,18 @@ def _start_smoke_topic_publishers(
|
|
|
7427
7556
|
log_line: Callable[[str], None] = print,
|
|
7428
7557
|
duration: float = 180.0,
|
|
7429
7558
|
source_peer_key: str | None = None,
|
|
7559
|
+
load: Mapping[str, Any] | None = None,
|
|
7430
7560
|
) -> list[SmokeTopicSpec]:
|
|
7431
7561
|
started: list[SmokeTopicSpec] = []
|
|
7432
7562
|
for spec in _smoke_publish_specs(cfg, source_peer_key=source_peer_key):
|
|
7433
7563
|
assert spec.publish_topic is not None and spec.publish_type is not None
|
|
7434
7564
|
container = containers[spec.source_peer_key]
|
|
7435
7565
|
ros_setup = ros_setups[spec.source_peer_key]
|
|
7436
|
-
cmd = _smoke_publisher_command(spec, ros_setup, duration)
|
|
7566
|
+
cmd = _smoke_publisher_command(spec, ros_setup, duration, load)
|
|
7567
|
+
offered = f" at {load.get('rate', spec.publish_rate)} Hz (benchmark load)" if load else ""
|
|
7437
7568
|
log_line(
|
|
7438
7569
|
f"Starting smoke publisher {spec.source_peer_key}->{spec.receiver_peer_key} "
|
|
7439
|
-
f"{spec.publish_topic} ({spec.publish_type}) in {container}"
|
|
7570
|
+
f"{spec.publish_topic} ({spec.publish_type}) in {container}{offered}"
|
|
7440
7571
|
)
|
|
7441
7572
|
subprocess.run(
|
|
7442
7573
|
["docker", "exec", "-d", container, "bash", "-c", cmd],
|
|
@@ -7801,6 +7932,30 @@ def probe_content_command(args: argparse.Namespace) -> int:
|
|
|
7801
7932
|
return 0 if ok else 1
|
|
7802
7933
|
|
|
7803
7934
|
|
|
7935
|
+
def _publish_load_override(args: argparse.Namespace) -> dict[str, Any] | None:
|
|
7936
|
+
"""The benchmark's load as `_sized_publisher_param_args` wants it, or None.
|
|
7937
|
+
|
|
7938
|
+
None means "use what the session expects", which is what an ordinary smoke
|
|
7939
|
+
run wants. A benchmark always passes something, because choosing the load is
|
|
7940
|
+
the whole point of it.
|
|
7941
|
+
"""
|
|
7942
|
+
load: dict[str, Any] = {}
|
|
7943
|
+
if getattr(args, "load_size", None) is not None:
|
|
7944
|
+
load["size"] = int(args.load_size)
|
|
7945
|
+
load["size_a"] = int(args.load_size)
|
|
7946
|
+
if getattr(args, "load_size_pattern", None):
|
|
7947
|
+
load["pattern"] = args.load_size_pattern
|
|
7948
|
+
if getattr(args, "load_rate_hz", None) is not None:
|
|
7949
|
+
load["rate"] = float(args.load_rate_hz)
|
|
7950
|
+
if getattr(args, "load_streams", None) is not None:
|
|
7951
|
+
load["streams"] = int(args.load_streams)
|
|
7952
|
+
if getattr(args, "load_interval_jitter_ms", None) is not None:
|
|
7953
|
+
load["interval_jitter_ms"] = float(args.load_interval_jitter_ms)
|
|
7954
|
+
if getattr(args, "load_interval_jitter_seed", None) is not None:
|
|
7955
|
+
load["interval_jitter_seed"] = int(args.load_interval_jitter_seed)
|
|
7956
|
+
return load or None
|
|
7957
|
+
|
|
7958
|
+
|
|
7804
7959
|
def publish_test_topics_command(args: argparse.Namespace) -> int:
|
|
7805
7960
|
"""Start or stop synthetic local app publishers for the peer's crossed topics.
|
|
7806
7961
|
|
|
@@ -7826,6 +7981,7 @@ def publish_test_topics_command(args: argparse.Namespace) -> int:
|
|
|
7826
7981
|
cfg,
|
|
7827
7982
|
duration=args.duration,
|
|
7828
7983
|
source_peer_key=args.identity,
|
|
7984
|
+
load=_publish_load_override(args),
|
|
7829
7985
|
)
|
|
7830
7986
|
except RuntimeError as exc:
|
|
7831
7987
|
print(f"ERROR: {exc}", file=sys.stderr)
|
|
@@ -10357,6 +10513,16 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
10357
10513
|
publish_test_topics_parser.add_argument(
|
|
10358
10514
|
"--stop", action="store_true", help="Stop running synthetic test topic publishers."
|
|
10359
10515
|
)
|
|
10516
|
+
# The benchmark's load, for the peer that publishes it. Without these a
|
|
10517
|
+
# two-host benchmark offered the session's own expected load and reported
|
|
10518
|
+
# the one that was asked for -- a run that reads as a success and measures
|
|
10519
|
+
# something else.
|
|
10520
|
+
publish_test_topics_parser.add_argument("--load-size", type=int, help=argparse.SUPPRESS)
|
|
10521
|
+
publish_test_topics_parser.add_argument("--load-size-pattern", help=argparse.SUPPRESS)
|
|
10522
|
+
publish_test_topics_parser.add_argument("--load-rate-hz", type=float, help=argparse.SUPPRESS)
|
|
10523
|
+
publish_test_topics_parser.add_argument("--load-streams", type=int, help=argparse.SUPPRESS)
|
|
10524
|
+
publish_test_topics_parser.add_argument("--load-interval-jitter-ms", type=float, help=argparse.SUPPRESS)
|
|
10525
|
+
publish_test_topics_parser.add_argument("--load-interval-jitter-seed", type=int, help=argparse.SUPPRESS)
|
|
10360
10526
|
publish_test_topics_parser.set_defaults(func=publish_test_topics_command)
|
|
10361
10527
|
|
|
10362
10528
|
list_parser = subparsers.add_parser("list-sessions", help="List configured sessions.")
|
|
@@ -5163,6 +5163,7 @@ def _make_live_run_point(args: argparse.Namespace, session_name: str) -> RunPoin
|
|
|
5163
5163
|
_peer_command_runner,
|
|
5164
5164
|
_peer_watchdog_launcher,
|
|
5165
5165
|
_profile_directions,
|
|
5166
|
+
_profile_directions_for,
|
|
5166
5167
|
_remove_smoke_network,
|
|
5167
5168
|
_resolve_ota_profile,
|
|
5168
5169
|
_resolve_ota_smoke_context,
|
|
@@ -5327,7 +5328,10 @@ def _make_live_run_point(args: argparse.Namespace, session_name: str) -> RunPoin
|
|
|
5327
5328
|
_ota_start_peers(target, plan, instance.instance_id, dry_run=dry_run)
|
|
5328
5329
|
if not dry_run:
|
|
5329
5330
|
time.sleep(12)
|
|
5330
|
-
|
|
5331
|
+
# The load is the benchmark's, not the session's expectation:
|
|
5332
|
+
# without this the peer published what its own `expect` declares
|
|
5333
|
+
# and the run reported the load that was asked for.
|
|
5334
|
+
_ota_start_session_publishers(target, plan, dry_run=dry_run, load=load)
|
|
5331
5335
|
|
|
5332
5336
|
if not dry_run:
|
|
5333
5337
|
if profile_obj is not None and profile_obj.is_timeline:
|
|
@@ -5651,34 +5655,36 @@ def _make_live_run_point(args: argparse.Namespace, session_name: str) -> RunPoin
|
|
|
5651
5655
|
print(
|
|
5652
5656
|
f" netem distribution {table_name!r} installed in {dist_container}: {dist_target}"
|
|
5653
5657
|
)
|
|
5658
|
+
# Which peer's egress carries `uplink` is the session's
|
|
5659
|
+
# answer, not the runner's: the same session under the same
|
|
5660
|
+
# profile must be shaped identically here and across two
|
|
5661
|
+
# machines, and hard-coding a=uplink here while the OTA path
|
|
5662
|
+
# hard-coded b=uplink meant it was not.
|
|
5663
|
+
lab_directions = _profile_directions_for(["a", "b"], cfg)
|
|
5664
|
+
lab_containers = {"a": a_container, "b": b_container}
|
|
5654
5665
|
if profile_obj.is_timeline:
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
# Peer B shapes downlink (egress to A)
|
|
5662
|
-
shaper_b = ProfileShaper("eth0", make_container_runner(b_container))
|
|
5663
|
-
lab_shapers.append(shaper_b)
|
|
5664
|
-
steps_b = expand_timeline(profile_obj, "eth0", direction="downlink")
|
|
5665
|
-
lab_peer_steps["b"] = (shaper_b, steps_b)
|
|
5666
|
+
for peer_name in ("a", "b"):
|
|
5667
|
+
shaper = ProfileShaper("eth0", make_container_runner(lab_containers[peer_name]))
|
|
5668
|
+
lab_shapers.append(shaper)
|
|
5669
|
+
steps = expand_timeline(profile_obj, "eth0", direction=lab_directions[peer_name])
|
|
5670
|
+
lab_peer_steps[peer_name] = (shaper, steps)
|
|
5666
5671
|
|
|
5667
5672
|
for shaper in lab_shapers:
|
|
5668
5673
|
shaper.arm([])
|
|
5669
5674
|
else:
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
shaper_b.arm(shaping_commands("eth0", profile_obj.downlink))
|
|
5675
|
+
for peer_name in ("a", "b"):
|
|
5676
|
+
leg = profile_obj.uplink if lab_directions[peer_name] == "uplink" else profile_obj.downlink
|
|
5677
|
+
if leg is None or leg.is_empty:
|
|
5678
|
+
continue
|
|
5679
|
+
shaper = ProfileShaper("eth0", make_container_runner(lab_containers[peer_name]))
|
|
5680
|
+
lab_shapers.append(shaper)
|
|
5681
|
+
shaper.arm(shaping_commands("eth0", leg))
|
|
5678
5682
|
|
|
5679
5683
|
# 4. Verify shaping was applied (diagnostic)
|
|
5680
5684
|
if profile_obj is not None and not getattr(args, "dry_run", False):
|
|
5681
|
-
for
|
|
5685
|
+
for peer_name in ("a", "b"):
|
|
5686
|
+
label = f"{peer_name.upper()} ({lab_directions[peer_name]})"
|
|
5687
|
+
container = lab_containers[peer_name]
|
|
5682
5688
|
tc_binary = container_tc_overrides.get(container, "tc")
|
|
5683
5689
|
res = subprocess.run(
|
|
5684
5690
|
["docker", "exec", "-u", "root", container, tc_binary, "qdisc", "show", "dev", "eth0"],
|
{rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom/resources/examples/profiles.yaml
RENAMED
|
@@ -245,3 +245,74 @@ profiles:
|
|
|
245
245
|
distribution_file: dist/field-20260817.dist
|
|
246
246
|
loss: 1%
|
|
247
247
|
downlink: { delay: 7ms, jitter: 5ms }
|
|
248
|
+
|
|
249
|
+
# B1-prime -- the two-state process with its chain rescaled per cell.
|
|
250
|
+
#
|
|
251
|
+
# netem advances a Gilbert-Elliott chain once per *packet*, so the fitted p
|
|
252
|
+
# and r describe a process in packets and not in time. At the drive's own
|
|
253
|
+
# 380 fragments/s they mean a bad run of about 105 ms; on a size ladder at a
|
|
254
|
+
# fixed 10 Hz the packet rate is N x 10, so the same p and r stretch the bad
|
|
255
|
+
# run by 380/(N x 10) and every cell meets a different link. Forcing the
|
|
256
|
+
# packet rate constant instead was tried and measured the wrong thing: the
|
|
257
|
+
# pipeline serves messages, not packets, and at 60 messages/s the depth-1 OTA
|
|
258
|
+
# queue overwrites its own backlog -- both loss processes then reported
|
|
259
|
+
# 10.7 % to two digits.
|
|
260
|
+
#
|
|
261
|
+
# So the chain is rescaled instead: p and r are multiplied by 380/(N x 10) in
|
|
262
|
+
# each cell, which leaves the stationary bad fraction at 3.92 % and the mean
|
|
263
|
+
# loss at 1 % while making the bad run 105 ms of wall clock everywhere. The
|
|
264
|
+
# comparison against `tilt-iid` is then a comparison of one thing.
|
|
265
|
+
|
|
266
|
+
bp-frag-one:
|
|
267
|
+
uplink:
|
|
268
|
+
delay: 25ms
|
|
269
|
+
jitter: 18ms
|
|
270
|
+
distribution: field-20260817
|
|
271
|
+
distribution_file: dist/field-20260817.dist
|
|
272
|
+
loss_gemodel: { p: 3.876%, r: 95%, loss_bad: 13.5%, loss_good: 0.49% }
|
|
273
|
+
downlink: { delay: 7ms, jitter: 5ms }
|
|
274
|
+
|
|
275
|
+
bp-frag-two:
|
|
276
|
+
uplink:
|
|
277
|
+
delay: 25ms
|
|
278
|
+
jitter: 18ms
|
|
279
|
+
distribution: field-20260817
|
|
280
|
+
distribution_file: dist/field-20260817.dist
|
|
281
|
+
loss_gemodel: { p: 1.938%, r: 47.5%, loss_bad: 13.5%, loss_good: 0.49% }
|
|
282
|
+
downlink: { delay: 7ms, jitter: 5ms }
|
|
283
|
+
|
|
284
|
+
bp-frag-four:
|
|
285
|
+
uplink:
|
|
286
|
+
delay: 25ms
|
|
287
|
+
jitter: 18ms
|
|
288
|
+
distribution: field-20260817
|
|
289
|
+
distribution_file: dist/field-20260817.dist
|
|
290
|
+
loss_gemodel: { p: 0.969%, r: 23.75%, loss_bad: 13.5%, loss_good: 0.49% }
|
|
291
|
+
downlink: { delay: 7ms, jitter: 5ms }
|
|
292
|
+
|
|
293
|
+
bp-frag-six:
|
|
294
|
+
uplink:
|
|
295
|
+
delay: 25ms
|
|
296
|
+
jitter: 18ms
|
|
297
|
+
distribution: field-20260817
|
|
298
|
+
distribution_file: dist/field-20260817.dist
|
|
299
|
+
loss_gemodel: { p: 0.646%, r: 15.83%, loss_bad: 13.5%, loss_good: 0.49% }
|
|
300
|
+
downlink: { delay: 7ms, jitter: 5ms }
|
|
301
|
+
|
|
302
|
+
bp-frag-twelve:
|
|
303
|
+
uplink:
|
|
304
|
+
delay: 25ms
|
|
305
|
+
jitter: 18ms
|
|
306
|
+
distribution: field-20260817
|
|
307
|
+
distribution_file: dist/field-20260817.dist
|
|
308
|
+
loss_gemodel: { p: 0.323%, r: 7.917%, loss_bad: 13.5%, loss_good: 0.49% }
|
|
309
|
+
downlink: { delay: 7ms, jitter: 5ms }
|
|
310
|
+
|
|
311
|
+
bp-frag-thirtyeight:
|
|
312
|
+
uplink:
|
|
313
|
+
delay: 25ms
|
|
314
|
+
jitter: 18ms
|
|
315
|
+
distribution: field-20260817
|
|
316
|
+
distribution_file: dist/field-20260817.dist
|
|
317
|
+
loss_gemodel: { p: 0.102%, r: 2.5%, loss_bad: 13.5%, loss_good: 0.49% }
|
|
318
|
+
downlink: { delay: 7ms, jitter: 5ms }
|
|
@@ -373,6 +373,7 @@ tests/unit/test_netem_dist.py
|
|
|
373
373
|
tests/unit/test_network_preflight.py
|
|
374
374
|
tests/unit/test_network_profiles.py
|
|
375
375
|
tests/unit/test_network_shaper.py
|
|
376
|
+
tests/unit/test_ota_benchmark_peer_exec.py
|
|
376
377
|
tests/unit/test_ota_link_configs.py
|
|
377
378
|
tests/unit/test_ota_pcap.py
|
|
378
379
|
tests/unit/test_ota_unwrapper.py
|
{rosotacom_dev-2.5.dev76 → rosotacom_dev-2.5.dev78}/src/rosotacom_dev.egg-info/scm_file_list.json
RENAMED
|
@@ -368,6 +368,7 @@
|
|
|
368
368
|
"tests/unit/test_network_preflight.py",
|
|
369
369
|
"tests/unit/test_network_profiles.py",
|
|
370
370
|
"tests/unit/test_network_shaper.py",
|
|
371
|
+
"tests/unit/test_ota_benchmark_peer_exec.py",
|
|
371
372
|
"tests/unit/test_ota_link_configs.py",
|
|
372
373
|
"tests/unit/test_ota_pcap.py",
|
|
373
374
|
"tests/unit/test_ota_unwrapper.py",
|