From 3faac69cea87346805106d4c40de8afe51bf351d Mon Sep 17 00:00:00 2001 From: Christopher Canel Date: Mon, 25 Nov 2024 03:20:49 +0000 Subject: [PATCH] Trunk format --- .devcontainer/devcontainer.json | 76 +-- .github/workflows/ossar.yml | 49 +- .travis.yml | 16 +- .trunk/.gitignore | 9 + .trunk/configs/.clang-tidy | 39 ++ .trunk/configs/.flake8 | 3 + .trunk/configs/.hadolint.yaml | 4 + .trunk/configs/.isort.cfg | 2 + .trunk/configs/.markdownlint.yaml | 2 + .trunk/configs/.remarkrc.yaml | 4 + .trunk/configs/.shellcheckrc | 7 + .trunk/configs/.vale.ini | 5 + .trunk/configs/.yamllint.yaml | 7 + .trunk/configs/cspell.yaml | 4 + .trunk/configs/ruff.toml | 5 + .trunk/trunk.yaml | 74 +++ .vscode/launch.json | 422 +++++++------ .vscode/settings.json | 14 +- README.md | 1 + linux/install_linux.sh | 46 +- ratemon/model/check_mathis_accuracy.py | 51 +- ratemon/model/cl_args.py | 285 ++++++--- ratemon/model/correlation.py | 582 +++++++++--------- ratemon/model/data.py | 2 +- ratemon/model/defaults.py | 3 +- ratemon/model/fet_hists.py | 22 +- ratemon/model/gen_features.py | 10 +- ratemon/model/gen_training_data.py | 78 ++- ratemon/model/graph_one.py | 54 +- ratemon/model/hyper.py | 182 +++--- ratemon/model/models.py | 12 +- ratemon/model/parse_validation_exps.sh | 50 +- ratemon/model/prepare_data.py | 5 +- ratemon/model/sim.py | 49 +- ratemon/model/test.py | 9 +- ratemon/model/test_all.py | 9 +- ratemon/model/test_data/scale_params.json | 112 +++- ratemon/model/tests.py | 90 ++- ratemon/model/train.py | 26 +- ratemon/model/training_param_sweep.py | 224 ++++--- ratemon/model/utils.py | 14 +- ratemon/model/validate_sim.py | 74 ++- .../c/experimental/client_server/client.c | 12 +- .../c/experimental/client_server/common.h | 1 + .../client_server/libinterptest.c | 4 +- .../client_server/libinterptest_cpp.cpp | 4 +- .../c/experimental/client_server/server.c | 15 +- .../runtime/c/experimental/ratemon_test.bpf.c | 78 +-- ratemon/runtime/c/experimental/ratemon_test.c | 24 +- ratemon/runtime/c/experimental/ratemon_test.h | 1 + ratemon/runtime/c/libratemon_interp.cpp | 74 +-- ratemon/runtime/c/ratemon.h | 5 +- ratemon/runtime/c/ratemon_kprobe.bpf.c | 5 +- ratemon/runtime/c/ratemon_main.c | 28 +- ratemon/runtime/c/ratemon_maps.h | 4 +- ratemon/runtime/c/ratemon_sockops.bpf.c | 12 +- ratemon/runtime/python/ebpf.py | 29 +- ratemon/runtime/python/pacing_notes.py | 6 +- ratemon/runtime/python/policies.py | 4 +- ratemon/runtime/python/ratemon_runtime.c | 94 +-- ratemon/runtime/python/ratemon_runtime.py | 9 +- ratemon/runtime/python/reaction_strategy.py | 2 +- ratemon/scripts/eval.py | 2 +- ratemon/scripts/graph_all_ccas.py | 4 +- ratemon/scripts/max_leaf_nodes.py | 2 +- .../scripts/prepare_data_all_generalized.sh | 36 +- ratemon/scripts/skb_len.py | 2 +- ratemon/scripts/train.sh | 130 ++-- ratemon/scripts/train_composite.sh | 42 +- ratemon/scripts/train_max_leaf_nodes.sh | 38 +- ratemon/scripts/train_old.sh | 38 +- 71 files changed, 1938 insertions(+), 1499 deletions(-) create mode 100644 .trunk/.gitignore create mode 100644 .trunk/configs/.clang-tidy create mode 100644 .trunk/configs/.flake8 create mode 100644 .trunk/configs/.hadolint.yaml create mode 100644 .trunk/configs/.isort.cfg create mode 100644 .trunk/configs/.markdownlint.yaml create mode 100644 .trunk/configs/.remarkrc.yaml create mode 100644 .trunk/configs/.shellcheckrc create mode 100644 .trunk/configs/.vale.ini create mode 100644 .trunk/configs/.yamllint.yaml create mode 100644 .trunk/configs/cspell.yaml create mode 100644 .trunk/configs/ruff.toml create mode 100644 .trunk/trunk.yaml diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 9128b905..12fb3ce8 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,41 +1,41 @@ // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: // https://github.com/microsoft/vscode-dev-containers/tree/v0.224.2/containers/docker-existing-dockerfile { - "name": "ratemon", - "image": "ccanel/ratemon:latest", - // Sets the run context to one level up instead of the .devcontainer folder. - "context": "..", - // Update the 'dockerFile' property if you aren't using the standard 'Dockerfile' filename. - // "dockerFile": "../Dockerfile", - // Set *default* container specific settings.json values on container create. - "settings": {}, - // Add the IDs of extensions you want installed when the container is created. - "extensions": [ - "ms-python.python", - "ms-python.vscode-pylance", - "eamodio.gitlens", - "GrapeCity.gc-excelviewer", - "austin.code-gnu-global", - "ms-vscode.cpptools-themes", - "ms-vscode.cpptools", - "jeff-hykin.better-cpp-syntax", - "shakram02.bash-beautify", - "timonwong.shellcheck", - "foxundermoon.shell-format", - "gitkraken.gitkraken-authentication" - ], - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], - // Uncomment the next line to run commands after the container is created - for example installing curl. - // "postCreateCommand": "apt-get update && apt-get install -y curl", - // Uncomment when using a ptrace-based debugger like C++, Go, and Rust - // "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" ], - // Uncomment to use the Docker CLI from inside the container. See https://aka.ms/vscode-remote/samples/docker-from-docker. - // "mounts": [ "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind" ], - // Uncomment to connect as a non-root user if you've added one. See https://aka.ms/vscode-remote/containers/non-root. - // "remoteUser": "vscode" - "mounts": [ - "source=/home/ccanel/out,target=/out,type=bind", - "source=/usr/src/linux-headers-4.15.0-169,target=/usr/src/4.15.0-169-generic,type=bind" - ] -} \ No newline at end of file + "name": "ratemon", + "image": "ccanel/ratemon:latest", + // Sets the run context to one level up instead of the .devcontainer folder. + "context": "..", + // Update the 'dockerFile' property if you aren't using the standard 'Dockerfile' filename. + // "dockerFile": "../Dockerfile", + // Set *default* container specific settings.json values on container create. + "settings": {}, + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "ms-python.python", + "ms-python.vscode-pylance", + "eamodio.gitlens", + "GrapeCity.gc-excelviewer", + "austin.code-gnu-global", + "ms-vscode.cpptools-themes", + "ms-vscode.cpptools", + "jeff-hykin.better-cpp-syntax", + "shakram02.bash-beautify", + "timonwong.shellcheck", + "foxundermoon.shell-format", + "gitkraken.gitkraken-authentication" + ], + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + // Uncomment the next line to run commands after the container is created - for example installing curl. + // "postCreateCommand": "apt-get update && apt-get install -y curl", + // Uncomment when using a ptrace-based debugger like C++, Go, and Rust + // "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" ], + // Uncomment to use the Docker CLI from inside the container. See https://aka.ms/vscode-remote/samples/docker-from-docker. + // "mounts": [ "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind" ], + // Uncomment to connect as a non-root user if you've added one. See https://aka.ms/vscode-remote/containers/non-root. + // "remoteUser": "vscode" + "mounts": [ + "source=/home/ccanel/out,target=/out,type=bind", + "source=/usr/src/linux-headers-4.15.0-169,target=/usr/src/4.15.0-169-generic,type=bind" + ] +} diff --git a/.github/workflows/ossar.yml b/.github/workflows/ossar.yml index 0a031cc4..99bf5d6b 100644 --- a/.github/workflows/ossar.yml +++ b/.github/workflows/ossar.yml @@ -10,12 +10,12 @@ name: OSSAR on: push: - branches: [ "main", "*" ] + branches: ["main", "*"] pull_request: # The branches below must be a subset of the branches above - branches: [ "main" ] + branches: ["main"] schedule: - - cron: '15 2 * * 5' + - cron: "15 2 * * 5" permissions: contents: read @@ -31,26 +31,25 @@ jobs: runs-on: windows-latest steps: - - name: Checkout repository - uses: actions/checkout@v3 - - # Ensure a compatible version of dotnet is installed. - # The [Microsoft Security Code Analysis CLI](https://aka.ms/mscadocs) is built with dotnet v3.1.201. - # A version greater than or equal to v3.1.201 of dotnet must be installed on the agent in order to run this action. - # GitHub hosted runners already have a compatible version of dotnet installed and this step may be skipped. - # For self-hosted runners, ensure dotnet version 3.1.201 or later is installed by including this action: - # - name: Install .NET - # uses: actions/setup-dotnet@v2 - # with: - # dotnet-version: '3.1.x' - + - name: Checkout repository + uses: actions/checkout@v3 + + # Ensure a compatible version of dotnet is installed. + # The [Microsoft Security Code Analysis CLI](https://aka.ms/mscadocs) is built with dotnet v3.1.201. + # A version greater than or equal to v3.1.201 of dotnet must be installed on the agent in order to run this action. + # GitHub hosted runners already have a compatible version of dotnet installed and this step may be skipped. + # For self-hosted runners, ensure dotnet version 3.1.201 or later is installed by including this action: + # - name: Install .NET + # uses: actions/setup-dotnet@v2 + # with: + # dotnet-version: '3.1.x' # Run open source static analysis tools - - name: Run OSSAR - uses: github/ossar-action@v1 - id: ossar - - # Upload results to the Security tab - - name: Upload OSSAR results - uses: github/codeql-action/upload-sarif@v2 - with: - sarif_file: ${{ steps.ossar.outputs.sarifFile }} + - name: Run OSSAR + uses: github/ossar-action@v1 + id: ossar + + # Upload results to the Security tab + - name: Upload OSSAR results + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: ${{ steps.ossar.outputs.sarifFile }} diff --git a/.travis.yml b/.travis.yml index 56b5ad6a..33d86e66 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: python python: - - "3.6" + - "3.6" # Cache pip dependencies. cache: pip @@ -10,18 +10,18 @@ cache: pip # Handle git submodules manually. # Based on: https://github.com/algolia/examples/issues/24 git: - submodules: false + submodules: false # Use sed to replace the SSH URL with the public URL, then initialize submodules # manually. before_install: - - sed -i "s/git@github.com:/https:\/\/github.com\//" .gitmodules - - git submodule update --init --recursive + - sed -i "s/git@github.com:/https:\/\/github.com\//" .gitmodules + - git submodule update --init --recursive # Install dependencies. install: - - sudo apt-get update - - sudo apt-get install -y tshark - - pip install -r model/requirements.txt + - sudo apt-get update + - sudo apt-get install -y tshark + - pip install -r model/requirements.txt # Run tests. script: - - python -m unittest model/tests.py + - python -m unittest model/tests.py diff --git a/.trunk/.gitignore b/.trunk/.gitignore new file mode 100644 index 00000000..15966d08 --- /dev/null +++ b/.trunk/.gitignore @@ -0,0 +1,9 @@ +*out +*logs +*actions +*notifications +*tools +plugins +user_trunk.yaml +user.yaml +tmp diff --git a/.trunk/configs/.clang-tidy b/.trunk/configs/.clang-tidy new file mode 100644 index 00000000..e4bd819f --- /dev/null +++ b/.trunk/configs/.clang-tidy @@ -0,0 +1,39 @@ +Checks: >- + bugprone-*, + cppcoreguidelines-*, + google-*, + misc-*, + modernize-*, + performance-*, + readability-*, + -bugprone-lambda-function-name, + -bugprone-reserved-identifier, + -cppcoreguidelines-avoid-goto, + -cppcoreguidelines-avoid-magic-numbers, + -cppcoreguidelines-avoid-non-const-global-variables, + -cppcoreguidelines-pro-bounds-array-to-pointer-decay, + -cppcoreguidelines-pro-type-vararg, + -google-readability-braces-around-statements, + -google-readability-function-size, + -misc-no-recursion, + -modernize-return-braced-init-list, + -modernize-use-nodiscard, + -modernize-use-trailing-return-type, + -performance-unnecessary-value-param, + -readability-magic-numbers, + +CheckOptions: + - key: readability-function-cognitive-complexity.Threshold + value: 100 + - key: readability-function-cognitive-complexity.IgnoreMacros + value: true + # Set naming conventions for your style below (there are dozens of naming settings possible): + # See https://clang.llvm.org/extra/clang-tidy/checks/readability/identifier-naming.html + # - key: readability-identifier-naming.ClassCase + # value: CamelCase + # - key: readability-identifier-naming.NamespaceCase + # value: lower_case + # - key: readability-identifier-naming.PrivateMemberSuffix + # value: _ + # - key: readability-identifier-naming.StructCase + # value: CamelCase diff --git a/.trunk/configs/.flake8 b/.trunk/configs/.flake8 new file mode 100644 index 00000000..5ba6e2ff --- /dev/null +++ b/.trunk/configs/.flake8 @@ -0,0 +1,3 @@ +# Autoformatter friendly flake8 config (all formatting rules disabled) +[flake8] +extend-ignore = D1, D2, E1, E2, E3, E501, W1, W2, W3, W5 diff --git a/.trunk/configs/.hadolint.yaml b/.trunk/configs/.hadolint.yaml new file mode 100644 index 00000000..98bf0cd2 --- /dev/null +++ b/.trunk/configs/.hadolint.yaml @@ -0,0 +1,4 @@ +# Following source doesn't work in most setups +ignored: + - SC1090 + - SC1091 diff --git a/.trunk/configs/.isort.cfg b/.trunk/configs/.isort.cfg new file mode 100644 index 00000000..b9fb3f3e --- /dev/null +++ b/.trunk/configs/.isort.cfg @@ -0,0 +1,2 @@ +[settings] +profile=black diff --git a/.trunk/configs/.markdownlint.yaml b/.trunk/configs/.markdownlint.yaml new file mode 100644 index 00000000..b40ee9d7 --- /dev/null +++ b/.trunk/configs/.markdownlint.yaml @@ -0,0 +1,2 @@ +# Prettier friendly markdownlint config (all formatting rules disabled) +extends: markdownlint/style/prettier diff --git a/.trunk/configs/.remarkrc.yaml b/.trunk/configs/.remarkrc.yaml new file mode 100644 index 00000000..501b6877 --- /dev/null +++ b/.trunk/configs/.remarkrc.yaml @@ -0,0 +1,4 @@ +plugins: + remark-preset-lint-consistent: true + remark-preset-lint-recommended: true + remark-lint-list-item-indent: true diff --git a/.trunk/configs/.shellcheckrc b/.trunk/configs/.shellcheckrc new file mode 100644 index 00000000..8c7b1ada --- /dev/null +++ b/.trunk/configs/.shellcheckrc @@ -0,0 +1,7 @@ +enable=all +source-path=SCRIPTDIR +disable=SC2154 + +# If you're having issues with shellcheck following source, disable the errors via: +# disable=SC1090 +# disable=SC1091 diff --git a/.trunk/configs/.vale.ini b/.trunk/configs/.vale.ini new file mode 100644 index 00000000..ee11cf24 --- /dev/null +++ b/.trunk/configs/.vale.ini @@ -0,0 +1,5 @@ +[formats] +markdoc = md + +[*.md] +BasedOnStyles = Vale diff --git a/.trunk/configs/.yamllint.yaml b/.trunk/configs/.yamllint.yaml new file mode 100644 index 00000000..184e251f --- /dev/null +++ b/.trunk/configs/.yamllint.yaml @@ -0,0 +1,7 @@ +rules: + quoted-strings: + required: only-when-needed + extra-allowed: ["{|}"] + key-duplicates: {} + octal-values: + forbid-implicit-octal: true diff --git a/.trunk/configs/cspell.yaml b/.trunk/configs/cspell.yaml new file mode 100644 index 00000000..7f995845 --- /dev/null +++ b/.trunk/configs/cspell.yaml @@ -0,0 +1,4 @@ +version: "0.2" +# Suggestions can sometimes take longer on CI machines, +# leading to inconsistent results. +suggestionsTimeout: 5000 # ms diff --git a/.trunk/configs/ruff.toml b/.trunk/configs/ruff.toml new file mode 100644 index 00000000..f5a235cf --- /dev/null +++ b/.trunk/configs/ruff.toml @@ -0,0 +1,5 @@ +# Generic, formatter-friendly config. +select = ["B", "D3", "E", "F"] + +# Never enforce `E501` (line length violations). This should be handled by formatters. +ignore = ["E501"] diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml new file mode 100644 index 00000000..2844f7e0 --- /dev/null +++ b/.trunk/trunk.yaml @@ -0,0 +1,74 @@ +# This file controls the behavior of Trunk: https://docs.trunk.io/cli +# To learn more about the format of this file, see https://docs.trunk.io/reference/trunk-yaml +version: 0.1 +cli: + version: 1.22.8 +# Trunk provides extensibility via plugins. (https://docs.trunk.io/plugins) +plugins: + sources: + - id: trunk + ref: v1.6.5 + uri: https://github.com/trunk-io/plugins +# Many linters and tools depend on runtimes - configure them here. (https://docs.trunk.io/runtimes) +runtimes: + enabled: + - go@1.21.0 + - node@18.12.1 + - python@3.10.8 +# This is the section where you manage your linters. (https://docs.trunk.io/check/configuration) +lint: + disabled: + - markdown-table-prettify + - remark-lint + - markdownlint-cli2 + - biome + - deno + - autopep8 + - flake8 + - mypy + - pylint + - pyright + - sourcery + - yapf + - cspell + enabled: + - clang-format@16.0.3 + - clang-tidy@16.0.3 + - codespell@2.3.0 + - dustilock@1.2.0 + - gitleaks@8.21.2 + - include-what-you-use@0.20 + - kube-linter@0.6.4 + - markdown-link-check@3.13.6 + - pragma-once + - pre-commit-hooks@5.0.0 + - ruff@0.7.3 + - semgrep@1.96.0 + - taplo@0.9.3 + - terrascan@1.19.1 + - trivy@0.56.2 + - trufflehog-git@3.83.7 + - trunk-toolbox@0.5.3 + - vale@3.9.0 + - actionlint@1.7.4 + - bandit@1.7.10 + - black@24.10.0 + - checkov@3.2.296 + - git-diff-check + - hadolint@2.12.1-beta + - isort@5.13.2 + - markdownlint@0.42.0 + - osv-scanner@1.9.1 + - prettier@3.3.3 + - ruff@0.7.3 + - shellcheck@0.10.0 + - shfmt@3.6.0 + - trufflehog@3.83.7 + - yamllint@1.35.1 +actions: + disabled: + - trunk-announce + - trunk-check-pre-push + - trunk-fmt-pre-commit + enabled: + - trunk-upgrade-available diff --git a/.vscode/launch.json b/.vscode/launch.json index 5ecfeefc..222cfc37 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,213 +1,211 @@ { - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "(d) runtime", - "type": "debugpy", - "request": "launch", - "program": "${workspaceFolder}/ratemon/runtime/python/ratemon_runtime.py", - "console": "integratedTerminal", - "args": [ - "-h" - ], - "autoReload": { - "enable": false - }, - "redirectOutput": true, - "env": { - "PYTHONPATH": "${workspaceFolder}" - }, - "sudo": true - }, - { - "name": "(r) runtime", - "type": "debugpy", - "request": "launch", - "program": "${workspaceFolder}/ratemon/runtime/python/ratemon_runtime.py", - "console": "integratedTerminal", - "args": [ - "--model=HistGbdtSklearn", - "--model-file=${workspaceFolder}/test/models/model.pickle", - "--interface=eno1", - "--reaction-strategy=mimd", - "--cgroup=${workspaceFolder}/test/test_cgroup", - "--check-interval-ms=100", - "--batch-size=10", - "--log=/tmp/ratemon.log", - "--skip-localhost", - "--listen-ports=9999", - "--debug", - "--smoothing-window=10", - ], - "autoReload": { - "enable": false - }, - "redirectOutput": true, - "env": { - "PYTHONPATH": "${workspaceFolder}" - }, - "sudo": true - }, - { - "name": "(r) runtime, schedule", - "type": "debugpy", - "request": "launch", - "program": "${workspaceFolder}/ratemon/runtime/python/ratemon_runtime.py", - "console": "integratedTerminal", - "args": [ - "--model=HistGbdtSklearn", - "--model-file=${workspaceFolder}/test/HistGbdtSklearn_fewer_features.pickle", - "--interface=ens3", - "--reaction-strategy=file", - "--schedule=${workspaceFolder}/test/ratemon_schedule_step.csv", - "--cgroup=${workspaceFolder}/test/test_cgroup", - "--check-interval-ms=1000", - "--log=/tmp/ratemon.log", - ], - "autoReload": { - "enable": false - }, - "redirectOutput": true, - "env": { - "PYTHONPATH": "${workspaceFolder}" - }, - "sudo": true - }, - { - "name": "(r) runtime, cprofile", - "type": "debugpy", - "request": "launch", - "module": "cProfile", - "console": "integratedTerminal", - "args": [ - "-o", - "/tmp/tmp.prof", - "${workspaceFolder}/ratemon/runtime/python/ratemon_runtime.py", - "--model=HistGbdtSklearn", - "--model-file=${workspaceFolder}/test/HistGbdtSklearn_fewer_features.pickle", - "--interface=ens3", - "--reaction-strategy=aimd", - "--cgroup=${workspaceFolder}/test/test_cgroup", - "--check-interval-ms=1000", - "--log=/tmp/ratemon.log", - // "--skip-localhost", - "--constrain-port", - "--debug", - ], - "autoReload": { - "enable": false - }, - "redirectOutput": true, - "env": { - "PYTHONPATH": "${workspaceFolder}" - }, - "sudo": true - }, - { - "name": "(r) train cubic bbr", - "type": "debugpy", - "request": "launch", - "program": "${workspaceFolder}/ratemon/model/train.py", - "console": "integratedTerminal", - "args": [ - "--no-rand", - "--tag=debugging", - "--data-dir=/home/ccanel/fawnstore2/out/cloudlab/2022-08-26/cubic-bbr/prepared/", - "--out-dir=/tmp/2022-08-26/cubic-bbr/full_models", - "--model=HistGbdtSklearn", - "--balance", - "--sample-percent=1", - "--max-iter=10", - "--max-leaf-nodes=10000", - "--max-depth=100", - "--min-samples-leaf=10", - "--early-stop", - "--analyze-features", - "--feature-selection-type=perm", - "--feature-selection-percent=1", - "--clusters=10", - "--num-features-to-pick=50", - "--permutation-importance-repeats=1" - ], - "autoReload": { - "enable": false - }, - "redirectOutput": true, - "env": { - "PYTHONPATH": "${workspaceFolder}" - } - }, - { - "name": "(r) prepare_data", - "type": "debugpy", - "request": "launch", - "program": "${workspaceFolder}/ratemon/model/prepare_data.py", - "console": "integratedTerminal", - "args": [ - "--data-dir=/home/ccanel/fawnstore2/out/cloudlab/2021-5-12/cubic-bbr", - "--train-split=60", - "--val-split=10", - "--test-split=30", - "--warmup-percent=5", - "--out-dir=/home/ccanel/out/foobar", - "--sample-percent=1", - "--disjoint-splits", - "--num-exps=10" - ], - "autoReload": { - "enable": false - }, - "redirectOutput": true, - "env": { - "PYTHONPATH": "${workspaceFolder}" - } - }, - { - "name": "(r) gen_features", - "type": "debugpy", - "request": "launch", - "program": "${workspaceFolder}/ratemon/model/gen_features.py", - "console": "integratedTerminal", - "args": [ - "--exp-dir=/home/ccanel/fawnstore2/out/cloudlab/2022-06-10/cubic-bbr/experiments", - "--untar-dir=/tmp/untar", - "--out-dir=/home/ccanel/fawnstore2/out/cloudlab/2022-06-10/cubic-bbr/features", - "--parallel=38", - "--random-order", - // "--num-exps=400", - "--select-tail-percent=20" - ], - "autoReload": { - "enable": false - }, - "redirectOutput": true, - "env": { - "PYTHONPATH": "${workspaceFolder}" - } - }, - { - "name": "(r) eval", - "type": "debugpy", - "request": "launch", - "program": "${workspaceFolder}/ratemon/scripts/eval.py", - "console": "integratedTerminal", - "args": [ - "--exp-dir=/home/ccanel/out/cloudlab/2022-4-21/", - "--untar-dir=/tmp/untar", - "--parallel=40", - "--out-dir=/home/ccanel/out/cloudlab/2022-4-21/out/" - ], - "autoReload": { - "enable": false - }, - "redirectOutput": true, - "env": { - "PYTHONPATH": "${workspaceFolder}" - }, - "sudo": false - }, - ] -} \ No newline at end of file + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "(d) runtime", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/ratemon/runtime/python/ratemon_runtime.py", + "console": "integratedTerminal", + "args": ["-h"], + "autoReload": { + "enable": false + }, + "redirectOutput": true, + "env": { + "PYTHONPATH": "${workspaceFolder}" + }, + "sudo": true + }, + { + "name": "(r) runtime", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/ratemon/runtime/python/ratemon_runtime.py", + "console": "integratedTerminal", + "args": [ + "--model=HistGbdtSklearn", + "--model-file=${workspaceFolder}/test/models/model.pickle", + "--interface=eno1", + "--reaction-strategy=mimd", + "--cgroup=${workspaceFolder}/test/test_cgroup", + "--check-interval-ms=100", + "--batch-size=10", + "--log=/tmp/ratemon.log", + "--skip-localhost", + "--listen-ports=9999", + "--debug", + "--smoothing-window=10" + ], + "autoReload": { + "enable": false + }, + "redirectOutput": true, + "env": { + "PYTHONPATH": "${workspaceFolder}" + }, + "sudo": true + }, + { + "name": "(r) runtime, schedule", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/ratemon/runtime/python/ratemon_runtime.py", + "console": "integratedTerminal", + "args": [ + "--model=HistGbdtSklearn", + "--model-file=${workspaceFolder}/test/HistGbdtSklearn_fewer_features.pickle", + "--interface=ens3", + "--reaction-strategy=file", + "--schedule=${workspaceFolder}/test/ratemon_schedule_step.csv", + "--cgroup=${workspaceFolder}/test/test_cgroup", + "--check-interval-ms=1000", + "--log=/tmp/ratemon.log" + ], + "autoReload": { + "enable": false + }, + "redirectOutput": true, + "env": { + "PYTHONPATH": "${workspaceFolder}" + }, + "sudo": true + }, + { + "name": "(r) runtime, cprofile", + "type": "debugpy", + "request": "launch", + "module": "cProfile", + "console": "integratedTerminal", + "args": [ + "-o", + "/tmp/tmp.prof", + "${workspaceFolder}/ratemon/runtime/python/ratemon_runtime.py", + "--model=HistGbdtSklearn", + "--model-file=${workspaceFolder}/test/HistGbdtSklearn_fewer_features.pickle", + "--interface=ens3", + "--reaction-strategy=aimd", + "--cgroup=${workspaceFolder}/test/test_cgroup", + "--check-interval-ms=1000", + "--log=/tmp/ratemon.log", + // "--skip-localhost", + "--constrain-port", + "--debug" + ], + "autoReload": { + "enable": false + }, + "redirectOutput": true, + "env": { + "PYTHONPATH": "${workspaceFolder}" + }, + "sudo": true + }, + { + "name": "(r) train cubic bbr", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/ratemon/model/train.py", + "console": "integratedTerminal", + "args": [ + "--no-rand", + "--tag=debugging", + "--data-dir=/home/ccanel/fawnstore2/out/cloudlab/2022-08-26/cubic-bbr/prepared/", + "--out-dir=/tmp/2022-08-26/cubic-bbr/full_models", + "--model=HistGbdtSklearn", + "--balance", + "--sample-percent=1", + "--max-iter=10", + "--max-leaf-nodes=10000", + "--max-depth=100", + "--min-samples-leaf=10", + "--early-stop", + "--analyze-features", + "--feature-selection-type=perm", + "--feature-selection-percent=1", + "--clusters=10", + "--num-features-to-pick=50", + "--permutation-importance-repeats=1" + ], + "autoReload": { + "enable": false + }, + "redirectOutput": true, + "env": { + "PYTHONPATH": "${workspaceFolder}" + } + }, + { + "name": "(r) prepare_data", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/ratemon/model/prepare_data.py", + "console": "integratedTerminal", + "args": [ + "--data-dir=/home/ccanel/fawnstore2/out/cloudlab/2021-5-12/cubic-bbr", + "--train-split=60", + "--val-split=10", + "--test-split=30", + "--warmup-percent=5", + "--out-dir=/home/ccanel/out/foobar", + "--sample-percent=1", + "--disjoint-splits", + "--num-exps=10" + ], + "autoReload": { + "enable": false + }, + "redirectOutput": true, + "env": { + "PYTHONPATH": "${workspaceFolder}" + } + }, + { + "name": "(r) gen_features", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/ratemon/model/gen_features.py", + "console": "integratedTerminal", + "args": [ + "--exp-dir=/home/ccanel/fawnstore2/out/cloudlab/2022-06-10/cubic-bbr/experiments", + "--untar-dir=/tmp/untar", + "--out-dir=/home/ccanel/fawnstore2/out/cloudlab/2022-06-10/cubic-bbr/features", + "--parallel=38", + "--random-order", + // "--num-exps=400", + "--select-tail-percent=20" + ], + "autoReload": { + "enable": false + }, + "redirectOutput": true, + "env": { + "PYTHONPATH": "${workspaceFolder}" + } + }, + { + "name": "(r) eval", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/ratemon/scripts/eval.py", + "console": "integratedTerminal", + "args": [ + "--exp-dir=/home/ccanel/out/cloudlab/2022-4-21/", + "--untar-dir=/tmp/untar", + "--parallel=40", + "--out-dir=/home/ccanel/out/cloudlab/2022-4-21/out/" + ], + "autoReload": { + "enable": false + }, + "redirectOutput": true, + "env": { + "PYTHONPATH": "${workspaceFolder}" + }, + "sudo": false + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 08426424..5403cf31 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,10 +1,8 @@ { - "python.analysis.extraPaths": [ - "./model" - ], - "cmake.configureOnOpen": false, - "files.associations": { - "types.h": "c" - }, - "python.analysis.typeCheckingMode": "basic" + "python.analysis.extraPaths": ["./model"], + "cmake.configureOnOpen": false, + "files.associations": { + "types.h": "c" + }, + "python.analysis.typeCheckingMode": "basic" } diff --git a/README.md b/README.md index 8d5c8e03..57cdea3c 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ # RateMon + Receiver-side mechanisms for rate control of TCP flows. diff --git a/linux/install_linux.sh b/linux/install_linux.sh index c31a69b2..37797227 100755 --- a/linux/install_linux.sh +++ b/linux/install_linux.sh @@ -2,38 +2,38 @@ set -eoux pipefail -if [ "$#" -ne 1 ] && [ "$#" -ne 2 ]; then - echo "ERROR: Illegal number of parameters." - echo "Usage: ./install_linux.sh
" - exit 255 +if [[ $# -ne 1 ]] && [[ $# -ne 2 ]]; then + echo "ERROR: Illegal number of parameters." + echo "Usage: ./install_linux.sh
" + exit 255 fi main_dir="$1" version="5.15.156" -if [ -n "$2" ]; then - version="$2" +if [[ -n $2 ]]; then + version="$2" fi sudo apt-get update DEBIAN_FRONTEND="noninteractive" sudo apt-get -y --no-install-recommends install \ - git \ - fakeroot \ - build-essential \ - ncurses-dev \ - xz-utils \ - libssl-dev \ - bc \ - flex \ - libelf-dev \ - bison \ - pahole + git \ + fakeroot \ + build-essential \ + ncurses-dev \ + xz-utils \ + libssl-dev \ + bc \ + flex \ + libelf-dev \ + bison \ + pahole # Download Linux 5.15.156 and apply get_info() patch. Do not build it yet. -pushd "$main_dir" -wget "https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-$version.tar.gz" -tar xf "linux-$version.tar.gz" -rm -f "linux-$version.tar.gz" -pushd "linux-$version" -git apply "$main_dir/ratemon/linux/get_info.patch" +pushd "${main_dir}" +wget "https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-${version}.tar.gz" +tar xf "linux-${version}.tar.gz" +rm -f "linux-${version}.tar.gz" +pushd "linux-${version}" +git apply "${main_dir}/ratemon/linux/get_info.patch" cp -fv "/boot/config-$(uname -r)" .config scripts/config --disable SYSTEM_TRUSTED_KEYS scripts/config --disable SYSTEM_REVOCATION_KEYS diff --git a/ratemon/model/check_mathis_accuracy.py b/ratemon/model/check_mathis_accuracy.py index 46e88a8a..4bb19dc8 100755 --- a/ratemon/model/check_mathis_accuracy.py +++ b/ratemon/model/check_mathis_accuracy.py @@ -10,12 +10,11 @@ from os import path import numpy as np - import utils def process_one(flp): - """ Process a single simulation. """ + """Process a single simulation.""" dat = np.load(flp) dat = dat[dat.files[0]] labels = dat["mathis model label"] @@ -23,29 +22,43 @@ def process_one(flp): exp = utils.Exp(flp) return ( ( - (labels[valid] == - # To determine the ground truth, compare the actual queue - # occupancy to the fair queue occupancy (convert to ints to - # generate class labels). - (dat["queue occupancy ewma-alpha0.5"][valid] > ( - 1 / exp.tot_flws)).astype(int) - # Count the number of correct predictions by converting - # from bools to ints and summing them up. - ).astype(int).sum()), + ( + labels[valid] + == + # To determine the ground truth, compare the actual queue + # occupancy to the fair queue occupancy (convert to ints to + # generate class labels). + ( + dat["queue occupancy ewma-alpha0.5"][valid] > (1 / exp.tot_flws) + ).astype(int) + # Count the number of correct predictions by converting + # from bools to ints and summing them up. + ) + .astype(int) + .sum() + ), len(valid[0]), - dat.shape[0]) + dat.shape[0], + ) def main(): - """ This program's entrypoint. """ + """This program's entrypoint.""" # Parse command line arguments. psr = argparse.ArgumentParser( - ("Checks the accuracy of the Mathis Model in predicting a flow's " - "fairness. Uses the output of parse_dumbbell.py.")) + ( + "Checks the accuracy of the Mathis Model in predicting a flow's " + "fairness. Uses the output of parse_dumbbell.py." + ) + ) psr.add_argument( "--exp-dir", - help=("The directory in which the experiment results are stored " - "(required)."), required=True, type=str) + help=( + "The directory in which the experiment results are stored " "(required)." + ), + required=True, + type=str, + ) args = psr.parse_args() exp_dir = args.exp_dir sims = [path.join(exp_dir, sim) for sim in os.listdir(exp_dir)] @@ -61,9 +74,7 @@ def main(): print(f"Mathis Model accuracy: {(correct / total) * 100:.2f}%") print(f"Total: {total} packets") print(f"Discarded {total_all - total} packets.") - print( - "Accuracy without discarding packets: " - f"{(correct / total_all) * 100:.2f}%") + print("Accuracy without discarding packets: " f"{(correct / total_all) * 100:.2f}%") if __name__ == "__main__": diff --git a/ratemon/model/cl_args.py b/ratemon/model/cl_args.py index 350355b8..fef85adc 100644 --- a/ratemon/model/cl_args.py +++ b/ratemon/model/cl_args.py @@ -11,6 +11,7 @@ def add_out(psr, psr_verify=lambda args: args): Returns the provided parser, as well as a lambda to verify existing arguments. """ + def verify(args): out_dir = args.out_dir if not path.exists(out_dir): @@ -18,8 +19,11 @@ def verify(args): return args psr.add_argument( - "--out-dir", default=".", - help="The directory in which to store output files.", type=str) + "--out-dir", + default=".", + help="The directory in which to store output files.", + type=str, + ) return psr, lambda args: verify(psr_verify(args)) @@ -28,18 +32,22 @@ def add_warmup(psr, psr_verify=lambda args: args): Returns the provided parser, as well as a lambda to verify existing arguments. """ + def verify(args): warmup_prc = args.warmup_percent - assert 0 <= warmup_prc < 100, \ - ("\"warmup-percent\" must be in the range [0, 100), but is: " - f"{warmup_prc}") + assert 0 <= warmup_prc < 100, ( + '"warmup-percent" must be in the range [0, 100), but is: ' f"{warmup_prc}" + ) return args psr.add_argument( - "--warmup-percent", default=defaults.DEFAULTS["warmup_percent"], - help=("The percent of each experiment's datapoint to drop from the " - "beginning."), - type=float) + "--warmup-percent", + default=defaults.DEFAULTS["warmup_percent"], + help=( + "The percent of each experiment's datapoint to drop from the " "beginning." + ), + type=float, + ) return psr, lambda args: verify(psr_verify(args)) @@ -48,15 +56,21 @@ def add_num_exps(psr, psr_verify=lambda args: args): Returns the provided parser, as well as a lambda to verify existing arguments. """ + def verify(args): num_exps = args.num_exps - assert num_exps is None or num_exps >= 0, \ - f"\"num-exps\" cannot be negative, but is: {num_exps}" + assert ( + num_exps is None or num_exps >= 0 + ), f'"num-exps" cannot be negative, but is: {num_exps}' return args psr.add_argument( - "--num-exps", default=defaults.DEFAULTS["num_exps"], - help="The number of experiments to consider.", required=False, type=int) + "--num-exps", + default=defaults.DEFAULTS["num_exps"], + help="The number of experiments to consider.", + required=False, + type=int, + ) return psr, lambda args: verify(psr_verify(args)) @@ -66,9 +80,13 @@ def add_standardize(psr, psr_verify=lambda args: args): Returns the provided parser, as well as a lambda to verify existing arguments. """ psr.add_argument( - "--standardize", action="store_true", - help=("Standardize the data so that it has a mean of 0 and a variance " - "of 1. Otherwise, data will be rescaled to the range [0, 1].")) + "--standardize", + action="store_true", + help=( + "Standardize the data so that it has a mean of 0 and a variance " + "of 1. Otherwise, data will be rescaled to the range [0, 1]." + ), + ) # "standardize" does not require verification. return psr, psr_verify @@ -78,16 +96,20 @@ def add_sample_percent(psr, psr_verify=lambda args: args): Returns the provided parser, as well as a lambda to verify existing arguments. """ + def verify(args): sample_prc = args.sample_percent - assert 0 < sample_prc <= 100, \ - ("\"sample-percent\" must be in the range (0, 100], but is: " - f"{sample_prc}") + assert 0 < sample_prc <= 100, ( + '"sample-percent" must be in the range (0, 100], but is: ' f"{sample_prc}" + ) return args psr.add_argument( - "--sample-percent", default=defaults.DEFAULTS["sample_percent"], - required=False, type=float) + "--sample-percent", + default=defaults.DEFAULTS["sample_percent"], + required=False, + type=float, + ) return psr, lambda args: verify(psr_verify(args)) @@ -96,107 +118,169 @@ def add_training(psr, psr_verify=lambda args: args): Returns the provided parser, as well as a lambda to verify existing arguments. """ + def verify(args): if args.early_stop: args.epochs = defaults.EPCS_MAX degree = args.degree - assert degree >= 0, \ - ("\"degree\" must be an integer greater than or equal to 0, but " - f"is: {degree}") + assert degree >= 0, ( + '"degree" must be an integer greater than or equal to 0, but ' + f"is: {degree}" + ) max_iter = args.max_iter - assert max_iter > 0, \ - f"\"max-iter\" must be greater than 0, but is: {max_iter}" + assert max_iter > 0, f'"max-iter" must be greater than 0, but is: {max_iter}' folds = args.folds - assert folds >= 2, f"\"folds\" must be at least 2, but is: {folds}" + assert folds >= 2, f'"folds" must be at least 2, but is: {folds}' return args - psr, psr_verify = add_sample_percent( - *add_out(*add_standardize(psr, psr_verify))) + psr, psr_verify = add_sample_percent(*add_out(*add_standardize(psr, psr_verify))) psr.add_argument( "--data-dir", - help=("The path to a directory containing the " - "training/validation/testing data (required)."), - required=True, type=str) - psr.add_argument( - "--no-rand", action="store_true", help="Use a fixed random seed.") + help=( + "The path to a directory containing the " + "training/validation/testing data (required)." + ), + required=True, + type=str, + ) + psr.add_argument("--no-rand", action="store_true", help="Use a fixed random seed.") psr.add_argument( - "--model", choices=models.MODEL_NAMES, - default=defaults.DEFAULTS["model"], help="The model to use.", type=str) + "--model", + choices=models.MODEL_NAMES, + default=defaults.DEFAULTS["model"], + help="The model to use.", + type=str, + ) psr.add_argument( - "--epochs", default=defaults.DEFAULTS["epochs"], - help="The number of epochs to train for.", type=int) + "--epochs", + default=defaults.DEFAULTS["epochs"], + help="The number of epochs to train for.", + type=int, + ) psr.add_argument( - "--num-gpus", default=defaults.DEFAULTS["num_gpus"], - help="The number of GPUs to use.", type=int) + "--num-gpus", + default=defaults.DEFAULTS["num_gpus"], + help="The number of GPUs to use.", + type=int, + ) psr.add_argument( - "--train-batch", default=defaults.DEFAULTS["train_batch"], - help="The batch size to use during training.", type=int) + "--train-batch", + default=defaults.DEFAULTS["train_batch"], + help="The batch size to use during training.", + type=int, + ) psr.add_argument( - "--test-batch", default=defaults.DEFAULTS["test_batch"], - help="The batch size to use during validation and testing.", type=int) + "--test-batch", + default=defaults.DEFAULTS["test_batch"], + help="The batch size to use during validation and testing.", + type=int, + ) psr.add_argument( - "--lr", default=defaults.DEFAULTS["lr"], - help="Learning rate for SGD training.", type=float) + "--lr", + default=defaults.DEFAULTS["lr"], + help="Learning rate for SGD training.", + type=float, + ) psr.add_argument( - "--momentum", default=defaults.DEFAULTS["momentum"], - help="Momentum for SGD training.", type=float) + "--momentum", + default=defaults.DEFAULTS["momentum"], + help="Momentum for SGD training.", + type=float, + ) psr.add_argument( - "--kernel", default=defaults.DEFAULTS["kernel"], + "--kernel", + default=defaults.DEFAULTS["kernel"], choices=["linear", "poly", "rbf", "sigmoid"], - help=(f"If the model is of type \"{models.SvmSklearnWrapper().name}\", " - "then use this type kernel. Ignored otherwise."), - type=str) - psr.add_argument( - "--degree", default=defaults.DEFAULTS["degree"], - help=(f"If the model is of type \"{models.SvmSklearnWrapper().name}\" " - "and \"--kernel=poly\", then this is the degree of the " - "polynomial that will be fit. Ignored otherwise."), - type=int) - psr.add_argument( - "--penalty", default=defaults.DEFAULTS["penalty"], choices=["l1", "l2"], - help=(f"If the model is of type \"{models.SvmSklearnWrapper().name}\", " - "then use this type of regularization. Ignored otherwise.")) - psr.add_argument( - "--max-iter", default=defaults.DEFAULTS["max_iter"], - help=("If the model is an sklearn model, then this is the maximum " - "number of iterations to use during the fitting process. Ignored " - "otherwise."), - type=int) - psr.add_argument( - "--rfe", choices=["None", "rfe", "rfecv"], default="None", - help=(f"If the model is of type \"{models.LrSklearnWrapper().name}\" " - f"or \"{models.LrCvSklearnWrapper().name}\", then this is the " - "type of recursive feature elimination to use. Ignored " - "otherwise."), - type=str) - psr.add_argument( - "--folds", default=defaults.DEFAULTS["folds"], - help=(f"If the model is of type \"{models.LrCvSklearnWrapper().name}\"," - " then use this number of cross-validation folds."), - type=int) - psr.add_argument( - "--early-stop", action="store_true", help="Enable early stopping.") - psr.add_argument( - "--val-patience", default=defaults.DEFAULTS["val_patience"], - help=("The number of times that the validation loss can increase " - "before training is automatically aborted."), - type=int) + help=( + f'If the model is of type "{models.SvmSklearnWrapper().name}", ' + "then use this type kernel. Ignored otherwise." + ), + type=str, + ) + psr.add_argument( + "--degree", + default=defaults.DEFAULTS["degree"], + help=( + f'If the model is of type "{models.SvmSklearnWrapper().name}" ' + 'and "--kernel=poly", then this is the degree of the ' + "polynomial that will be fit. Ignored otherwise." + ), + type=int, + ) + psr.add_argument( + "--penalty", + default=defaults.DEFAULTS["penalty"], + choices=["l1", "l2"], + help=( + f'If the model is of type "{models.SvmSklearnWrapper().name}", ' + "then use this type of regularization. Ignored otherwise." + ), + ) + psr.add_argument( + "--max-iter", + default=defaults.DEFAULTS["max_iter"], + help=( + "If the model is an sklearn model, then this is the maximum " + "number of iterations to use during the fitting process. Ignored " + "otherwise." + ), + type=int, + ) + psr.add_argument( + "--rfe", + choices=["None", "rfe", "rfecv"], + default="None", + help=( + f'If the model is of type "{models.LrSklearnWrapper().name}" ' + f'or "{models.LrCvSklearnWrapper().name}", then this is the ' + "type of recursive feature elimination to use. Ignored " + "otherwise." + ), + type=str, + ) + psr.add_argument( + "--folds", + default=defaults.DEFAULTS["folds"], + help=( + f'If the model is of type "{models.LrCvSklearnWrapper().name}",' + " then use this number of cross-validation folds." + ), + type=int, + ) + psr.add_argument("--early-stop", action="store_true", help="Enable early stopping.") + psr.add_argument( + "--val-patience", + default=defaults.DEFAULTS["val_patience"], + help=( + "The number of times that the validation loss can increase " + "before training is automatically aborted." + ), + type=int, + ) psr.add_argument( "--val-improvement-thresh", default=defaults.DEFAULTS["val_improvement_thresh"], help="Threshold for percept improvement in validation loss.", - type=float) + type=float, + ) psr.add_argument( - "--conf-trials", default=defaults.DEFAULTS["conf_trials"], - help="The number of trials to run.", type=int) + "--conf-trials", + default=defaults.DEFAULTS["conf_trials"], + help="The number of trials to run.", + type=int, + ) psr.add_argument( - "--max-attempts", default=defaults.DEFAULTS["max_attempts"], + "--max-attempts", + default=defaults.DEFAULTS["max_attempts"], help="The maximum number of failed training attempts to survive.", - type=int) + type=int, + ) psr.add_argument( - "--timeout-s", default=defaults.DEFAULTS["timeout_s"], + "--timeout-s", + default=defaults.DEFAULTS["timeout_s"], help="Automatically stop training after this amount of time (seconds).", - type=float) + type=float, + ) return psr, lambda args: verify(psr_verify(args)) @@ -205,14 +289,19 @@ def add_running(psr, psr_verify=lambda args: args): Returns the provided parser, as well as a lambda to verify existing arguments. """ + def verify(args): scl_prms_flp = args.scale_params - assert path.exists(scl_prms_flp), \ - f"Scale parameters file does not exist: {scl_prms_flp}" + assert path.exists( + scl_prms_flp + ), f"Scale parameters file does not exist: {scl_prms_flp}" return args psr, psr_verify = add_out(*add_standardize(*add_warmup(psr, psr_verify))) psr.add_argument( - "--scale-params", help="The path to the input scaling parameters.", - required=True, type=str) + "--scale-params", + help="The path to the input scaling parameters.", + required=True, + type=str, + ) return psr, lambda args: verify(psr_verify(args)) diff --git a/ratemon/model/correlation.py b/ratemon/model/correlation.py index 8cafc8c5..6602fa94 100755 --- a/ratemon/model/correlation.py +++ b/ratemon/model/correlation.py @@ -4,281 +4,290 @@ import argparse import multiprocessing import os -from os import path import random import shutil - -from matplotlib import pyplot as plt -import numpy as np -import seaborn as sns +from os import path import cl_args import defaults -import models +import numpy as np +import seaborn as sns import train import utils +from matplotlib import pyplot as plt # Features to analyze. -ALL_FETS = sorted([ - # "1/sqrt loss event rate-windowed-minRtt1", - # "1/sqrt loss event rate-windowed-minRtt1024", - # "1/sqrt loss event rate-windowed-minRtt128", - # "1/sqrt loss event rate-windowed-minRtt16", - # "1/sqrt loss event rate-windowed-minRtt2", - # "1/sqrt loss event rate-windowed-minRtt256", - # "1/sqrt loss event rate-windowed-minRtt32", - # "1/sqrt loss event rate-windowed-minRtt4", - # "1/sqrt loss event rate-windowed-minRtt512", - # "1/sqrt loss event rate-windowed-minRtt64", - # "1/sqrt loss event rate-windowed-minRtt8", - # "RTT estimate ratio-ewma-alpha0.001", - # "RTT estimate ratio-ewma-alpha0.002", - # "RTT estimate ratio-ewma-alpha0.003", - # "RTT estimate ratio-ewma-alpha0.004", - # "RTT estimate ratio-ewma-alpha0.005", - # "RTT estimate ratio-ewma-alpha0.006", - # "RTT estimate ratio-ewma-alpha0.007", - # "RTT estimate ratio-ewma-alpha0.008", - # "RTT estimate ratio-ewma-alpha0.009", - # "RTT estimate ratio-ewma-alpha0.01", - # "RTT estimate ratio-ewma-alpha0.1", - # "RTT estimate ratio-ewma-alpha0.2", - # "RTT estimate ratio-ewma-alpha0.3", - # "RTT estimate ratio-ewma-alpha0.4", - "RTT estimate ratio-ewma-alpha0.5", - # "RTT estimate ratio-ewma-alpha0.6", - # "RTT estimate ratio-ewma-alpha0.7", - # "RTT estimate ratio-ewma-alpha0.8", - # "RTT estimate ratio-ewma-alpha0.9", - # "RTT estimate ratio-ewma-alpha1.0", - # "RTT estimate us-ewma-alpha0.001", - # "RTT estimate us-ewma-alpha0.002", - # "RTT estimate us-ewma-alpha0.003", - # "RTT estimate us-ewma-alpha0.004", - # "RTT estimate us-ewma-alpha0.005", - # "RTT estimate us-ewma-alpha0.006", - # "RTT estimate us-ewma-alpha0.007", - # "RTT estimate us-ewma-alpha0.008", - # "RTT estimate us-ewma-alpha0.009", - # "RTT estimate us-ewma-alpha0.01", - # "RTT estimate us-ewma-alpha0.1", - # "RTT estimate us-ewma-alpha0.2", - # "RTT estimate us-ewma-alpha0.3", - # "RTT estimate us-ewma-alpha0.4", - "RTT estimate us-ewma-alpha0.5", - # "RTT estimate us-ewma-alpha0.6", - # "RTT estimate us-ewma-alpha0.7", - # "RTT estimate us-ewma-alpha0.8", - # "RTT estimate us-ewma-alpha0.9", - # "RTT estimate us-ewma-alpha1.0", - # "arrival time us", - # "average RTT estimate ratio-windowed-minRtt1", - # "average RTT estimate ratio-windowed-minRtt1024", - # "average RTT estimate ratio-windowed-minRtt128", - # "average RTT estimate ratio-windowed-minRtt16", - # "average RTT estimate ratio-windowed-minRtt2", - # "average RTT estimate ratio-windowed-minRtt256", - # "average RTT estimate ratio-windowed-minRtt32", - # "average RTT estimate ratio-windowed-minRtt4", - # "average RTT estimate ratio-windowed-minRtt512", - # "average RTT estimate ratio-windowed-minRtt64", - # "average RTT estimate ratio-windowed-minRtt8", - # "average RTT estimate us-windowed-minRtt1", - # "average RTT estimate us-windowed-minRtt1024", - # "average RTT estimate us-windowed-minRtt128", - # "average RTT estimate us-windowed-minRtt16", - # "average RTT estimate us-windowed-minRtt2", - # "average RTT estimate us-windowed-minRtt256", - # "average RTT estimate us-windowed-minRtt32", - # "average RTT estimate us-windowed-minRtt4", - # "average RTT estimate us-windowed-minRtt512", - # "average RTT estimate us-windowed-minRtt64", - # "average RTT estimate us-windowed-minRtt8", - # "average interarrival time us-windowed-minRtt1", - # "average interarrival time us-windowed-minRtt1024", - # "average interarrival time us-windowed-minRtt128", - # "average interarrival time us-windowed-minRtt16", - # "average interarrival time us-windowed-minRtt2", - # "average interarrival time us-windowed-minRtt256", - # "average interarrival time us-windowed-minRtt32", - # "average interarrival time us-windowed-minRtt4", - # "average interarrival time us-windowed-minRtt512", - # "average interarrival time us-windowed-minRtt64", - # "average interarrival time us-windowed-minRtt8", - # "average throughput p/s-windowed-minRtt1", - # "average throughput p/s-windowed-minRtt1024", - # "average throughput p/s-windowed-minRtt128", - # "average throughput p/s-windowed-minRtt16", - # "average throughput p/s-windowed-minRtt2", - # "average throughput p/s-windowed-minRtt256", - # "average throughput p/s-windowed-minRtt32", - # "average throughput p/s-windowed-minRtt4", - # "average throughput p/s-windowed-minRtt512", - # "average throughput p/s-windowed-minRtt64", - # "average throughput p/s-windowed-minRtt8", - # "interarrival time us-ewma-alpha0.001", - # "interarrival time us-ewma-alpha0.002", - # "interarrival time us-ewma-alpha0.003", - # "interarrival time us-ewma-alpha0.004", - # "interarrival time us-ewma-alpha0.005", - # "interarrival time us-ewma-alpha0.006", - # "interarrival time us-ewma-alpha0.007", - # "interarrival time us-ewma-alpha0.008", - # "interarrival time us-ewma-alpha0.009", - # "interarrival time us-ewma-alpha0.01", - # "interarrival time us-ewma-alpha0.1", - # "interarrival time us-ewma-alpha0.2", - # "interarrival time us-ewma-alpha0.3", - # "interarrival time us-ewma-alpha0.4", - "interarrival time us-ewma-alpha0.5", - # "interarrival time us-ewma-alpha0.6", - # "interarrival time us-ewma-alpha0.7", - # "interarrival time us-ewma-alpha0.8", - # "interarrival time us-ewma-alpha0.9", - # "interarrival time us-ewma-alpha1.0", - # "loss event rate-windowed-minRtt1", - # "loss event rate-windowed-minRtt1024", - # "loss event rate-windowed-minRtt128", - # "loss event rate-windowed-minRtt16", - # "loss event rate-windowed-minRtt2", - # "loss event rate-windowed-minRtt256", - # "loss event rate-windowed-minRtt32", - # "loss event rate-windowed-minRtt4", - # "loss event rate-windowed-minRtt512", - # "loss event rate-windowed-minRtt64", - # "loss event rate-windowed-minRtt8", - # "loss rate estimate-ewma-alpha0.001", - # "loss rate estimate-ewma-alpha0.002", - # "loss rate estimate-ewma-alpha0.003", - # "loss rate estimate-ewma-alpha0.004", - # "loss rate estimate-ewma-alpha0.005", - # "loss rate estimate-ewma-alpha0.006", - # "loss rate estimate-ewma-alpha0.007", - # "loss rate estimate-ewma-alpha0.008", - # "loss rate estimate-ewma-alpha0.009", - # "loss rate estimate-ewma-alpha0.01", - # "loss rate estimate-ewma-alpha0.1", - # "loss rate estimate-ewma-alpha0.2", - # "loss rate estimate-ewma-alpha0.3", - # "loss rate estimate-ewma-alpha0.4", - "loss rate estimate-ewma-alpha0.5", - # "loss rate estimate-ewma-alpha0.6", - # "loss rate estimate-ewma-alpha0.7", - # "loss rate estimate-ewma-alpha0.8", - # "loss rate estimate-ewma-alpha0.9", - # "loss rate estimate-ewma-alpha1.0", - # "loss rate estimate-windowed-minRtt1", - # "loss rate estimate-windowed-minRtt1024", - # "loss rate estimate-windowed-minRtt128", - # "loss rate estimate-windowed-minRtt16", - # "loss rate estimate-windowed-minRtt2", - # "loss rate estimate-windowed-minRtt256", - # "loss rate estimate-windowed-minRtt32", - # "loss rate estimate-windowed-minRtt4", - # "loss rate estimate-windowed-minRtt512", - # "loss rate estimate-windowed-minRtt64", - # "loss rate estimate-windowed-minRtt8", - # "mathis model label-ewma-alpha0.001", - # "mathis model label-ewma-alpha0.002", - # "mathis model label-ewma-alpha0.003", - # "mathis model label-ewma-alpha0.004", - # "mathis model label-ewma-alpha0.005", - # "mathis model label-ewma-alpha0.006", - # "mathis model label-ewma-alpha0.007", - # "mathis model label-ewma-alpha0.008", - # "mathis model label-ewma-alpha0.009", - # "mathis model label-ewma-alpha0.01", - # "mathis model label-ewma-alpha0.1", - # "mathis model label-ewma-alpha0.2", - # "mathis model label-ewma-alpha0.3", - # "mathis model label-ewma-alpha0.4", - "mathis model label-ewma-alpha0.5", - # "mathis model label-ewma-alpha0.6", - # "mathis model label-ewma-alpha0.7", - # "mathis model label-ewma-alpha0.8", - # "mathis model label-ewma-alpha0.9", - # "mathis model label-ewma-alpha1.0", - # "mathis model label-windowed-minRtt1", - # "mathis model label-windowed-minRtt1024", - # "mathis model label-windowed-minRtt128", - # "mathis model label-windowed-minRtt16", - # "mathis model label-windowed-minRtt2", - # "mathis model label-windowed-minRtt256", - # "mathis model label-windowed-minRtt32", - # "mathis model label-windowed-minRtt4", - # "mathis model label-windowed-minRtt512", - # "mathis model label-windowed-minRtt64", - # "mathis model label-windowed-minRtt8", - # "mathis model throughput p/s-ewma-alpha0.001", - # "mathis model throughput p/s-ewma-alpha0.002", - # "mathis model throughput p/s-ewma-alpha0.003", - # "mathis model throughput p/s-ewma-alpha0.004", - # "mathis model throughput p/s-ewma-alpha0.005", - # "mathis model throughput p/s-ewma-alpha0.006", - # "mathis model throughput p/s-ewma-alpha0.007", - # "mathis model throughput p/s-ewma-alpha0.008", - # "mathis model throughput p/s-ewma-alpha0.009", - # "mathis model throughput p/s-ewma-alpha0.01", - # "mathis model throughput p/s-ewma-alpha0.1", - # "mathis model throughput p/s-ewma-alpha0.2", - # "mathis model throughput p/s-ewma-alpha0.3", - # "mathis model throughput p/s-ewma-alpha0.4", - "mathis model throughput p/s-ewma-alpha0.5", - # "mathis model throughput p/s-ewma-alpha0.6", - # "mathis model throughput p/s-ewma-alpha0.7", - # "mathis model throughput p/s-ewma-alpha0.8", - # "mathis model throughput p/s-ewma-alpha0.9", - # "mathis model throughput p/s-ewma-alpha1.0", - # "mathis model throughput p/s-windowed-minRtt1", - # "mathis model throughput p/s-windowed-minRtt1024", - # "mathis model throughput p/s-windowed-minRtt128", - # "mathis model throughput p/s-windowed-minRtt16", - # "mathis model throughput p/s-windowed-minRtt2", - # "mathis model throughput p/s-windowed-minRtt256", - # "mathis model throughput p/s-windowed-minRtt32", - # "mathis model throughput p/s-windowed-minRtt4", - # "mathis model throughput p/s-windowed-minRtt512", - # "mathis model throughput p/s-windowed-minRtt64", - # "mathis model throughput p/s-windowed-minRtt8", - "min RTT us", - # "seq", - # "throughput p/s-ewma-alpha0.001", - # "throughput p/s-ewma-alpha0.002", - # "throughput p/s-ewma-alpha0.003", - # "throughput p/s-ewma-alpha0.004", - # "throughput p/s-ewma-alpha0.005", - # "throughput p/s-ewma-alpha0.006", - # "throughput p/s-ewma-alpha0.007", - # "throughput p/s-ewma-alpha0.008", - # "throughput p/s-ewma-alpha0.009", - # "throughput p/s-ewma-alpha0.01", - # "throughput p/s-ewma-alpha0.1", - # "throughput p/s-ewma-alpha0.2", - # "throughput p/s-ewma-alpha0.3", - # "throughput p/s-ewma-alpha0.4", - "throughput p/s-ewma-alpha0.5", - # "throughput p/s-ewma-alpha0.6", - # "throughput p/s-ewma-alpha0.7", - # "throughput p/s-ewma-alpha0.8", - # "throughput p/s-ewma-alpha0.9", - # "throughput p/s-ewma-alpha1.0" -]) +ALL_FETS = sorted( + [ + # "1/sqrt loss event rate-windowed-minRtt1", + # "1/sqrt loss event rate-windowed-minRtt1024", + # "1/sqrt loss event rate-windowed-minRtt128", + # "1/sqrt loss event rate-windowed-minRtt16", + # "1/sqrt loss event rate-windowed-minRtt2", + # "1/sqrt loss event rate-windowed-minRtt256", + # "1/sqrt loss event rate-windowed-minRtt32", + # "1/sqrt loss event rate-windowed-minRtt4", + # "1/sqrt loss event rate-windowed-minRtt512", + # "1/sqrt loss event rate-windowed-minRtt64", + # "1/sqrt loss event rate-windowed-minRtt8", + # "RTT estimate ratio-ewma-alpha0.001", + # "RTT estimate ratio-ewma-alpha0.002", + # "RTT estimate ratio-ewma-alpha0.003", + # "RTT estimate ratio-ewma-alpha0.004", + # "RTT estimate ratio-ewma-alpha0.005", + # "RTT estimate ratio-ewma-alpha0.006", + # "RTT estimate ratio-ewma-alpha0.007", + # "RTT estimate ratio-ewma-alpha0.008", + # "RTT estimate ratio-ewma-alpha0.009", + # "RTT estimate ratio-ewma-alpha0.01", + # "RTT estimate ratio-ewma-alpha0.1", + # "RTT estimate ratio-ewma-alpha0.2", + # "RTT estimate ratio-ewma-alpha0.3", + # "RTT estimate ratio-ewma-alpha0.4", + "RTT estimate ratio-ewma-alpha0.5", + # "RTT estimate ratio-ewma-alpha0.6", + # "RTT estimate ratio-ewma-alpha0.7", + # "RTT estimate ratio-ewma-alpha0.8", + # "RTT estimate ratio-ewma-alpha0.9", + # "RTT estimate ratio-ewma-alpha1.0", + # "RTT estimate us-ewma-alpha0.001", + # "RTT estimate us-ewma-alpha0.002", + # "RTT estimate us-ewma-alpha0.003", + # "RTT estimate us-ewma-alpha0.004", + # "RTT estimate us-ewma-alpha0.005", + # "RTT estimate us-ewma-alpha0.006", + # "RTT estimate us-ewma-alpha0.007", + # "RTT estimate us-ewma-alpha0.008", + # "RTT estimate us-ewma-alpha0.009", + # "RTT estimate us-ewma-alpha0.01", + # "RTT estimate us-ewma-alpha0.1", + # "RTT estimate us-ewma-alpha0.2", + # "RTT estimate us-ewma-alpha0.3", + # "RTT estimate us-ewma-alpha0.4", + "RTT estimate us-ewma-alpha0.5", + # "RTT estimate us-ewma-alpha0.6", + # "RTT estimate us-ewma-alpha0.7", + # "RTT estimate us-ewma-alpha0.8", + # "RTT estimate us-ewma-alpha0.9", + # "RTT estimate us-ewma-alpha1.0", + # "arrival time us", + # "average RTT estimate ratio-windowed-minRtt1", + # "average RTT estimate ratio-windowed-minRtt1024", + # "average RTT estimate ratio-windowed-minRtt128", + # "average RTT estimate ratio-windowed-minRtt16", + # "average RTT estimate ratio-windowed-minRtt2", + # "average RTT estimate ratio-windowed-minRtt256", + # "average RTT estimate ratio-windowed-minRtt32", + # "average RTT estimate ratio-windowed-minRtt4", + # "average RTT estimate ratio-windowed-minRtt512", + # "average RTT estimate ratio-windowed-minRtt64", + # "average RTT estimate ratio-windowed-minRtt8", + # "average RTT estimate us-windowed-minRtt1", + # "average RTT estimate us-windowed-minRtt1024", + # "average RTT estimate us-windowed-minRtt128", + # "average RTT estimate us-windowed-minRtt16", + # "average RTT estimate us-windowed-minRtt2", + # "average RTT estimate us-windowed-minRtt256", + # "average RTT estimate us-windowed-minRtt32", + # "average RTT estimate us-windowed-minRtt4", + # "average RTT estimate us-windowed-minRtt512", + # "average RTT estimate us-windowed-minRtt64", + # "average RTT estimate us-windowed-minRtt8", + # "average interarrival time us-windowed-minRtt1", + # "average interarrival time us-windowed-minRtt1024", + # "average interarrival time us-windowed-minRtt128", + # "average interarrival time us-windowed-minRtt16", + # "average interarrival time us-windowed-minRtt2", + # "average interarrival time us-windowed-minRtt256", + # "average interarrival time us-windowed-minRtt32", + # "average interarrival time us-windowed-minRtt4", + # "average interarrival time us-windowed-minRtt512", + # "average interarrival time us-windowed-minRtt64", + # "average interarrival time us-windowed-minRtt8", + # "average throughput p/s-windowed-minRtt1", + # "average throughput p/s-windowed-minRtt1024", + # "average throughput p/s-windowed-minRtt128", + # "average throughput p/s-windowed-minRtt16", + # "average throughput p/s-windowed-minRtt2", + # "average throughput p/s-windowed-minRtt256", + # "average throughput p/s-windowed-minRtt32", + # "average throughput p/s-windowed-minRtt4", + # "average throughput p/s-windowed-minRtt512", + # "average throughput p/s-windowed-minRtt64", + # "average throughput p/s-windowed-minRtt8", + # "interarrival time us-ewma-alpha0.001", + # "interarrival time us-ewma-alpha0.002", + # "interarrival time us-ewma-alpha0.003", + # "interarrival time us-ewma-alpha0.004", + # "interarrival time us-ewma-alpha0.005", + # "interarrival time us-ewma-alpha0.006", + # "interarrival time us-ewma-alpha0.007", + # "interarrival time us-ewma-alpha0.008", + # "interarrival time us-ewma-alpha0.009", + # "interarrival time us-ewma-alpha0.01", + # "interarrival time us-ewma-alpha0.1", + # "interarrival time us-ewma-alpha0.2", + # "interarrival time us-ewma-alpha0.3", + # "interarrival time us-ewma-alpha0.4", + "interarrival time us-ewma-alpha0.5", + # "interarrival time us-ewma-alpha0.6", + # "interarrival time us-ewma-alpha0.7", + # "interarrival time us-ewma-alpha0.8", + # "interarrival time us-ewma-alpha0.9", + # "interarrival time us-ewma-alpha1.0", + # "loss event rate-windowed-minRtt1", + # "loss event rate-windowed-minRtt1024", + # "loss event rate-windowed-minRtt128", + # "loss event rate-windowed-minRtt16", + # "loss event rate-windowed-minRtt2", + # "loss event rate-windowed-minRtt256", + # "loss event rate-windowed-minRtt32", + # "loss event rate-windowed-minRtt4", + # "loss event rate-windowed-minRtt512", + # "loss event rate-windowed-minRtt64", + # "loss event rate-windowed-minRtt8", + # "loss rate estimate-ewma-alpha0.001", + # "loss rate estimate-ewma-alpha0.002", + # "loss rate estimate-ewma-alpha0.003", + # "loss rate estimate-ewma-alpha0.004", + # "loss rate estimate-ewma-alpha0.005", + # "loss rate estimate-ewma-alpha0.006", + # "loss rate estimate-ewma-alpha0.007", + # "loss rate estimate-ewma-alpha0.008", + # "loss rate estimate-ewma-alpha0.009", + # "loss rate estimate-ewma-alpha0.01", + # "loss rate estimate-ewma-alpha0.1", + # "loss rate estimate-ewma-alpha0.2", + # "loss rate estimate-ewma-alpha0.3", + # "loss rate estimate-ewma-alpha0.4", + "loss rate estimate-ewma-alpha0.5", + # "loss rate estimate-ewma-alpha0.6", + # "loss rate estimate-ewma-alpha0.7", + # "loss rate estimate-ewma-alpha0.8", + # "loss rate estimate-ewma-alpha0.9", + # "loss rate estimate-ewma-alpha1.0", + # "loss rate estimate-windowed-minRtt1", + # "loss rate estimate-windowed-minRtt1024", + # "loss rate estimate-windowed-minRtt128", + # "loss rate estimate-windowed-minRtt16", + # "loss rate estimate-windowed-minRtt2", + # "loss rate estimate-windowed-minRtt256", + # "loss rate estimate-windowed-minRtt32", + # "loss rate estimate-windowed-minRtt4", + # "loss rate estimate-windowed-minRtt512", + # "loss rate estimate-windowed-minRtt64", + # "loss rate estimate-windowed-minRtt8", + # "mathis model label-ewma-alpha0.001", + # "mathis model label-ewma-alpha0.002", + # "mathis model label-ewma-alpha0.003", + # "mathis model label-ewma-alpha0.004", + # "mathis model label-ewma-alpha0.005", + # "mathis model label-ewma-alpha0.006", + # "mathis model label-ewma-alpha0.007", + # "mathis model label-ewma-alpha0.008", + # "mathis model label-ewma-alpha0.009", + # "mathis model label-ewma-alpha0.01", + # "mathis model label-ewma-alpha0.1", + # "mathis model label-ewma-alpha0.2", + # "mathis model label-ewma-alpha0.3", + # "mathis model label-ewma-alpha0.4", + "mathis model label-ewma-alpha0.5", + # "mathis model label-ewma-alpha0.6", + # "mathis model label-ewma-alpha0.7", + # "mathis model label-ewma-alpha0.8", + # "mathis model label-ewma-alpha0.9", + # "mathis model label-ewma-alpha1.0", + # "mathis model label-windowed-minRtt1", + # "mathis model label-windowed-minRtt1024", + # "mathis model label-windowed-minRtt128", + # "mathis model label-windowed-minRtt16", + # "mathis model label-windowed-minRtt2", + # "mathis model label-windowed-minRtt256", + # "mathis model label-windowed-minRtt32", + # "mathis model label-windowed-minRtt4", + # "mathis model label-windowed-minRtt512", + # "mathis model label-windowed-minRtt64", + # "mathis model label-windowed-minRtt8", + # "mathis model throughput p/s-ewma-alpha0.001", + # "mathis model throughput p/s-ewma-alpha0.002", + # "mathis model throughput p/s-ewma-alpha0.003", + # "mathis model throughput p/s-ewma-alpha0.004", + # "mathis model throughput p/s-ewma-alpha0.005", + # "mathis model throughput p/s-ewma-alpha0.006", + # "mathis model throughput p/s-ewma-alpha0.007", + # "mathis model throughput p/s-ewma-alpha0.008", + # "mathis model throughput p/s-ewma-alpha0.009", + # "mathis model throughput p/s-ewma-alpha0.01", + # "mathis model throughput p/s-ewma-alpha0.1", + # "mathis model throughput p/s-ewma-alpha0.2", + # "mathis model throughput p/s-ewma-alpha0.3", + # "mathis model throughput p/s-ewma-alpha0.4", + "mathis model throughput p/s-ewma-alpha0.5", + # "mathis model throughput p/s-ewma-alpha0.6", + # "mathis model throughput p/s-ewma-alpha0.7", + # "mathis model throughput p/s-ewma-alpha0.8", + # "mathis model throughput p/s-ewma-alpha0.9", + # "mathis model throughput p/s-ewma-alpha1.0", + # "mathis model throughput p/s-windowed-minRtt1", + # "mathis model throughput p/s-windowed-minRtt1024", + # "mathis model throughput p/s-windowed-minRtt128", + # "mathis model throughput p/s-windowed-minRtt16", + # "mathis model throughput p/s-windowed-minRtt2", + # "mathis model throughput p/s-windowed-minRtt256", + # "mathis model throughput p/s-windowed-minRtt32", + # "mathis model throughput p/s-windowed-minRtt4", + # "mathis model throughput p/s-windowed-minRtt512", + # "mathis model throughput p/s-windowed-minRtt64", + # "mathis model throughput p/s-windowed-minRtt8", + "min RTT us", + # "seq", + # "throughput p/s-ewma-alpha0.001", + # "throughput p/s-ewma-alpha0.002", + # "throughput p/s-ewma-alpha0.003", + # "throughput p/s-ewma-alpha0.004", + # "throughput p/s-ewma-alpha0.005", + # "throughput p/s-ewma-alpha0.006", + # "throughput p/s-ewma-alpha0.007", + # "throughput p/s-ewma-alpha0.008", + # "throughput p/s-ewma-alpha0.009", + # "throughput p/s-ewma-alpha0.01", + # "throughput p/s-ewma-alpha0.1", + # "throughput p/s-ewma-alpha0.2", + # "throughput p/s-ewma-alpha0.3", + # "throughput p/s-ewma-alpha0.4", + "throughput p/s-ewma-alpha0.5", + # "throughput p/s-ewma-alpha0.6", + # "throughput p/s-ewma-alpha0.7", + # "throughput p/s-ewma-alpha0.8", + # "throughput p/s-ewma-alpha0.9", + # "throughput p/s-ewma-alpha1.0" + ] +) def run_cnfs(fets, args, sims): - """ Trains a model for each provided configuration. """ + """Trains a model for each provided configuration.""" # Assemble configurations. cnfs = [ - {**vars(args), "features": fets_, "sims": sims, "sync": True, - "out_dir": path.join(args.out_dir, subdir), - "tmp_dir": path.join("/tmp", subdir)} + { + **vars(args), + "features": fets_, + "sims": sims, + "sync": True, + "out_dir": path.join(args.out_dir, subdir), + "tmp_dir": path.join("/tmp", subdir), + } for fets_, subdir in zip( fets, # Create a subdirectory name for each list of features. - [",".join([ - str(fet).replace(" ", "_").replace("/", "p") - for fet in fets_]) - for fets_ in fets])] + [ + ",".join( + [str(fet).replace(" ", "_").replace("/", "p") for fet in fets_] + ) + for fets_ in fets + ], + ) + ] # Train configurations. if defaults.SYNC: res = [train.run_trials(cnf) for cnf in cnfs] @@ -292,12 +301,11 @@ def run_cnfs(fets, args, sims): except FileNotFoundError: pass # Note that accuracy = 1 - loss. - return dict(zip( - [tuple(cnf["features"]) for cnf in cnfs], 1 - np.array(res))) + return dict(zip([tuple(cnf["features"]) for cnf in cnfs], 1 - np.array(res))) def main(): - """ This program's entrypoint. """ + """This program's entrypoint.""" # Parse command line arguments. psr = argparse.ArgumentParser(description="Evaluates feature correlation.") psr, psr_verify = cl_args.add_training(psr) @@ -333,26 +341,39 @@ def main(): num_sims = args.num_sims if num_sims is not None: num_sims_actual = len(sims) - assert num_sims_actual >= num_sims, \ - (f"Insufficient simulations. Requested {num_sims}, but only " - f"{num_sims_actual} available.") + assert num_sims_actual >= num_sims, ( + f"Insufficient simulations. Requested {num_sims}, but only " + f"{num_sims_actual} available." + ) sims = sims[:num_sims] # Train models. accs_single = run_cnfs([[fet] for fet in all_fets], args, sims) accs_pairs = run_cnfs( - [[fet1, fet2] - for i, fet1 in enumerate(all_fets) - for j, fet2 in enumerate(all_fets) - # Do not consider pairs of the same feature. - if i != j], - args, sims) + [ + [fet1, fet2] + for i, fet1 in enumerate(all_fets) + for j, fet2 in enumerate(all_fets) + # Do not consider pairs of the same feature. + if i != j + ], + args, + sims, + ) # Calculate the accuracy ratios. accs_ratios = np.array( - [[(accs_pairs[(fet1, fet2)] / accs_single[(fet1,)] - if (fet1, fet2) in accs_pairs else 0) - for fet2 in fets_x] - for fet1 in fets_y]) + [ + [ + ( + accs_pairs[(fet1, fet2)] / accs_single[(fet1,)] + if (fet1, fet2) in accs_pairs + else 0 + ) + for fet2 in fets_x + ] + for fet1 in fets_y + ] + ) # Save results. np.savez_compressed(dat_flp, accs_ratios=accs_ratios) print(f"Saving results: {dat_flp}") @@ -361,9 +382,16 @@ def main(): plt.subplots(figsize=(8, 7)) with sns.axes_style("white"): sns.heatmap( - accs_ratios, linewidth=0.5, center=1, xticklabels=fets_x, - yticklabels=fets_y, square=True, annot=True, fmt=".2f", - annot_kws={"fontsize":8}) + accs_ratios, + linewidth=0.5, + center=1, + xticklabels=fets_x, + yticklabels=fets_y, + square=True, + annot=True, + fmt=".2f", + annot_kws={"fontsize": 8}, + ) plt.tight_layout() out_flp = path.join(out_dir, "correlation.pdf") print(f"Saving graph: {out_flp}") diff --git a/ratemon/model/data.py b/ratemon/model/data.py index d8125a04..62251df1 100644 --- a/ratemon/model/data.py +++ b/ratemon/model/data.py @@ -5,8 +5,8 @@ from os import path import numpy as np -from numpy.lib import recfunctions import torch +from numpy.lib import recfunctions from ratemon.model import defaults, features, models, utils diff --git a/ratemon/model/defaults.py b/ratemon/model/defaults.py index f3d06594..09eef436 100644 --- a/ratemon/model/defaults.py +++ b/ratemon/model/defaults.py @@ -1,9 +1,8 @@ """Default values.""" -from enum import IntEnum import math import struct - +from enum import IntEnum # Parameter defaults. DEFAULTS = { diff --git a/ratemon/model/fet_hists.py b/ratemon/model/fet_hists.py index 47ca3b7f..d4098a4b 100755 --- a/ratemon/model/fet_hists.py +++ b/ratemon/model/fet_hists.py @@ -4,20 +4,21 @@ import argparse from os import path -from matplotlib import pyplot -import numpy as np - import cl_args +import numpy as np +from matplotlib import pyplot def main(): - """ This program's entrypoint. """ + """This program's entrypoint.""" # Parse command line arguments. - psr = argparse.ArgumentParser( - description="Visualize a simulation's features.") + psr = argparse.ArgumentParser(description="Visualize a simulation's features.") psr.add_argument( - "--training-data", help="The path to the parsed training data.", - required=True, type=str) + "--training-data", + help="The path to the parsed training data.", + required=True, + type=str, + ) psr, psr_verify = cl_args.add_out(psr) args = psr_verify(psr.parse_args()) dat_flp = args.training_data @@ -35,8 +36,9 @@ def main(): pyplot.hist(dat_in[fet], bins=50, density=True) pyplot.xlabel(fet) pyplot.ylabel("histogram") - pyplot.savefig(path.join( - args.out_dir, f"{fet.replace(' ', '_').replace('/', '-')}.pdf")) + pyplot.savefig( + path.join(args.out_dir, f"{fet.replace(' ', '_').replace('/', '-')}.pdf") + ) pyplot.close() diff --git a/ratemon/model/gen_features.py b/ratemon/model/gen_features.py index 2b1d0657..e0a83651 100755 --- a/ratemon/model/gen_features.py +++ b/ratemon/model/gen_features.py @@ -2,21 +2,21 @@ """Parses the output of CloudLab experiments.""" import argparse -from contextlib import contextmanager -from io import UnsupportedOperation import itertools +import json import logging import multiprocessing -import subprocess import os -from os import path import random import shutil +import subprocess import sys import time import traceback +from contextlib import contextmanager +from io import UnsupportedOperation +from os import path -import json import numpy as np from ratemon.model import cl_args, defaults, features, loss_event_rate, utils diff --git a/ratemon/model/gen_training_data.py b/ratemon/model/gen_training_data.py index 6afb4482..50804702 100755 --- a/ratemon/model/gen_training_data.py +++ b/ratemon/model/gen_training_data.py @@ -5,15 +5,14 @@ import itertools import logging import os -from os import path import time +from os import path import cl_args import defaults import sim import utils - # Bandwidth (Mbps). BW_MIN_Mbps = 10 BW_MAX_Mbps = 10 @@ -57,12 +56,15 @@ def main(): - """ This program's entrypoint. """ + """This program's entrypoint.""" # Parse command line arguments. psr = argparse.ArgumentParser(description="Generates training data.") psr.add_argument( - "--log-dst", default=EMAIL_DST, - help="The email address to which updates will be sent.", type=str) + "--log-dst", + default=EMAIL_DST, + help="The email address to which updates will be sent.", + type=str, + ) psr, psr_verify = cl_args.add_out(psr) args = psr_verify(psr.parse_args()) # The ID of the experiment. @@ -91,31 +93,47 @@ def main(): log.info("Duration (s): %s", DUR_s) # Assemble the configurations. - cnfs = [{"bottleneck_bandwidth_Mbps": bw_Mbps, - "bottleneck_delay_us": dly_us, - # Calculate queue capacity as a multiple of the BDP. If the BDP is - # less than a single packet, then use 1 packet as the BDP anyway. - "bottleneck_queue_p": int(round( - que_mult * - max(1, - utils.bdp_B(bw_Mbps * 1e6, dly_us / 1e6 * 6) / float(PACKET_SIZE_B)))), - "unfair_flows": unfair_flws, - "unfair_proto": UNFAIR_PROTO, - "fair_flows": fair_flws, - "fair_proto": FAIR_PROTO, - "unfair_edge_delays_us": f"[{dly_us}]", - "fair_edge_delays_us": f"[{dly_us}]", - "payload_B": PACKET_SIZE_B, - "enable_mitigation": "false", - "duration_s": DUR_s, - "pcap": "true" if PCAP else "false", - "out_dir": sim_dir} - for (bw_Mbps, dly_us, que_mult, unfair_flws, - fair_flws) in itertools.product( - BWS_Mbps, DELAYS_us, QUEUE_MULTS, UNFAIR_FLOWS, - FAIR_FLOWS)] - sim.sim(eid, cnfs, out_dir, log_par=LOGGER, log_dst=args.log_dst, - dry_run=DRY_RUN, sync=defaults.SYNC) + cnfs = [ + { + "bottleneck_bandwidth_Mbps": bw_Mbps, + "bottleneck_delay_us": dly_us, + # Calculate queue capacity as a multiple of the BDP. If the BDP is + # less than a single packet, then use 1 packet as the BDP anyway. + "bottleneck_queue_p": int( + round( + que_mult + * max( + 1, + utils.bdp_B(bw_Mbps * 1e6, dly_us / 1e6 * 6) + / float(PACKET_SIZE_B), + ) + ) + ), + "unfair_flows": unfair_flws, + "unfair_proto": UNFAIR_PROTO, + "fair_flows": fair_flws, + "fair_proto": FAIR_PROTO, + "unfair_edge_delays_us": f"[{dly_us}]", + "fair_edge_delays_us": f"[{dly_us}]", + "payload_B": PACKET_SIZE_B, + "enable_mitigation": "false", + "duration_s": DUR_s, + "pcap": "true" if PCAP else "false", + "out_dir": sim_dir, + } + for (bw_Mbps, dly_us, que_mult, unfair_flws, fair_flws) in itertools.product( + BWS_Mbps, DELAYS_us, QUEUE_MULTS, UNFAIR_FLOWS, FAIR_FLOWS + ) + ] + sim.sim( + eid, + cnfs, + out_dir, + log_par=LOGGER, + log_dst=args.log_dst, + dry_run=DRY_RUN, + sync=defaults.SYNC, + ) log.info("Results in: %s", out_dir) log.critical("Finished.") diff --git a/ratemon/model/graph_one.py b/ratemon/model/graph_one.py index e53524b7..9c4bb984 100755 --- a/ratemon/model/graph_one.py +++ b/ratemon/model/graph_one.py @@ -6,16 +6,15 @@ import os from os import path -from matplotlib import pyplot as plt -import numpy as np - import cl_args import features +import numpy as np import utils +from matplotlib import pyplot as plt def graph_fet(out_dir, dat, fet, bw_share_fair, bw_fair, x_min, x_max, labels): - """ Graphs a single feature. """ + """Graphs a single feature.""" if features.ARRIVAL_TIME_FET in fet: return @@ -24,37 +23,44 @@ def graph_fet(out_dir, dat, fet, bw_share_fair, bw_fair, x_min, x_max, labels): plt.plot( flw_dat[features.ARRIVAL_TIME_FET], np.where(flw_dat[fet] == -1, np.nan, flw_dat[fet]), - ".", markersize=0.5) + ".", + markersize=0.5, + ) plt.xlabel(features.ARRIVAL_TIME_FET) plt.ylabel(fet) if features.TPUT_FET in fet and features.TOTAL_TPUT_FET not in fet: plt.hlines(bw_fair, 0, x_max, colors="k", linestyles="dashdot") elif features.TPUT_SHARE_FRAC_FET in fet: - plt.hlines( - bw_share_fair, 0, x_max, colors="k", linestyles="dashdot") + plt.hlines(bw_share_fair, 0, x_max, colors="k", linestyles="dashdot") plt.legend(labels, loc="upper left") plt.xlim(x_min, x_max) plt.ylim(bottom=0) plt.tight_layout() - plt.savefig(path.join( - out_dir, - (features.ARRIVAL_TIME_FET + "_vs_" + fet + ".pdf").replace( - ' ', '_').replace('/', '-'))) + plt.savefig( + path.join( + out_dir, + (features.ARRIVAL_TIME_FET + "_vs_" + fet + ".pdf") + .replace(" ", "_") + .replace("/", "-"), + ) + ) plt.close() def main(): - """ This program's entrypoint. """ + """This program's entrypoint.""" # Parse command line arguments. - psr = argparse.ArgumentParser( - description="Visualize a experiment's features.") + psr = argparse.ArgumentParser(description="Visualize a experiment's features.") psr.add_argument( "--parsed-data", - help=("The path to the parsed experiment data generated by " - "gen_features.py."), - required=True, type=str) + help=( + "The path to the parsed experiment data generated by " "gen_features.py." + ), + required=True, + type=str, + ) psr, psr_verify = cl_args.add_out(psr) args = psr_verify(psr.parse_args()) dat_flp = args.parsed_data @@ -68,9 +74,10 @@ def main(): exp = utils.Exp(dat_flp) num_flws = exp.tot_flws found_flws = len(dat) - assert num_flws == found_flws, \ - (f"Experiment has {num_flws} flows, parsed data has {found_flws} " - f"flows: {dat_flp}") + assert num_flws == found_flws, ( + f"Experiment has {num_flws} flows, parsed data has {found_flws} " + f"flows: {dat_flp}" + ) if found_flws == 0: print("No flows to graph.") return @@ -86,8 +93,11 @@ def main(): with multiprocessing.Pool() as pol: pol.starmap( graph_fet, - ((out_dir, dat, fet, bw_share_fair, bw_fair, x_min, x_max, labels) - for fet in fets)) + ( + (out_dir, dat, fet, bw_share_fair, bw_fair, x_min, x_max, labels) + for fet in fets + ), + ) if __name__ == "__main__": diff --git a/ratemon/model/hyper.py b/ratemon/model/hyper.py index e18b4f9f..104d85ad 100755 --- a/ratemon/model/hyper.py +++ b/ratemon/model/hyper.py @@ -9,29 +9,33 @@ import time import ax -import numpy as np - import cl_args import defaults +import numpy as np import train - DEFAULT_TLS_OPT = 40 def main(): - """ This program's entrypoint. """ + """This program's entrypoint.""" # Parse command line arguments. - psr = argparse.ArgumentParser( - description="Hyper-parameter optimizer for train.py.") + psr = argparse.ArgumentParser(description="Hyper-parameter optimizer for train.py.") psr, psr_verify = cl_args.add_training(psr) psr.add_argument( - "--opt-trials", default=DEFAULT_TLS_OPT, - help="The number of optimization trials to run.", type=int) + "--opt-trials", + default=DEFAULT_TLS_OPT, + help="The number of optimization trials to run.", + type=int, + ) psr.add_argument( - "--exhaustive", action="store_true", - help=("Try all combinations of parameters. Incompatible with " - "parameters of type \"range\".")) + "--exhaustive", + action="store_true", + help=( + "Try all combinations of parameters. Incompatible with " + 'parameters of type "range".' + ), + ) args = psr_verify(psr.parse_args()) tls_opt = args.opt_trials tls_cnf = args.conf_trials @@ -39,41 +43,13 @@ def main(): # Define the optimization parameters. params = [ - { - "name": "data_dir", - "type": "fixed", - "value": args.data_dir - }, - { - "name": "model", - "type": "choice", - "values": ["SvmSklearn", "LrSklearn"] - }, - { - "name": "conf_trials", - "type": "fixed", - "value": tls_cnf - }, - { - "name": "max_attempts", - "type": "fixed", - "value": args.max_attempts - }, - { - "name": "num_gpus", - "type": "fixed", - "value": 0 - }, - { - "name": "warmup_percent", - "type": "fixed", - "value": 10 - }, - { - "name": "num_sims", - "type": "fixed", - "value": args.num_sims - }, + {"name": "data_dir", "type": "fixed", "value": args.data_dir}, + {"name": "model", "type": "choice", "values": ["SvmSklearn", "LrSklearn"]}, + {"name": "conf_trials", "type": "fixed", "value": tls_cnf}, + {"name": "max_attempts", "type": "fixed", "value": args.max_attempts}, + {"name": "num_gpus", "type": "fixed", "value": 0}, + {"name": "warmup_percent", "type": "fixed", "value": 10}, + {"name": "num_sims", "type": "fixed", "value": args.num_sims}, # { # "name": "train_batch", # "type": "fixed", @@ -92,7 +68,7 @@ def main(): { "name": "kernel", "type": "choice", - "values": ["linear", "poly", "rbf", "sigmoid"] + "values": ["linear", "poly", "rbf", "sigmoid"], }, # { # "name": "degree", @@ -101,78 +77,59 @@ def main(): # }, # Represent degree as a choice parameter so that it is # compatible with exhaustive mode. - { - "name": "degree", - "type": "choice", - "values": list(range(0, 21)) - }, - { - "name": "penalty", - "type": "choice", - "values": ["l1", "l2"] - }, - { - "name": "no_rand", - "type": "fixed", - "value": no_rand - }, - { - "name": "timeout_s", - "type": "fixed", - "value": args.timeout_s - }, - { - "name": "out_dir", - "type": "fixed", - "value": args.out_dir - } + {"name": "degree", "type": "choice", "values": list(range(0, 21))}, + {"name": "penalty", "type": "choice", "values": ["l1", "l2"]}, + {"name": "no_rand", "type": "fixed", "value": no_rand}, + {"name": "timeout_s", "type": "fixed", "value": args.timeout_s}, + {"name": "out_dir", "type": "fixed", "value": args.out_dir}, ] # If we are using early stopping, then "epochs" is unnecessary but # "val_patience" and "val_improvement_thresh" are also candidates for # optimization. if args.early_stop: - params.extend([ - { - "name": "early_stop", - "type": "fixed", - "value": True - }, - { - "name": "val_patience", - "type": "range", - "bounds": [5, 20] - }, - { - "name": "val_improvement_thresh", - "type": "range", - "bounds": [0.01, 0.1] - } - ]) + params.extend( + [ + {"name": "early_stop", "type": "fixed", "value": True}, + {"name": "val_patience", "type": "range", "bounds": [5, 20]}, + { + "name": "val_improvement_thresh", + "type": "range", + "bounds": [0.01, 0.1], + }, + ] + ) else: - params.extend([ - # { - # "name": "epochs", - # "type": "range", - # "bounds": [1, 100] - # }, - ]) + params.extend( + [ + # { + # "name": "epochs", + # "type": "range", + # "bounds": [1, 100] + # }, + ] + ) tim_srt_s = time.time() if args.exhaustive: for param in params: - assert param["type"] != "range", \ - f"Exhaustive mode does not support range parameters: {param}" + assert ( + param["type"] != "range" + ), f"Exhaustive mode does not support range parameters: {param}" fixed = { param["name"]: param["value"] - for param in params if param["type"] == "fixed"} + for param in params + if param["type"] == "fixed" + } to_vary = [ [(param["name"], value) for value in param["values"]] - for param in params if param["type"] == "choice"] + for param in params + if param["type"] == "choice" + ] print( f"Varying these parameters, with {tls_cnf} sub-trials(s) for each " - f"configuration: {[pairs[0][0] for pairs in to_vary]}") - cnfs = [ - {**fixed, **dict(params)} for params in itertools.product(*to_vary)] + f"configuration: {[pairs[0][0] for pairs in to_vary]}" + ) + cnfs = [{**fixed, **dict(params)} for params in itertools.product(*to_vary)] print(f"Total trials: {len(cnfs) * tls_cnf}") if defaults.SYNC: res = [train.run_trials(cnf)[0] for cnf in cnfs] @@ -183,17 +140,26 @@ def main(): best_params = cnfs[best_idx] best_err = res[best_idx] else: - print((f"Running {tls_opt} optimization trial(s), with {tls_cnf} " - "sub-trial(s) for each configuration.")) + print( + ( + f"Running {tls_opt} optimization trial(s), with {tls_cnf} " + "sub-trial(s) for each configuration." + ) + ) best_params, best_vals, _, _ = ax.optimize( parameters=params, evaluation_function=lambda cnf: train.run_trials(cnf)[0], minimize=True, total_trials=args.opt_trials, - random_seed=defaults.SEED if no_rand else None) + random_seed=defaults.SEED if no_rand else None, + ) best_err = best_vals[0]["objective"] - print((f"Done with hyper-parameter optimization - " - f"{time.time() - tim_srt_s:.2f} seconds")) + print( + ( + f"Done with hyper-parameter optimization - " + f"{time.time() - tim_srt_s:.2f} seconds" + ) + ) print(f"\nBest params: {best_params}") print(f"Best error: {best_err:.4f}%") diff --git a/ratemon/model/models.py b/ratemon/model/models.py index 2676d240..469de92e 100644 --- a/ratemon/model/models.py +++ b/ratemon/model/models.py @@ -4,22 +4,18 @@ import logging import math import os -from os import path import pickle import random +from os import path -from matplotlib import pyplot as plt import numpy as np import sklearn -from sklearn import ensemble -from sklearn import linear_model -from sklearn import metrics -from sklearn import svm import torch +from matplotlib import pyplot as plt +from sklearn import ensemble, linear_model, metrics, svm from ratemon.model import defaults, features, utils - SMOOTHING_THRESHOLD = 0.4 SLIDING_WINDOW_NUM_RTT = 1 @@ -1296,7 +1292,7 @@ def init_hidden(self, batch_size): @staticmethod def convert_to_class(dat_out): # TODO: Implement. - assert False, "Not implemented." + raise AssertionError("Not implemented.") return dat_out diff --git a/ratemon/model/parse_validation_exps.sh b/ratemon/model/parse_validation_exps.sh index 1d8453bd..c3697158 100755 --- a/ratemon/model/parse_validation_exps.sh +++ b/ratemon/model/parse_validation_exps.sh @@ -14,41 +14,33 @@ RATEMON_DIR=$1 ITERS_DIR=$2 UNTAR_DIR=$3 DIRECTION=$4 -mkdir -p "$UNTAR_DIR" +mkdir -p "${UNTAR_DIR}" NUM_ITERS=10 - -parse_iter_batchsize () { - ITER=$1 - BATCH_SIZE=$2 - EXP_DIR="$ITERS_DIR/iter_$ITER/batchsize_$BATCH_SIZE" - python "$RATEMON_DIR/model/parse_cloudlab.py" --exp-dir "$EXP_DIR" \ - --untar-dir "$UNTAR_DIR" --out-dir "$EXP_DIR" \ - --skip-smoothed-features +parse_iter_batchsize() { + ITER=$1 + BATCH_SIZE=$2 + EXP_DIR="${ITERS_DIR}/iter_${ITER}/batchsize_${BATCH_SIZE}" + python "${RATEMON_DIR}/model/parse_cloudlab.py" --exp-dir "${EXP_DIR}" \ + --untar-dir "${UNTAR_DIR}" --out-dir "${EXP_DIR}" \ + --skip-smoothed-features } - -if [ "$DIRECTION" = "forward" ] -then - for (( ITER=1; ITER<=NUM_ITERS; ITER++ )) - do - for BATCH_SIZE in 1 5 10 20 - do - parse_iter_batchsize "$ITER" "$BATCH_SIZE" - done - done -elif [ "$DIRECTION" = "reverse" ] -then - for (( ITER=NUM_ITERS; ITER>=1; ITER-- )) - do - for BATCH_SIZE in 20 10 5 1 - do - parse_iter_batchsize "$ITER" "$BATCH_SIZE" - done - done +if [[ ${DIRECTION} == "forward" ]]; then + for ((ITER = 1; ITER <= NUM_ITERS; ITER++)); do + for BATCH_SIZE in 1 5 10 20; do + parse_iter_batchsize "${ITER}" "${BATCH_SIZE}" + done + done +elif [[ ${DIRECTION} == "reverse" ]]; then + for ((ITER = NUM_ITERS; ITER >= 1; ITER--)); do + for BATCH_SIZE in 20 10 5 1; do + parse_iter_batchsize "${ITER}" "${BATCH_SIZE}" + done + done else - echo "Unknown direction: $DIRECTION" + echo "Unknown direction: ${DIRECTION}" fi echo "Done" diff --git a/ratemon/model/prepare_data.py b/ratemon/model/prepare_data.py index db2ededd..0279f238 100755 --- a/ratemon/model/prepare_data.py +++ b/ratemon/model/prepare_data.py @@ -10,16 +10,15 @@ import logging import math import os -from os import path -import time import random import sys +import time +from os import path import numpy as np from ratemon.model import cl_args, defaults, features, models, utils - SPLIT_NAMES = ["train", "val", "test"] diff --git a/ratemon/model/sim.py b/ratemon/model/sim.py index 5ea48cdb..94149600 100755 --- a/ratemon/model/sim.py +++ b/ratemon/model/sim.py @@ -5,11 +5,10 @@ import logging.handlers import multiprocessing import os -from os import path import subprocess import time import traceback - +from os import path # Path to the ns-3 top-level directory. # Warning: If you move this file from the directory "ratemon/model", then you @@ -26,15 +25,19 @@ def check_output(cnf, logger, msg): - """ Runs a configuration and returns its output. """ - args = ([path.join(NS3_DIR, "build", "scratch", APP),] + - [f"--{arg}={val}" for arg, val in cnf.items()]) + """Runs a configuration and returns its output.""" + args = [ + path.join(NS3_DIR, "build", "scratch", APP), + ] + [f"--{arg}={val}" for arg, val in cnf.items()] cmd = f"LD_LIBRARY_PATH={os.environ['LD_LIBRARY_PATH']} {' '.join(args)}" log = logging.getLogger(logger) log.info("Running%s: %s", f" ({msg})" if msg is not None else "", cmd) try: - res = subprocess.check_output( - args, stderr=subprocess.STDOUT, env=os.environ).decode().split("\n") + res = ( + subprocess.check_output(args, stderr=subprocess.STDOUT, env=os.environ) + .decode() + .split("\n") + ) except subprocess.CalledProcessError: traceback.print_exc() log.exception("Exception while running:\n%s\n\n", cmd) @@ -67,15 +70,22 @@ def run(cnf, res_fnc, logger, idx, total): """ # Build the arguments array, run the simulation, and iterate over each line # in its output. - out = check_output( - cnf, logger, msg=f"{idx + 1:{f'0{len(str(total))}'}}/{total}") + out = check_output(cnf, logger, msg=f"{idx + 1:{f'0{len(str(total))}'}}/{total}") if res_fnc is None: return None return res_fnc(out) -def sim(eid, cnfs, out_dir, res_fnc=None, log_par=None, log_dst=None, - dry_run=False, sync=False): +def sim( + eid, + cnfs, + out_dir, + res_fnc=None, + log_par=None, + log_dst=None, + dry_run=False, + sync=False, +): """ Simulates a set of configurations. Returns a list of pairs of the form: (configuration, result) @@ -91,7 +101,8 @@ def sim(eid, cnfs, out_dir, res_fnc=None, log_par=None, log_dst=None, mailhost="localhost", fromaddr=f"{os.getlogin()}@maas.cmcl.cs.cmu.edu", toaddrs=log_dst, - subject=f"[{logger}] {eid}") + subject=f"[{logger}] {eid}", + ) hdl.setLevel("ERROR") log.addHandler(hdl) @@ -102,7 +113,8 @@ def sim(eid, cnfs, out_dir, res_fnc=None, log_par=None, log_dst=None, # the ns-3 library can be found. os.environ["LD_LIBRARY_PATH"] = ( f"/usr/lib/gcc/x86_64-linux-gnu/7:{path.join(NS3_DIR, 'build', 'lib')}:" - "/opt/libtorch/lib") + "/opt/libtorch/lib" + ) # Record the configurations. with open(path.join(out_dir, "configurations.json"), "w") as fil: @@ -116,14 +128,13 @@ def sim(eid, cnfs, out_dir, res_fnc=None, log_par=None, log_dst=None, tim_srt_s = time.time() if sync: data = [ - run(cnf, res_fnc, logger, idx, num_cnfs) - for idx, cnf in enumerate(cnfs)] + run(cnf, res_fnc, logger, idx, num_cnfs) for idx, cnf in enumerate(cnfs) + ] else: with multiprocessing.Pool() as pool: data = pool.starmap( run, - ((cnf, res_fnc, logger, idx, num_cnfs) - for idx, cnf in enumerate(cnfs))) - log.critical( - "Done with simulations - time: %.2f seconds", time.time() - tim_srt_s) + ((cnf, res_fnc, logger, idx, num_cnfs) for idx, cnf in enumerate(cnfs)), + ) + log.critical("Done with simulations - time: %.2f seconds", time.time() - tim_srt_s) return list(zip(cnfs, data)) diff --git a/ratemon/model/test.py b/ratemon/model/test.py index c3a52ac7..8d224bcc 100755 --- a/ratemon/model/test.py +++ b/ratemon/model/test.py @@ -5,19 +5,18 @@ import json import multiprocessing import os -from os import path import pickle import time -from matplotlib import pyplot - -import numpy as np -import torch +from os import path import cl_args import defaults import models +import numpy as np +import torch import train import utils +from matplotlib import pyplot def plot_bar(x_axis, y_axis, file_name): diff --git a/ratemon/model/test_all.py b/ratemon/model/test_all.py index 72aef603..aece1d06 100755 --- a/ratemon/model/test_all.py +++ b/ratemon/model/test_all.py @@ -5,18 +5,17 @@ import json import multiprocessing import os -from os import path import pickle -from statistics import mean import time -from matplotlib import pyplot +from os import path +from statistics import mean +import models import numpy as np import torch - -import models import train import utils +from matplotlib import pyplot manager = multiprocessing.Manager() all_accuracy = manager.list() diff --git a/ratemon/model/test_data/scale_params.json b/ratemon/model/test_data/scale_params.json index 7c370c25..9f783c6f 100644 --- a/ratemon/model/test_data/scale_params.json +++ b/ratemon/model/test_data/scale_params.json @@ -1 +1,111 @@ -[[2.273030282830976, 9.9079092984679], [2.273030282830976, 19.12502723309608], [2.273030282830976, 19.12502723309608], [2.273030282830976, 13.089435944047906], [2.273030282830976, 19.12502723309608], [2.273030282830976, 19.12502723309608], [2.273030282830976, 16.258331197676267], [2.273030282830976, 19.12502723309608], [2.273030282830976, 19.128512749296533], [1.0007578251498102, 7.500346839070761], [1.0022534042799602, 7.657026540088466], [1.0037225338414915, 7.77530722329203], [1.0051655840372473, 7.873739369132442], [1.0065829203368395, 8.149371827511755], [1.012112468263781, 12.563109437867734], [1.0040349406554874, 13.354470276989755], [1.004170744124976, 13.512101713773239], [1.0, 13.652039714468643], [770379.0822356541, 2881001.604858467], [639171.3012942033, 2885208.522507776], [579730.0402807747, 2889317.3392991326], [545784.9333212022, 2893329.1906575365], [524595.2128850332, 2897245.199712089], [321516.42492363247, 2990575.088686485], [241328.88507924118, 2852134.761971103], [245952.58843907612, 2697565.3121622605], [252432.0, 2722961.0], [1.0121658538377496, 13.161763940782928], [1.0446308638359887, 7.6792542970651105], [1.0446308638359887, 9.94118983160236], [1.025948251919928, 12.686373629215081], [1.0446308638359887, 7.49966018966071], [1.0446308638359887, 8.75306300021772], [1.0407586548676597, 11.776442169866314], [1.0446308638359887, 7.99683839322124], [1.04338677513287, 10.150346512326298], [247837.5, 3074593.6363636362], [695405.8932316492, 3074593.6363636362], [422842.126984127, 3074593.6363636362], [247837.5, 3074593.6363636362], [731397.4551248008, 3074593.6363636362], [496512.6138211382, 3074593.6363636362], [197043.33333333334, 3074593.6363636362], [584393.8527918782, 3074593.6363636362], [397908.2794117647, 3074593.6363636362], [4610.5, 178624.0], [9294.802220680083, 128826.33333333333], [7162.4248927038625, 128826.33333333333], [4610.5, 178624.0], [10084.334119496856, 128826.33333333333], [7367.938189845475, 128826.33333333333], [6065.820895522388, 205300.66666666666], [7615.237770193402, 128826.33333333333], [6986.151260504202, 128826.33333333333], [5.598351845216768, 216.89621516104543], [7.762388124581156, 107.58701220937135], [7.762388124581156, 139.61751990148875], [5.598351845216768, 216.89621516104543], [7.762388124581156, 99.16371156987148], [7.762388124581156, 135.72317984130277], [4.870904786800498, 164.8581481754878], [7.762388124581156, 131.31566343392103], [7.762388124581156, 143.14033044967715], [11987.240518239276, 51102.32738864708], [8397.288402094997, 54329.26303760978], [7589.124910361394, 57041.43841888775], [7248.936669502694, 59421.48106801299], [6895.814132790256, 61828.04506508371], [6158.845825601434, 140769.27005379187], [6151.646622361971, 290457.7858117319], [6143.623156118695, 431916.7802734375], [6108.0, 788373.0], [0.0, 0.1935483870967742], [0.0, 0.1935483870967742], [0.0, 0.1935483870967742], [0.0, 0.1935483870967742], [0.0, 0.1935483870967742], [0.0, 0.1935483870967742], [0.0, 0.1935483870967742], [0.0, 0.1935483870967742], [0.0, 0.1935483870967742], [0.0, 0.1017248463000567], [0.0, 0.19302357992046917], [0.0, 0.24128358208341874], [0.0, 0.2826254852328126], [0.0, 0.31267985808962173], [0.0, 0.6188188532135033], [0.0, 0.6194697204683558], [0.0, 0.6220486110904144], [0.0, 0.6666666666666666], [0.0, 0.6444444444444445], [0.0, 0.244], [0.0, 0.38202247191011235], [0.0, 0.6413043478260869], [0.0, 0.244], [0.0, 0.35949764521193095], [0.0, 0.6024096385542169], [0.0, 0.27053571428571427], [0.0, 0.4956140350877193], [104647.0, 1545893.0], [19.568580358282478, 83.4220351613403], [18.406286853325135, 119.08606113260502], [17.531114707459352, 131.76749780922765], [16.828930919029332, 137.95126728132996], [16.173890003271868, 145.01550951683924], [7.103823154143458, 162.36808459194484], [3.442841090333785, 162.55810214534762], [2.3152608226217115, 162.77040023264735], [1.2684351189094503, 163.71971185330713]] \ No newline at end of file +[ + [2.273030282830976, 9.9079092984679], + [2.273030282830976, 19.12502723309608], + [2.273030282830976, 19.12502723309608], + [2.273030282830976, 13.089435944047906], + [2.273030282830976, 19.12502723309608], + [2.273030282830976, 19.12502723309608], + [2.273030282830976, 16.258331197676267], + [2.273030282830976, 19.12502723309608], + [2.273030282830976, 19.128512749296533], + [1.0007578251498102, 7.500346839070761], + [1.0022534042799602, 7.657026540088466], + [1.0037225338414915, 7.77530722329203], + [1.0051655840372473, 7.873739369132442], + [1.0065829203368395, 8.149371827511755], + [1.012112468263781, 12.563109437867734], + [1.0040349406554874, 13.354470276989755], + [1.004170744124976, 13.512101713773239], + [1.0, 13.652039714468643], + [770379.0822356541, 2881001.604858467], + [639171.3012942033, 2885208.522507776], + [579730.0402807747, 2889317.3392991326], + [545784.9333212022, 2893329.1906575365], + [524595.2128850332, 2897245.199712089], + [321516.42492363247, 2990575.088686485], + [241328.88507924118, 2852134.761971103], + [245952.58843907612, 2697565.3121622605], + [252432.0, 2722961.0], + [1.0121658538377496, 13.161763940782928], + [1.0446308638359887, 7.6792542970651105], + [1.0446308638359887, 9.94118983160236], + [1.025948251919928, 12.686373629215081], + [1.0446308638359887, 7.49966018966071], + [1.0446308638359887, 8.75306300021772], + [1.0407586548676597, 11.776442169866314], + [1.0446308638359887, 7.99683839322124], + [1.04338677513287, 10.150346512326298], + [247837.5, 3074593.6363636362], + [695405.8932316492, 3074593.6363636362], + [422842.126984127, 3074593.6363636362], + [247837.5, 3074593.6363636362], + [731397.4551248008, 3074593.6363636362], + [496512.6138211382, 3074593.6363636362], + [197043.33333333334, 3074593.6363636362], + [584393.8527918782, 3074593.6363636362], + [397908.2794117647, 3074593.6363636362], + [4610.5, 178624.0], + [9294.802220680083, 128826.33333333333], + [7162.4248927038625, 128826.33333333333], + [4610.5, 178624.0], + [10084.334119496856, 128826.33333333333], + [7367.938189845475, 128826.33333333333], + [6065.820895522388, 205300.66666666666], + [7615.237770193402, 128826.33333333333], + [6986.151260504202, 128826.33333333333], + [5.598351845216768, 216.89621516104543], + [7.762388124581156, 107.58701220937135], + [7.762388124581156, 139.61751990148875], + [5.598351845216768, 216.89621516104543], + [7.762388124581156, 99.16371156987148], + [7.762388124581156, 135.72317984130277], + [4.870904786800498, 164.8581481754878], + [7.762388124581156, 131.31566343392103], + [7.762388124581156, 143.14033044967715], + [11987.240518239276, 51102.32738864708], + [8397.288402094997, 54329.26303760978], + [7589.124910361394, 57041.43841888775], + [7248.936669502694, 59421.48106801299], + [6895.814132790256, 61828.04506508371], + [6158.845825601434, 140769.27005379187], + [6151.646622361971, 290457.7858117319], + [6143.623156118695, 431916.7802734375], + [6108.0, 788373.0], + [0.0, 0.1935483870967742], + [0.0, 0.1935483870967742], + [0.0, 0.1935483870967742], + [0.0, 0.1935483870967742], + [0.0, 0.1935483870967742], + [0.0, 0.1935483870967742], + [0.0, 0.1935483870967742], + [0.0, 0.1935483870967742], + [0.0, 0.1935483870967742], + [0.0, 0.1017248463000567], + [0.0, 0.19302357992046917], + [0.0, 0.24128358208341874], + [0.0, 0.2826254852328126], + [0.0, 0.31267985808962173], + [0.0, 0.6188188532135033], + [0.0, 0.6194697204683558], + [0.0, 0.6220486110904144], + [0.0, 0.6666666666666666], + [0.0, 0.6444444444444445], + [0.0, 0.244], + [0.0, 0.38202247191011235], + [0.0, 0.6413043478260869], + [0.0, 0.244], + [0.0, 0.35949764521193095], + [0.0, 0.6024096385542169], + [0.0, 0.27053571428571427], + [0.0, 0.4956140350877193], + [104647.0, 1545893.0], + [19.568580358282478, 83.4220351613403], + [18.406286853325135, 119.08606113260502], + [17.531114707459352, 131.76749780922765], + [16.828930919029332, 137.95126728132996], + [16.173890003271868, 145.01550951683924], + [7.103823154143458, 162.36808459194484], + [3.442841090333785, 162.55810214534762], + [2.3152608226217115, 162.77040023264735], + [1.2684351189094503, 163.71971185330713] +] diff --git a/ratemon/model/tests.py b/ratemon/model/tests.py index f4224c2c..5ff257b3 100755 --- a/ratemon/model/tests.py +++ b/ratemon/model/tests.py @@ -1,24 +1,26 @@ #! /usr/bin/env python3 """ General unit tests. """ +import os +import shlex import shutil import subprocess -import shlex -import unittest -import os -from os import path + # Add the program directory to the system path, in case this script is # being executed from a different directory using "python -m unittest ...". import sys -sys.path.append(path.dirname(path.realpath(__file__))) +import unittest +from os import path +sys.path.append(path.dirname(path.realpath(__file__))) TEST_DATA_DIR = "model/test_data/" LR_MODEL = ( - TEST_DATA_DIR + - "1-3-False-100-2-False-5.0-linear-0.001-10-1-LrSklearn-0.09-False-0-2-l1" + - "-False-None-False-False-9223372036854775807-0-9223372036854775807-0.1" + - "-10-0.pickle") + TEST_DATA_DIR + + "1-3-False-100-2-False-5.0-linear-0.001-10-1-LrSklearn-0.09-False-0-2-l1" + + "-False-None-False-False-9223372036854775807-0-9223372036854775807-0.1" + + "-10-0.pickle" +) SCALE_PARAM = TEST_DATA_DIR + "scale_params.json" SIMULATIONS = TEST_DATA_DIR + "simulations/" EXPERIMENTS = TEST_DATA_DIR + "experiments/" @@ -28,7 +30,7 @@ class TestGeneral(unittest.TestCase): - """ General unit tests. """ + """General unit tests.""" def test_deps(self): """ @@ -37,23 +39,6 @@ def test_deps(self): Implicitly tests that all modules are free of syntax errors. """ - import check_mathis_accuracy - import cl_args - import correlation - import defaults - import fet_hists - import features - import gen_features - import gen_training_data - import graph_one - import hyper - import models - import prepare_data - import sim - import test - import train - import training_param_sweep - import utils def test_parsing(self): """ @@ -64,19 +49,20 @@ def test_parsing(self): "./model/parse_cloudlab.py " f"--exp-dir {EXPERIMENTS} " f"--untar-dir {UNTAR_DIR} " - f"--out-dir {PARSED_EXPERIMENTS}") + f"--out-dir {PARSED_EXPERIMENTS}" + ) split_args = shlex.split(command_line_args) p = subprocess.Popen(split_args) p.wait() - assert(p.returncode == 0) + assert p.returncode == 0 suffix = ".tar.gz" - exp_name = [ - d for d in os.listdir(EXPERIMENTS) if d.endswith(suffix)][0][ - : -len(suffix)] + exp_name = [d for d in os.listdir(EXPERIMENTS) if d.endswith(suffix)][0][ + : -len(suffix) + ] # Check if output files are in parsed_experiments - assert(os.path.exists(PARSED_EXPERIMENTS + f"{exp_name}.npz")) + assert os.path.exists(PARSED_EXPERIMENTS + f"{exp_name}.npz") # Remove files shutil.rmtree(PARSED_EXPERIMENTS) @@ -87,22 +73,23 @@ def test_training_lrsklearn(self): command_line_args = ( f"./model/train.py --data-dir {SIMULATIONS} " f"--model=LrSklearn --out-dir {TEST_OUTPUT_DIR} " - "--num-sims=2 --max-iter=1 --keep-percent=5") + "--num-sims=2 --max-iter=1 --keep-percent=5" + ) split_args = shlex.split(command_line_args) p = subprocess.Popen(split_args) p.wait() - assert(p.returncode == 0) + assert p.returncode == 0 # Check if output files are in test_output model_file = False scale_file = False for fname in os.listdir(TEST_OUTPUT_DIR): - if fname.endswith('.pickle'): + if fname.endswith(".pickle"): model_file = True if fname == "scale_params.json": scale_file = True - assert(model_file and scale_file) + assert model_file and scale_file # Remove files shutil.rmtree(TEST_OUTPUT_DIR) @@ -115,22 +102,23 @@ def test_training_binarydnn(self): f"./model/train.py --data-dir {SIMULATIONS} " f"--model=BinaryDnn --out-dir {TEST_OUTPUT_DIR} " "--num-sims=2 --max-iter=1 --keep-percent=5 " - "--train-batch=10") + "--train-batch=10" + ) split_args = shlex.split(command_line_args) p = subprocess.Popen(split_args) p.wait() - assert(p.returncode == 0) + assert p.returncode == 0 # Check if output files are in test_output model_file = False scale_file = False for fname in os.listdir(TEST_OUTPUT_DIR): - if fname.endswith('.pth'): + if fname.endswith(".pth"): model_file = True if fname == "scale_params.json": scale_file = True - assert(model_file and scale_file) + assert model_file and scale_file # Remove files shutil.rmtree(TEST_OUTPUT_DIR) @@ -142,20 +130,22 @@ def test_evaluation(self): The test should also remove all the files generated from the script. """ - command_line_args = (f"./model/test.py --model {LR_MODEL} " - f"--scale-params {SCALE_PARAM} " - f"--standardize --simulation {SIMULATIONS} " - f"--out-dir {TEST_OUTPUT_DIR}") + command_line_args = ( + f"./model/test.py --model {LR_MODEL} " + f"--scale-params {SCALE_PARAM} " + f"--standardize --simulation {SIMULATIONS} " + f"--out-dir {TEST_OUTPUT_DIR}" + ) split_args = shlex.split(command_line_args) p = subprocess.Popen(split_args) p.wait() - assert(p.returncode == 0) + assert p.returncode == 0 # Check if output files are in test_output - assert(os.path.exists(TEST_OUTPUT_DIR + "results.txt")) - assert(os.path.exists(TEST_OUTPUT_DIR + "queue_vs_accuracy.pdf")) - assert(os.path.exists(TEST_OUTPUT_DIR + "rtt_vs_accuracy.pdf")) - assert(os.path.exists(TEST_OUTPUT_DIR + "bandwidth_vs_accuracy.pdf")) + assert os.path.exists(TEST_OUTPUT_DIR + "results.txt") + assert os.path.exists(TEST_OUTPUT_DIR + "queue_vs_accuracy.pdf") + assert os.path.exists(TEST_OUTPUT_DIR + "rtt_vs_accuracy.pdf") + assert os.path.exists(TEST_OUTPUT_DIR + "bandwidth_vs_accuracy.pdf") # TODO(Ron): Add more file checks here when the other PR is merged in # Remove files diff --git a/ratemon/model/train.py b/ratemon/model/train.py index c38ce546..de973fd4 100755 --- a/ratemon/model/train.py +++ b/ratemon/model/train.py @@ -6,33 +6,32 @@ https://blog.floydhub.com/long-short-term-memory-from-zero-to-hero-with-pytorch/ """ -import logging - -log_flp = "train.log" -print(f"Logging to: {log_flp}") -logging.basicConfig( - filename=log_flp, - filemode="a", - format="%(asctime)s %(levelname)s | %(message)s", - level=logging.DEBUG, -) - import argparse import copy import functools import json +import logging import math import multiprocessing import os -from os import path import pickle import sys import time +from os import path import torch from ratemon.model import cl_args, data, defaults, models, utils +log_flp = "train.log" +print(f"Logging to: {log_flp}") +logging.basicConfig( + filename=log_flp, + filemode="a", + format="%(asctime)s %(levelname)s | %(message)s", + level=logging.DEBUG, +) + # The threshold of the new throughout to the old throughput above which a # a training example will not be considered. I.e., the throughput must have @@ -321,7 +320,8 @@ def run_sklearn(args, out_dir, out_flp, ldrs): dat_in, dat_out, dat_extra, - graph_prms={"out_dir": out_dir, "sort_by_unfairness": True}, # , "dur_s": None}, + # , "dur_s": None}, + graph_prms={"out_dir": out_dir, "sort_by_unfairness": True}, ) logging.info(f"Finished testing - time: {time.time() - tim_srt_s:.2f} seconds") diff --git a/ratemon/model/training_param_sweep.py b/ratemon/model/training_param_sweep.py index 8317668c..facaef3e 100755 --- a/ratemon/model/training_param_sweep.py +++ b/ratemon/model/training_param_sweep.py @@ -5,20 +5,18 @@ import itertools import multiprocessing import os -from os import path import random import shutil import time - -import numpy as np -from matplotlib import pyplot as plt +from os import path import cl_args import defaults import models +import numpy as np import train import utils - +from matplotlib import pyplot as plt # Key to use in the results file. RESULTS_KEY = "results" @@ -48,11 +46,11 @@ def get_partial_results_flp(cnf): - """ Assembles the results filepath for a configuration. """ + """Assembles the results filepath for a configuration.""" return path.join( cnf["out_dir"], - (f"{cnf['num_sims']}_{cnf['keep_percent']}_" - f"{cnf['max_iter']}_results.npz")) + (f"{cnf['num_sims']}_{cnf['keep_percent']}_" f"{cnf['max_iter']}_results.npz"), + ) def maybe_run_cnf(cnf, func): @@ -97,14 +95,14 @@ def cleanup_combine_and_save_results(cnf, res): if len(res) != 5: los_tst, tim_trn_s = res res = np.array( - [cnf["num_sims"], cnf["keep_percent"], cnf["max_iter"], los_tst, - tim_trn_s]) + [cnf["num_sims"], cnf["keep_percent"], cnf["max_iter"], los_tst, tim_trn_s] + ) np.savez_compressed(get_partial_results_flp(cnf), **{RESULTS_KEY: res}) return res def graph(lines, flp, lbl_leg, lbl_x, lbl_y, lim_y=None): - """ Generate a single graph. """ + """Generate a single graph.""" for key, line in sorted(lines.items()): xs, ys = zip(*line) plt.plot(xs, ys, label=f"{key}{lbl_leg}") @@ -120,13 +118,15 @@ def graph(lines, flp, lbl_leg, lbl_x, lbl_y, lim_y=None): def graph_partial_results(cnfs, out_dir): - """ Look for and graph partial results. """ + """Look for and graph partial results.""" results = [] for cnf in cnfs: cnf_out_dir = cnf["out_dir"] results_flps = [ - path.join(cnf_out_dir, fln) for fln in os.listdir(cnf_out_dir) - if fln.endswith("_results.npz")] + path.join(cnf_out_dir, fln) + for fln in os.listdir(cnf_out_dir) + if fln.endswith("_results.npz") + ] assert len(results_flps) <= 1 if results_flps: results_flp = results_flps[0] @@ -140,13 +140,16 @@ def graph_partial_results(cnfs, out_dir): results = [res for res in results if not np.isnan(res).any()] len_after = len(results) print( - (f"Found {len_after} valid results! (Dropped " - f"{len_before - len_after} containing NaNs.)")) + ( + f"Found {len_after} valid results! (Dropped " + f"{len_before - len_after} containing NaNs.)" + ) + ) graph_results(results, out_dir) def graph_results(results, out_dir): - """ Graph the provided results. """ + """Graph the provided results.""" # Vary keep_percent. One graph for each number of iterations. A line for # each number of simulations. # @@ -160,28 +163,32 @@ def graph_results(results, out_dir): num_sims, keep_prc, max_iter, los_tst, tim_trn_s = result if num_sims == num_sims_target and max_iter == max_iters_graph: num_sims_lines[num_sims_target].append( - (keep_prc, los_tst, tim_trn_s)) + (keep_prc, los_tst, tim_trn_s) + ) graph( lines={ key: [(x, 1 - y) for x, y, _ in val] - for key, val in num_sims_lines.items()}, + for key, val in num_sims_lines.items() + }, flp=path.join( - out_dir, - f"max_iters_{max_iters_graph}-vary_keep_percent-accuracy.pdf"), + out_dir, f"max_iters_{max_iters_graph}-vary_keep_percent-accuracy.pdf" + ), lbl_leg=" simulations", lbl_x="Percent kept from each sim", lbl_y="Accuracy", - lim_y=(0, 1)) + lim_y=(0, 1), + ) graph( lines={ - key: [(x, y) for x, _, y in val] - for key, val in num_sims_lines.items()}, + key: [(x, y) for x, _, y in val] for key, val in num_sims_lines.items() + }, flp=path.join( - out_dir, - f"max_iters_{max_iters_graph}-vary_keep_percent-time.pdf"), + out_dir, f"max_iters_{max_iters_graph}-vary_keep_percent-time.pdf" + ), lbl_leg=" simulations", lbl_x="Percent kept from each sim", - lbl_y="Training time (seconds)") + lbl_y="Training time (seconds)", + ) # Vary max_iter. One graph for each number of iterations. A line for # each number of simulations. @@ -196,40 +203,45 @@ def graph_results(results, out_dir): num_sims, keep_prc, max_iter, los_tst, tim_trn_s = result if num_sims == num_sims_graph and keep_prc == keep_prc_target: keep_prc_lines[keep_prc_target].append( - (max_iter, los_tst, tim_trn_s)) + (max_iter, los_tst, tim_trn_s) + ) graph( lines={ key: [(x, 1 - y) for x, y, _ in val] - for key, val in keep_prc_lines.items()}, + for key, val in keep_prc_lines.items() + }, flp=path.join( - out_dir, - f"num_sims_{num_sims_graph}-vary_max_iter-accuracy.pdf"), + out_dir, f"num_sims_{num_sims_graph}-vary_max_iter-accuracy.pdf" + ), lbl_leg="% kept", lbl_x="Number of training iterations", lbl_y="Accuracy", - lim_y=(0, 1)) + lim_y=(0, 1), + ) graph( lines={ - key: [(x, y) for x, _, y in val] - for key, val in keep_prc_lines.items()}, - flp=path.join( - out_dir, - f"num_sims_{num_sims_graph}-vary_max_iter-time.pdf"), + key: [(x, y) for x, _, y in val] for key, val in keep_prc_lines.items() + }, + flp=path.join(out_dir, f"num_sims_{num_sims_graph}-vary_max_iter-time.pdf"), lbl_leg="% kept", lbl_x="Number of training iterations", - lbl_y="Training time (seconds)") + lbl_y="Training time (seconds)", + ) def main(): - """ This program's entrypoint. """ - psr = argparse.ArgumentParser( - description="Visualize sklearn training parameters.") + """This program's entrypoint.""" + psr = argparse.ArgumentParser(description="Visualize sklearn training parameters.") psr, psr_verify = cl_args.add_training(psr) psr.add_argument( - "--graph-results", action="store_true", - help=("Look through the output directory for completed experiments, " - "and graph them.")) + "--graph-results", + action="store_true", + help=( + "Look through the output directory for completed experiments, " + "and graph them." + ), + ) args = psr_verify(psr.parse_args()) args = train.prepare_args(vars(args)) tim_srt_s = time.time() @@ -239,31 +251,46 @@ def main(): # product of their hyper-parameters, which is a heuristic of how # long they will take to run. cnfs = sorted( - [train.prepare_args({ - "warmup_percent": args["warmup_percent"], - "model": args["model"], - "kernel": args["kernel"], - "degree": args["degree"], - "penalty": args["penalty"], - "standardize": args["standardize"], - "no_rand": args["no_rand"], - "max_iter": max_iter, - "keep_percent": prc, - "num_sims": num_sims, - "out_dir": path.join(out_dir, f"{num_sims}_{prc}_{max_iter}") - }) for num_sims, prc, max_iter in set( - # Fix number of iterations and number of - # simulations. Vary percent of each simulation. - list(itertools.product( - NUMS_SIMS, range(PRC_MIN, PRC_MAX + 1, PRC_DELTA), - NUMS_ITERS)) + - # Fix percent of each simulation and number of - # simulations. Vary number of iterations. - list(itertools.product( - NUMS_SIMS, KEEP_PRCS, - range(NUM_ITERS_MIN, NUM_ITERS_MAX + 1, NUM_ITERS_DELTA))))], + [ + train.prepare_args( + { + "warmup_percent": args["warmup_percent"], + "model": args["model"], + "kernel": args["kernel"], + "degree": args["degree"], + "penalty": args["penalty"], + "standardize": args["standardize"], + "no_rand": args["no_rand"], + "max_iter": max_iter, + "keep_percent": prc, + "num_sims": num_sims, + "out_dir": path.join(out_dir, f"{num_sims}_{prc}_{max_iter}"), + } + ) + for num_sims, prc, max_iter in set( + # Fix number of iterations and number of + # simulations. Vary percent of each simulation. + list( + itertools.product( + NUMS_SIMS, range(PRC_MIN, PRC_MAX + 1, PRC_DELTA), NUMS_ITERS + ) + ) + + + # Fix percent of each simulation and number of + # simulations. Vary number of iterations. + list( + itertools.product( + NUMS_SIMS, + KEEP_PRCS, + range(NUM_ITERS_MIN, NUM_ITERS_MAX + 1, NUM_ITERS_DELTA), + ) + ) + ) + ], key=lambda cnf: np.prod( - [cnf["num_sims"], cnf["keep_percent"], cnf["max_iter"]])) + [cnf["num_sims"], cnf["keep_percent"], cnf["max_iter"]] + ), + ) print(f"Will test {len(cnfs)} configurations.") if args["graph_results"]: @@ -273,8 +300,7 @@ def main(): # For each possible configuration of number of simulations and # percentage of each simulation, create a temporary file # containing the parsed data for that configuration. - all_prcs = list(set( - KEEP_PRCS + list(range(PRC_MIN, PRC_MAX + 1, PRC_DELTA)))) + all_prcs = list(set(KEEP_PRCS + list(range(PRC_MIN, PRC_MAX + 1, PRC_DELTA)))) tmp_dat = {} for num_sims, prc in itertools.product(NUMS_SIMS, all_prcs): base_dir = path.join(out_dir, f"{num_sims}_{prc}") @@ -294,20 +320,26 @@ def main(): cnf_out_dir = cnf["out_dir"] if not path.exists(cnf_out_dir): os.makedirs(cnf_out_dir) - tmp_dat_flp, tmp_scl_prms_flp = tmp_dat[ - (cnf["num_sims"], cnf["keep_percent"])] - src_dst.append(( - (tmp_dat_flp, - path.join(cnf_out_dir, path.basename(tmp_dat_flp))), - (tmp_scl_prms_flp, - path.join(cnf_out_dir, path.basename(tmp_scl_prms_flp))))) + tmp_dat_flp, tmp_scl_prms_flp = tmp_dat[(cnf["num_sims"], cnf["keep_percent"])] + src_dst.append( + ( + (tmp_dat_flp, path.join(cnf_out_dir, path.basename(tmp_dat_flp))), + ( + tmp_scl_prms_flp, + path.join(cnf_out_dir, path.basename(tmp_scl_prms_flp)), + ), + ) + ) # Check if any of the data has not been generated yet. If any of # the data has not been generated yet, then we must regenerate all # of the data. - if np.array([ + if np.array( + [ path.exists(dat_dst) and path.exists(scl_prms_dst) - for (_, dat_dst), (_, scl_prms_dst) in src_dst]).all(): + for (_, dat_dst), (_, scl_prms_dst) in src_dst + ] + ).all(): print("All data already generated.") else: print("Generating all new data.") @@ -341,14 +373,16 @@ def main(): random.shuffle(sims) num_sims_actual = len(sims) max_sims = max(NUMS_SIMS) - assert num_sims_actual >= max_sims, \ - (f"Insufficient simulations. Requested {max_sims}, but only " - f"{num_sims_actual} available.") + assert num_sims_actual >= max_sims, ( + f"Insufficient simulations. Requested {max_sims}, but only " + f"{num_sims_actual} available." + ) sims = sims[:max_sims] net = models.MODELS[args["model"]]() sim_args = [ (idx, max_sims, net, sim_flp, out_dir, args["warmup_percent"], 100) - for idx, sim_flp in enumerate(sims)] + for idx, sim_flp in enumerate(sims) + ] if defaults.SYNC: dat_all = [train.process_exp(*sim_args_) for sim_args_ in sim_args] else: @@ -361,8 +395,9 @@ def main(): # trends, we need to make sure that we are training on the # number of simulations that we intend. for dat in dat_all: - assert dat is not None, \ - "Error processing at least one simulation. Check logs (above)." + assert ( + dat is not None + ), "Error processing at least one simulation. Check logs (above)." # Unpack the data. dat_all, sims = zip(*dat_all) dat_all = [utils.load_tmp_file(flp) for flp in dat_all] @@ -376,17 +411,23 @@ def main(): for (num_sims, prc), (tmp_dat_flp, tmp_scl_prms_flp) in tmp_dat.items(): # Select the data corresponding to this number of # simulations and percent of each simulation. - dat_all = list(zip(*utils.filt( - dat_in, dat_out, dat_extra, scl_grps, num_sims, prc))) + dat_all = list( + zip(*utils.filt(dat_in, dat_out, dat_extra, scl_grps, num_sims, prc)) + ) # Finish processesing the data and save it in a form that # can be read by the training process. ignore = train.gen_data( - net, args, dat_flp=tmp_dat_flp, scl_prms_flp=tmp_scl_prms_flp, - dat=(dat_all, sims), save_data=True) + net, + args, + dat_flp=tmp_dat_flp, + scl_prms_flp=tmp_scl_prms_flp, + dat=(dat_all, sims), + save_data=True, + ) del ignore # Copy temporary data to configuration output directories. - for (dat_src, dat_dst), (scl_prms_src, scl_prms_dst) in src_dst: + for (dat_src, dat_dst), (scl_prms_src, scl_prms_dst) in src_dst: shutil.copyfile(dat_src, dat_dst) shutil.copyfile(scl_prms_src, scl_prms_dst) @@ -397,8 +438,7 @@ def main(): shutil.rmtree(tmp_dir) # Train models. - train.run_cnfs( - cnfs, defaults.SYNC, maybe_run_cnf, cleanup_combine_and_save_results) + train.run_cnfs(cnfs, defaults.SYNC, maybe_run_cnf, cleanup_combine_and_save_results) # # Remove real data files. # for cnf in cnfs: diff --git a/ratemon/model/utils.py b/ratemon/model/utils.py index e98ec196..75f94656 100644 --- a/ratemon/model/utils.py +++ b/ratemon/model/utils.py @@ -5,7 +5,6 @@ import logging import math import os -from os import path import pickle import random import socket @@ -15,23 +14,20 @@ import time import zipfile import zlib +from os import path -from matplotlib import pyplot as plt import numpy as np import scapy -import scapy.layers.l2 import scapy.layers.inet +import scapy.layers.l2 import scapy.utils -from scipy import stats -from scipy import cluster -from sklearn import ensemble -from sklearn import feature_selection -from sklearn import inspection import torch +from matplotlib import pyplot as plt +from scipy import cluster, stats +from sklearn import ensemble, feature_selection, inspection from ratemon.model import defaults, features - # Values considered unsafe for division and min(). UNSAFE = {-1, 0, float("inf"), float("NaN")} # The sysctl configuration item for TCP window scaling. diff --git a/ratemon/model/validate_sim.py b/ratemon/model/validate_sim.py index 74268c8a..33427473 100755 --- a/ratemon/model/validate_sim.py +++ b/ratemon/model/validate_sim.py @@ -11,12 +11,10 @@ import os from os import path -from matplotlib import pyplot as plt -import numpy as np - import cl_args +import numpy as np import utils - +from matplotlib import pyplot as plt ARRIVAL_TIME_KEY = "arrival time us" TPUT_KEY = "average throughput p/s-windowed-minRtt32" @@ -25,31 +23,33 @@ def get_avg_tputs(flp): - """ Returns the average throughput for each flow. """ + """Returns the average throughput for each flow.""" with np.load(flp) as fil: return ( utils.Exp(flp), - [utils.safe_mean(fil[flw][TPUT_KEY]) for flw in fil.files]) + [utils.safe_mean(fil[flw][TPUT_KEY]) for flw in fil.files], + ) def plot_f1b(flps, var, out_dir): - """ Generate figure 1b from Ray's paper. """ + """Generate figure 1b from Ray's paper.""" datapoints = [get_avg_tputs(flp) for flp in flps] # Sort the datapoint based on the simulation BDP. datapoints = sorted(datapoints, key=lambda datapoint: datapoint[0].queue_p) sims, all_ys = zip(*datapoints) tot_flws = len(all_ys[0]) - assert tot_flws == 2, \ - ("This figure supports simulations with two flows, but the " - f"provided simulation contains {tot_flws} flows!") + assert tot_flws == 2, ( + "This figure supports simulations with two flows, but the " + f"provided simulation contains {tot_flws} flows!" + ) # Create the x-values by converting each bottleneck queue size # into a multiple of the BDP. x_vals = [ - sim.queue_p / ( - utils.bdp_B(sim.bw_bps, 6 * sim.btl_delay_us / 1e6) / PKT_SIZE_B) - for sim in sims] + sim.queue_p / (utils.bdp_B(sim.bw_bps, 6 * sim.btl_delay_us / 1e6) / PKT_SIZE_B) + for sim in sims + ] plt.figure(figsize=(8, 3)) # Plot a line for each flow. Reverse the flows so that BBR is @@ -62,7 +62,8 @@ def plot_f1b(flps, var, out_dir): # Line with circle markers. "o-", # The first flow is BBR and the second is Cubic. - label=("1 BBR" if idx == 0 else f"1 {var}")) + label=("1 BBR" if idx == 0 else f"1 {var}"), + ) plt.xscale("log", basex=2) plt.xticks(x_vals, [f"{x:.2f}" if x < 1 else str(round(x)) for x in x_vals]) @@ -76,18 +77,20 @@ def plot_f1b(flps, var, out_dir): def plot_f1c(flps, var, out_dir): - """ Generate figure 1c from Ray's paper. """ + """Generate figure 1c from Ray's paper.""" tot_flps = len(flps) - assert tot_flps == 1, \ - f"This figure uses a single experiment, but {tot_flps} were provided." + assert ( + tot_flps == 1 + ), f"This figure uses a single experiment, but {tot_flps} were provided." flp = flps[0] - sim = utils.Exp(flp) + utils.Exp(flp) x_vals = np.arange(300 * 1000, dtype=float) / 1000 with np.load(flp) as fil: tot_flws = len(fil.files) - assert tot_flws == 17, \ - ("This figure supports simulations with 17 flows, but the " - f"provided simulation contains {tot_flws} flows!") + assert tot_flws == 17, ( + "This figure supports simulations with 17 flows, but the " + f"provided simulation contains {tot_flws} flows!" + ) tputs = [] for flw in range(tot_flws): dat = fil[str(flw)][[ARRIVAL_TIME_KEY, TPUT_KEY]] @@ -100,7 +103,9 @@ def plot_f1c(flps, var, out_dir): # Convert from us to s. xp=dat[ARRIVAL_TIME_KEY] / 1e6, # Convert from packets/second to Mbps. - fp=dat[TPUT_KEY] * PKT_SIZE_B * 8 / 1e6)) + fp=dat[TPUT_KEY] * PKT_SIZE_B * 8 / 1e6, + ) + ) # The 16 Cubic flows are first. Add up the throughputs of all of # the Cubic flows. @@ -120,23 +125,26 @@ def plot_f1c(flps, var, out_dir): def main(): - """ This program's entrypoint. """ + """This program's entrypoint.""" # Parse command line arguments. - psr = argparse.ArgumentParser( - description="Visualize a simulation's features.") + psr = argparse.ArgumentParser(description="Visualize a simulation's features.") psr.add_argument( "--f1b", - help=("The path to a directory contained parsed data files for figure " - "1b."), - required=True, type=str) + help=("The path to a directory contained parsed data files for figure " "1b."), + required=True, + type=str, + ) psr.add_argument( "--f1c", - help=("The path to a directory containing a parsed data file for figure " - "1c."), - required=True, type=str) + help=( + "The path to a directory containing a parsed data file for figure " "1c." + ), + required=True, + type=str, + ) psr.add_argument( - "--variant", help="The TCP variant competing with BBR.", required=True, - type=str) + "--variant", help="The TCP variant competing with BBR.", required=True, type=str + ) psr, psr_verify = cl_args.add_out(psr) args = psr_verify(psr.parse_args()) f1b = args.f1b diff --git a/ratemon/runtime/c/experimental/client_server/client.c b/ratemon/runtime/c/experimental/client_server/client.c index b50870ff..50f86dc5 100644 --- a/ratemon/runtime/c/experimental/client_server/client.c +++ b/ratemon/runtime/c/experimental/client_server/client.c @@ -1,13 +1,13 @@ -#include // structure for storing address information +#include // structure for storing address information #include #include -#include // for socket APIs +#include // for socket APIs #include -#include // for close() +#include // for close() #include "common.h" -int main(int argc, char const* argv[]) { +int main(int argc, char const *argv[]) { int sockD = socket(AF_INET, SOCK_STREAM, 0); if (sockD == -1) { printf("Error in creating socket\n"); @@ -16,10 +16,10 @@ int main(int argc, char const* argv[]) { struct sockaddr_in servAddr; servAddr.sin_family = AF_INET; - servAddr.sin_port = htons(SERVER_PORT); // use some unused port number + servAddr.sin_port = htons(SERVER_PORT); // use some unused port number servAddr.sin_addr.s_addr = INADDR_ANY; - if (connect(sockD, (struct sockaddr*)&servAddr, sizeof(servAddr)) == -1) { + if (connect(sockD, (struct sockaddr *)&servAddr, sizeof(servAddr)) == -1) { printf("Error in connecting\n"); return 1; } diff --git a/ratemon/runtime/c/experimental/client_server/common.h b/ratemon/runtime/c/experimental/client_server/common.h index c7477080..156e2454 100644 --- a/ratemon/runtime/c/experimental/client_server/common.h +++ b/ratemon/runtime/c/experimental/client_server/common.h @@ -1,3 +1,4 @@ +#pragma once #ifndef __RATEMON_COMMON_H #define __RATEMON_COMMON_H diff --git a/ratemon/runtime/c/experimental/client_server/libinterptest.c b/ratemon/runtime/c/experimental/client_server/libinterptest.c index 5bea0436..a0287f24 100644 --- a/ratemon/runtime/c/experimental/client_server/libinterptest.c +++ b/ratemon/runtime/c/experimental/client_server/libinterptest.c @@ -1,10 +1,10 @@ #define _GNU_SOURCE #include -#include // structure for storing address information +#include // structure for storing address information #include #include #include -#include // for socket APIs +#include // for socket APIs int storedSockFd = 0; diff --git a/ratemon/runtime/c/experimental/client_server/libinterptest_cpp.cpp b/ratemon/runtime/c/experimental/client_server/libinterptest_cpp.cpp index 3c2f7bfc..dba381d9 100644 --- a/ratemon/runtime/c/experimental/client_server/libinterptest_cpp.cpp +++ b/ratemon/runtime/c/experimental/client_server/libinterptest_cpp.cpp @@ -4,12 +4,12 @@ #include #include -#include // structure for storing address information +#include // structure for storing address information #include #include #include #include -#include // for socket APIs +#include // for socket APIs #include #include diff --git a/ratemon/runtime/c/experimental/client_server/server.c b/ratemon/runtime/c/experimental/client_server/server.c index 8bebb21a..535aa5b1 100644 --- a/ratemon/runtime/c/experimental/client_server/server.c +++ b/ratemon/runtime/c/experimental/client_server/server.c @@ -1,13 +1,13 @@ -#include // structure for storing address information +#include // structure for storing address information #include #include -#include // for socket APIs +#include // for socket APIs #include -#include // for close() +#include // for close() #include "common.h" -int main(int argc, char const* argv[]) { +int main(int argc, char const *argv[]) { // create server socket similar to what was done in // client program int servSockD = socket(AF_INET, SOCK_STREAM, 0); @@ -22,9 +22,8 @@ int main(int argc, char const* argv[]) { } // string store data to send to client - const char serMsg[255] = - "Message from the server to the " - "client \'Hello Client\' "; + const char serMsg[255] = "Message from the server to the " + "client \'Hello Client\' "; // define server address struct sockaddr_in servAddr; @@ -33,7 +32,7 @@ int main(int argc, char const* argv[]) { servAddr.sin_addr.s_addr = INADDR_ANY; // bind socket to the specified IP and port - if (bind(servSockD, (struct sockaddr*)&servAddr, sizeof(servAddr)) == -1) { + if (bind(servSockD, (struct sockaddr *)&servAddr, sizeof(servAddr)) == -1) { printf("Error in binding\n"); return 1; } diff --git a/ratemon/runtime/c/experimental/ratemon_test.bpf.c b/ratemon/runtime/c/experimental/ratemon_test.bpf.c index 92859bc3..ad25f698 100644 --- a/ratemon/runtime/c/experimental/ratemon_test.bpf.c +++ b/ratemon/runtime/c/experimental/ratemon_test.bpf.c @@ -105,7 +105,8 @@ SEC("tp/syscalls/sys_enter_write") int handle_tp(void *ctx) { int pid = bpf_get_current_pid_tgid() >> 32; - if (pid != my_pid) return 0; + if (pid != my_pid) + return 0; u64 t = bpf_ktime_get_ns(); bpf_map_update_elem(&test_map_1, &t, &pid, BPF_ANY); @@ -132,7 +133,8 @@ int test_iter_1(struct bpf_iter__bpf_map_elem *ctx) { u64 *key = ctx->key; int *val = ctx->value; - if (key == NULL || val == NULL) return 0; + if (key == NULL || val == NULL) + return 0; // bpf_printk("test_map_1: seq_num: %u, key %lu, value %d", seq_num, *key, // *val); @@ -149,7 +151,8 @@ int test_iter_2(struct bpf_iter__bpf_map_elem *ctx) { u32 *key = ctx->key; u64 *val = ctx->value; - if (key == NULL || val == NULL) return 0; + if (key == NULL || val == NULL) + return 0; // bpf_printk("test_map_2: seq_num: %u, key %u, value %lu", seq_num, *key, // *val); @@ -162,9 +165,11 @@ int test_iter_2(struct bpf_iter__bpf_map_elem *ctx) { SEC("sockops") int skops_getsockopt(struct bpf_sock_ops *skops) { bpf_printk("skops_getsockops"); - if (skops == NULL) return 1; + if (skops == NULL) + return 1; bpf_printk("%u skops_getsockops", skops->local_port); - if (!(skops->local_port == 50000 || skops->local_port == 50001)) return 1; + if (!(skops->local_port == 50000 || skops->local_port == 50001)) + return 1; // struct bpf_sock *sk = skops->sk; // if (sk == NULL) { @@ -188,35 +193,35 @@ int skops_getsockopt(struct bpf_sock_ops *skops) { } switch (skops->op) { - case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: - case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: { - bpf_printk("skops_getsockops set flag BPF_SOCK_OPS_RTT_CB_FLAG"); - bpf_sock_ops_cb_flags_set(skops, BPF_SOCK_OPS_RTT_CB_FLAG); - // struct tcp_info info; - // // socklen_t optlen = sizeof(info); - - // long e = bpf_getsockopt(skops, SOL_TCP, TCP_INFO, &info, sizeof(info)); - // if (e < 0) { - // bpf_printk("Failed to lookup TCP stats"); - // } else { - // bpf_printk("tcp_info snd_cwnd: %u snd_wnd: %u min_rtt: %u", - // info.tcpi_snd_cwnd, info.tcpi_snd_wnd, info.tcpi_min_rtt); - // } - break; - } - case BPF_SOCK_OPS_RTT_CB: { - bpf_printk("skops_getsockops in BPF_SOCK_OPS_RTT_CB"); - // struct tcp_info info; - // // socklen_t optlen = sizeof(info); - // long e = bpf_getsockopt(skops, SOL_TCP, TCP_INFO, &info, sizeof(info)); - // if (e < 0) { - // bpf_printk("Failed to lookup TCP stats"); - // } else { - // bpf_printk("tcp_info snd_cwnd: %u snd_wnd: %u min_rtt: %u", - // info.tcpi_snd_cwnd, info.tcpi_snd_wnd, info.tcpi_min_rtt); - // } - break; - } + case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: + case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: { + bpf_printk("skops_getsockops set flag BPF_SOCK_OPS_RTT_CB_FLAG"); + bpf_sock_ops_cb_flags_set(skops, BPF_SOCK_OPS_RTT_CB_FLAG); + // struct tcp_info info; + // // socklen_t optlen = sizeof(info); + + // long e = bpf_getsockopt(skops, SOL_TCP, TCP_INFO, &info, sizeof(info)); + // if (e < 0) { + // bpf_printk("Failed to lookup TCP stats"); + // } else { + // bpf_printk("tcp_info snd_cwnd: %u snd_wnd: %u min_rtt: %u", + // info.tcpi_snd_cwnd, info.tcpi_snd_wnd, info.tcpi_min_rtt); + // } + break; + } + case BPF_SOCK_OPS_RTT_CB: { + bpf_printk("skops_getsockops in BPF_SOCK_OPS_RTT_CB"); + // struct tcp_info info; + // // socklen_t optlen = sizeof(info); + // long e = bpf_getsockopt(skops, SOL_TCP, TCP_INFO, &info, sizeof(info)); + // if (e < 0) { + // bpf_printk("Failed to lookup TCP stats"); + // } else { + // bpf_printk("tcp_info snd_cwnd: %u snd_wnd: %u min_rtt: %u", + // info.tcpi_snd_cwnd, info.tcpi_snd_wnd, info.tcpi_min_rtt); + // } + break; + } } return 1; } @@ -285,7 +290,8 @@ int test_iter_3(struct bpf_iter__bpf_map_elem *ctx) { u32 *key = ctx->key; struct tcp_sock **val = ctx->value; - if (key == NULL || val == NULL) return 0; + if (key == NULL || val == NULL) + return 0; u32 r = 0; BPF_CORE_READ_INTO(&r, *val, rcv_nxt); @@ -616,7 +622,7 @@ int test_iter_set_await(struct bpf_iter__bpf_map_elem *ctx) { return 0; } -#define from_timer(var, callback_timer, timer_fieldname) \ +#define from_timer(var, callback_timer, timer_fieldname) \ container_of(callback_timer, typeof(*var), timer_fieldname) SEC("kprobe/tcp_keepalive_timer") diff --git a/ratemon/runtime/c/experimental/ratemon_test.c b/ratemon/runtime/c/experimental/ratemon_test.c index dae6bdfa..773c3502 100644 --- a/ratemon/runtime/c/experimental/ratemon_test.c +++ b/ratemon/runtime/c/experimental/ratemon_test.c @@ -47,7 +47,7 @@ static int libbpf_print_fn(enum libbpf_print_level level, const char *format, #define CGROUP_MOUNT_PATH "/mnt/cgroup-test-work-dir" -#define format_cgroup_path(buf, path) \ +#define format_cgroup_path(buf, path) \ snprintf(buf, sizeof(buf), "%s/%s", CGROUP_MOUNT_PATH, path) /** @@ -82,7 +82,8 @@ static int enable_all_controllers(char *cgroup_path) { close(fd); /* No controllers available? We're probably on cgroup v1. */ - if (len == 0) return 0; + if (len == 0) + return 0; snprintf(path, sizeof(path), "%s/cgroup.subtree_control", cgroup_path); cfd = open(path, O_RDWR); @@ -530,10 +531,9 @@ int main(int argc, char **argv) { goto cleanup; } - printf( - "Successfully started! Please run `sudo cat " - "/sys/kernel/debug/tracing/trace_pipe` " - "to see output of the BPF programs.\n"); + printf("Successfully started! Please run `sudo cat " + "/sys/kernel/debug/tracing/trace_pipe` " + "to see output of the BPF programs.\n"); for (;;) { /* trigger our BPF program */ @@ -618,10 +618,14 @@ int main(int argc, char **argv) { } cleanup: - if (iter_fd_1) close(iter_fd_1); - if (iter_fd_2) close(iter_fd_2); - if (iter_fd_3) close(iter_fd_3); - if (iter_fd_4) close(iter_fd_4); + if (iter_fd_1) + close(iter_fd_1); + if (iter_fd_2) + close(iter_fd_2); + if (iter_fd_3) + close(iter_fd_3); + if (iter_fd_4) + close(iter_fd_4); ratemon_test_bpf__destroy(skel); return -err; } diff --git a/ratemon/runtime/c/experimental/ratemon_test.h b/ratemon/runtime/c/experimental/ratemon_test.h index 3adf8e27..0f4d1987 100644 --- a/ratemon/runtime/c/experimental/ratemon_test.h +++ b/ratemon/runtime/c/experimental/ratemon_test.h @@ -1,3 +1,4 @@ +#pragma once /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ #ifndef __RATEMON_TEST_H diff --git a/ratemon/runtime/c/libratemon_interp.cpp b/ratemon/runtime/c/libratemon_interp.cpp index f78684d1..acdddca1 100644 --- a/ratemon/runtime/c/libratemon_interp.cpp +++ b/ratemon/runtime/c/libratemon_interp.cpp @@ -7,13 +7,13 @@ #include #include #include -#include // structure for storing address information +#include // structure for storing address information #include #include #include #include #include -#include // for socket APIs +#include // for socket APIs #include #include @@ -200,7 +200,8 @@ void timer_callback(const boost::system::error_code &error) { a = active_fds_queue.front(); active_fds_queue.pop(); // 1.1) If this flow has been closed, remove it. - if (!fd_to_flow.contains(a.first)) continue; + if (!fd_to_flow.contains(a.first)) + continue; // 1.2) If idle timeout mode is enabled, then check if this flow is // past its idle timeout. Skip this check if there are no paused // flows. @@ -279,7 +280,8 @@ void timer_callback(const boost::system::error_code &error) { p = paused_fds_queue.front(); paused_fds_queue.pop(); // If this flow has been closed, then skip it. - if (!fd_to_flow.contains(p)) continue; + if (!fd_to_flow.contains(p)) + continue; // If this flow is not in the flow_to_keepalive map (bpf_map_lookup_elem() // returns negative error code when the flow is not found), then it has no // pending data and should be skipped. @@ -352,9 +354,8 @@ void timer_callback(const boost::system::error_code &error) { RM_PRINTF("INFO: scheduling timer for next idle timeout\n"); when = boost::posix_time::microsec(idle_timeout_us); } else { - RM_PRINTF( - "INFO: scheduling timer for next epoch end, sooner than idle " - "timeout\n"); + RM_PRINTF("INFO: scheduling timer for next epoch end, sooner than idle " + "timeout\n"); when = boost::posix_time::microsec(next_epoch_us); } @@ -386,7 +387,8 @@ void thread_func() { // Delete all flows from flow_to_rwnd and flow_to_win_scale. lock_scheduler.lock(); for (const auto &p : fd_to_flow) { - if (flow_to_rwnd_fd) bpf_map_delete_elem(flow_to_rwnd_fd, &p.second); + if (flow_to_rwnd_fd) + bpf_map_delete_elem(flow_to_rwnd_fd, &p.second); if (flow_to_win_scale_fd) bpf_map_delete_elem(flow_to_win_scale_fd, &p.second); if (flow_to_last_data_time_fd) @@ -398,25 +400,24 @@ void thread_func() { RM_PRINTF("INFO: scheduler thread ended\n"); if (run) { - RM_PRINTF( - "ERROR: scheduled thread ended before program was signalled to " - "stop\n"); + RM_PRINTF("ERROR: scheduled thread ended before program was signalled to " + "stop\n"); } } // Catch SIGINT and trigger the scheduler thread and timer to end. void sigint_handler(int signum) { switch (signum) { - case SIGINT: - RM_PRINTF("INFO: caught SIGINT\n"); - run = false; - scheduler_thread.join(); - RM_PRINTF("INFO: resetting old SIGINT handler\n"); - sigaction(SIGINT, &oldact, NULL); - break; - default: - RM_PRINTF("ERROR: caught signal %d\n", signum); - break; + case SIGINT: + RM_PRINTF("INFO: caught SIGINT\n"); + run = false; + scheduler_thread.join(); + RM_PRINTF("INFO: resetting old SIGINT handler\n"); + sigaction(SIGINT, &oldact, NULL); + break; + default: + RM_PRINTF("ERROR: caught signal %d\n", signum); + break; } RM_PRINTF("INFO: re-raising signal %d\n", signum); raise(signum); @@ -448,8 +449,10 @@ bool read_env_uint(const char *key, volatile unsigned int *dest, // flow_to_rwnd. bool setup() { // Read environment variables with parameters. - if (!read_env_uint(RM_MAX_ACTIVE_FLOWS_KEY, &max_active_flows)) return false; - if (!read_env_uint(RM_EPOCH_US_KEY, &epoch_us)) return false; + if (!read_env_uint(RM_MAX_ACTIVE_FLOWS_KEY, &max_active_flows)) + return false; + if (!read_env_uint(RM_EPOCH_US_KEY, &epoch_us)) + return false; unsigned int idle_timeout_us_; if (!read_env_uint(RM_IDLE_TIMEOUT_US_KEY, &idle_timeout_us_, true /* allow_zero */)) @@ -504,10 +507,9 @@ bool setup() { // BPF skeleton for this. err = bpf_obj_get(RM_FLOW_TO_KEEPALIVE_PIN_PATH); if (err == -1) { - RM_PRINTF( - "ERROR: failed to get FD for 'flow_to_keepalive' from path " - "'%s'\n", - RM_FLOW_TO_KEEPALIVE_PIN_PATH); + RM_PRINTF("ERROR: failed to get FD for 'flow_to_keepalive' from path " + "'%s'\n", + RM_FLOW_TO_KEEPALIVE_PIN_PATH); return false; } flow_to_keepalive_fd = err; @@ -522,11 +524,10 @@ bool setup() { // Launch the scheduler thread. scheduler_thread = boost::thread(thread_func); - RM_PRINTF( - "INFO: setup complete! max_active_flows=%u, epoch_us=%u, " - "idle_timeout_ns=%lu, monitor_port_start=%u, monitor_port_end=%u\n", - max_active_flows, epoch_us, idle_timeout_ns, monitor_port_start, - monitor_port_end); + RM_PRINTF("INFO: setup complete! max_active_flows=%u, epoch_us=%u, " + "idle_timeout_ns=%lu, monitor_port_start=%u, monitor_port_end=%u\n", + max_active_flows, epoch_us, idle_timeout_ns, monitor_port_start, + monitor_port_end); return true; } @@ -631,7 +632,8 @@ int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { } // If we have been signalled to quit, then do nothing more. - if (!run) return fd; + if (!run) + return fd; // One-time setup. lock_setup.lock(); if (!setup_done) { @@ -644,7 +646,8 @@ int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { lock_setup.unlock(); // Look up the four-tuple. struct rm_flow flow; - if (!get_flow(fd, &flow)) return fd; + if (!get_flow(fd, &flow)) + return fd; RM_PRINTF("flow: %u:%u->%u:%u\n", flow.remote_addr, flow.remote_port, flow.local_addr, flow.local_port); // Ignore flows that are not in the monitor port range. @@ -658,7 +661,8 @@ int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { } fd_to_flow[fd] = flow; // Change the CCA to BPF_CUBIC. - if (!set_cca(fd, RM_BPF_CUBIC)) return fd; + if (!set_cca(fd, RM_BPF_CUBIC)) + return fd; // Initial scheduling for this flow. lock_scheduler.lock(); initial_scheduling(fd); diff --git a/ratemon/runtime/c/ratemon.h b/ratemon/runtime/c/ratemon.h index a9393df6..741694e2 100644 --- a/ratemon/runtime/c/ratemon.h +++ b/ratemon/runtime/c/ratemon.h @@ -1,3 +1,4 @@ +#pragma once // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause #ifndef __RATEMON_H @@ -10,7 +11,7 @@ #define RM_PRINTF(...) printf(__VA_ARGS__) // #define RM_PRINTK(...) bpf_printk(__VA_ARGS__) #else -#define NDEBUG // Disable assert() calls. +#define NDEBUG // Disable assert() calls. #define RM_PRINTF(...) // #define RM_PRINTK(...) #endif @@ -20,7 +21,7 @@ // Map pin paths. #define RM_FLOW_TO_RWND_PIN_PATH "/sys/fs/bpf/flow_to_rwnd" #define RM_FLOW_TO_WIN_SCALE_PIN_PATH "/sys/fs/bpf/flow_to_win_scale" -#define RM_FLOW_TO_LAST_DATA_TIME_PIN_PATH \ +#define RM_FLOW_TO_LAST_DATA_TIME_PIN_PATH \ "/sys/fs/bpf/flow_to_last_data_time_ns" #define RM_FLOW_TO_KEEPALIVE_PIN_PATH "/sys/fs/bpf/flow_to_keepalive" // Name of struct_ops CCA that flows must use to be woken up. diff --git a/ratemon/runtime/c/ratemon_kprobe.bpf.c b/ratemon/runtime/c/ratemon_kprobe.bpf.c index f25a263c..068aa528 100644 --- a/ratemon/runtime/c/ratemon_kprobe.bpf.c +++ b/ratemon/runtime/c/ratemon_kprobe.bpf.c @@ -102,9 +102,8 @@ int BPF_KPROBE(tcp_rcv_established, struct sock *sk, struct sk_buff *skb) { unsigned long now_ns = bpf_ktime_get_ns(); if (bpf_map_update_elem(&flow_to_last_data_time_ns, &flow, &now_ns, BPF_ANY)) { - bpf_printk( - "ERROR: 'tcp_rcv_established' error updating " - "flow_to_last_data_time_ns"); + bpf_printk("ERROR: 'tcp_rcv_established' error updating " + "flow_to_last_data_time_ns"); } return 0; } diff --git a/ratemon/runtime/c/ratemon_main.c b/ratemon/runtime/c/ratemon_main.c index 20d2930d..c21db873 100644 --- a/ratemon/runtime/c/ratemon_main.c +++ b/ratemon/runtime/c/ratemon_main.c @@ -37,15 +37,15 @@ static int libbpf_print_fn(enum libbpf_print_level level, const char *format, // Catch SIGINT and trigger the main function to end. void sigint_handler(int signum) { switch (signum) { - case SIGINT: - printf("INFO: caught SIGINT\n"); - run = false; - printf("Resetting old SIGINT handler\n"); - sigaction(SIGINT, &oldact, NULL); - break; - default: - printf("ERROR: caught signal %d\n", signum); - break; + case SIGINT: + printf("INFO: caught SIGINT\n"); + run = false; + printf("Resetting old SIGINT handler\n"); + sigaction(SIGINT, &oldact, NULL); + break; + default: + printf("ERROR: caught signal %d\n", signum); + break; } printf("INFO: re-raising signal %d\n", signum); raise(signum); @@ -179,13 +179,13 @@ int main(int argc, char **argv) { goto cleanup; } - printf( - "INFO: BPF programs running. " - "Progress: `sudo cat /sys/kernel/debug/tracing/trace_pipe`. " - "Ctrl-C to end.\n"); + printf("INFO: BPF programs running. " + "Progress: `sudo cat /sys/kernel/debug/tracing/trace_pipe`. " + "Ctrl-C to end.\n"); // Wait for Ctrl-C. - while (run) sleep(1); + while (run) + sleep(1); cleanup: printf("Destroying BPF programs\n"); diff --git a/ratemon/runtime/c/ratemon_maps.h b/ratemon/runtime/c/ratemon_maps.h index 1f2c11fd..28527b2d 100644 --- a/ratemon/runtime/c/ratemon_maps.h +++ b/ratemon/runtime/c/ratemon_maps.h @@ -1,3 +1,4 @@ +#pragma once // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause #ifndef __RATEMON_MAPS_H @@ -41,7 +42,8 @@ struct { __uint(pinning, LIBBPF_PIN_BY_NAME); } flow_to_last_data_time_ns SEC(".maps"); -// Flows in this map have received a recent keepalive and have not gone idle since, so they are considered to be active. +// Flows in this map have received a recent keepalive and have not gone idle +// since, so they are considered to be active. struct { __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, RM_MAX_FLOWS); diff --git a/ratemon/runtime/c/ratemon_sockops.bpf.c b/ratemon/runtime/c/ratemon_sockops.bpf.c index 17efe421..61fe164a 100644 --- a/ratemon/runtime/c/ratemon_sockops.bpf.c +++ b/ratemon/runtime/c/ratemon_sockops.bpf.c @@ -153,12 +153,12 @@ __always_inline int handle_write_hdr_opt(struct bpf_sock_ops *skops) { SEC("sockops") int read_win_scale(struct bpf_sock_ops *skops) { switch (skops->op) { - case BPF_SOCK_OPS_TCP_LISTEN_CB: - return enable_hdr_cbs(skops); - case BPF_SOCK_OPS_HDR_OPT_LEN_CB: - return handle_hdr_opt_len(skops); - case BPF_SOCK_OPS_WRITE_HDR_OPT_CB: - return handle_write_hdr_opt(skops); + case BPF_SOCK_OPS_TCP_LISTEN_CB: + return enable_hdr_cbs(skops); + case BPF_SOCK_OPS_HDR_OPT_LEN_CB: + return handle_hdr_opt_len(skops); + case BPF_SOCK_OPS_WRITE_HDR_OPT_CB: + return handle_write_hdr_opt(skops); } return SOCKOPS_OK; } \ No newline at end of file diff --git a/ratemon/runtime/python/ebpf.py b/ratemon/runtime/python/ebpf.py index d71e9c00..7be9331b 100644 --- a/ratemon/runtime/python/ebpf.py +++ b/ratemon/runtime/python/ebpf.py @@ -1,10 +1,10 @@ import logging import os -from os import path import time +from os import path -from bcc import BPF, BPFAttachType, BPFProgType import numpy as np +from bcc import BPF, BPFAttachType, BPFProgType from pyroute2 import IPRoute, protocols from pyroute2.netlink.exceptions import NetlinkError @@ -33,7 +33,8 @@ def configure_ebpf(args): # instances of this program do not try to configure themselves at the same # time. rand_sleep = min(args.listen_ports) - 50000 - logging.info("Waiting %f seconds to prevent race conditions...", rand_sleep) + logging.info( + "Waiting %f seconds to prevent race conditions...", rand_sleep) time.sleep(rand_sleep) try: @@ -59,7 +60,8 @@ def configure_ebpf(args): try: ipr.tc("add", "htb", ifindex, handle, default=default) except NetlinkError: - logging.warning("Unable to create central qdisc. It probably already exists.") + logging.warning( + "Unable to create central qdisc. It probably already exists.") else: logging.info("Responsible for central TC") responsible_for_central_tc = True @@ -77,22 +79,23 @@ def configure_ebpf(args): # Overwrite advertised window size in outgoing packets. egress_fn = bpf.load_func("do_rwnd_at_egress", BPF.SCHED_ACT) - action = dict(kind="bpf", fd=egress_fn.fd, name=egress_fn.name, action="ok") + action = dict(kind="bpf", fd=egress_fn.fd, + name=egress_fn.name, action="ok") # int prog_fd; - prod_fd = bpf.load_func("bpf_iter__task", BPFProgtype.TRACING); - int link_fd = bcc_iter_attach(prog_fd, NULL, 0); + prod_fd = bpf.load_func("bpf_iter__task", BPFProgtype.TRACING) + int link_fd = bcc_iter_attach(prog_fd, NULL, 0) if (link_fd < 0) { - std::cerr << "bcc_iter_attach failed: " << link_fd << std::endl; - return 1; + std: : cerr << "bcc_iter_attach failed: " << link_fd << std: : endl + return 1 } - int iter_fd = bcc_iter_create(link_fd); + int iter_fd = bcc_iter_create(link_fd) if (iter_fd < 0) { - std::cerr << "bcc_iter_create failed: " << iter_fd << std::endl; - close(link_fd); - return 1; + std: : cerr << "bcc_iter_create failed: " << iter_fd << std: : endl + close(link_fd) + return 1 } try: diff --git a/ratemon/runtime/python/pacing_notes.py b/ratemon/runtime/python/pacing_notes.py index e79cecbd..733dbaa0 100644 --- a/ratemon/runtime/python/pacing_notes.py +++ b/ratemon/runtime/python/pacing_notes.py @@ -1,7 +1,5 @@ """This module contains functionality related to packing ACKs.""" -import pyroute2 - # # # @@ -16,7 +14,6 @@ # - current fairness mitigation state: yes or no # - if yes, information about current action: pacing rate, TC filter info, etc. - # tc qdisc add dev lo root handle 1: htb default 30 # tc class add dev lo parent 1:0 classid 1:1 htb rate 1gbit burst 10m @@ -32,7 +29,6 @@ # tc filter add dev lo protocol ip parent 1:0 prio 1 u32 match ip src 2.4.6.8/32 match ip sport 3453 match ip dst 1.2.3.4/32 match ip dport 9998 0xffff flowid 1:10 # tc filter add dev lo protocol ip parent 1:0 prio 1 u32 match ip src 2.4.6.8/32 match ip sport 3454 match ip dst 4.3.2.1/32 match ip dport 9999 0xffff flowid 1:20 - # An example with htb qdisc, lets assume eth0 == 2:: # # u32 --> +--> htb 1:10 --> sfq 10:0 @@ -92,4 +88,4 @@ def add_tc(): ipr = IPRoute() - ipr.tc("add", "") \ No newline at end of file + ipr.tc("add", "") diff --git a/ratemon/runtime/python/policies.py b/ratemon/runtime/python/policies.py index 49891f73..8981a771 100644 --- a/ratemon/runtime/python/policies.py +++ b/ratemon/runtime/python/policies.py @@ -1,9 +1,9 @@ """Different types of receiver policy, depending on workload.""" -from enum import IntEnum import logging +from enum import IntEnum -from ratemon.model import defaults, models, features, utils +from ratemon.model import defaults, features, models, utils from ratemon.runtime.python import reaction_strategy diff --git a/ratemon/runtime/python/ratemon_runtime.c b/ratemon/runtime/python/ratemon_runtime.c index 2ef6e42b..8ee12878 100644 --- a/ratemon/runtime/python/ratemon_runtime.c +++ b/ratemon/runtime/python/ratemon_runtime.c @@ -205,47 +205,47 @@ static inline int handle_write_hdr_opt(struct bpf_sock_ops *skops) { if (ret != 3 || win_scale_opt.len != 3 || win_scale_opt.kind != TCPOPT_WINDOW) { switch (ret) { - case -ENOMSG: - bpf_trace_printk( - "Error: Failure loading window scale option for flow on local port " - "%u: -ENOMSG\n", - skops->local_port); - break; - case -EINVAL: - bpf_trace_printk( - "Error: Failure loading window scale option for flow on local port " - "%u: -EINVAL\n", - skops->local_port); - break; - case -ENOENT: - bpf_trace_printk( - "Error: Failure loading window scale option for flow on local port " - "%u: -ENOENT\n", - skops->local_port); - break; - case -ENOSPC: - bpf_trace_printk( - "Error: Failure loading window scale option for flow on local port " - "%u: -ENOSPC\n", - skops->local_port); - break; - case -EFAULT: - bpf_trace_printk( - "Error: Failure loading window scale option for flow on local port " - "%u: -EFAULT\n", - skops->local_port); - break; - case -EPERM: - bpf_trace_printk( - "Error: Failure loading window scale option for flow on local port " - "%u: -EPERM\n", - skops->local_port); - break; - default: - bpf_trace_printk( - "Error: Failure loading window scale option for flow on local port " - "%u: failure code = %d\n", - skops->local_port, ret); + case -ENOMSG: + bpf_trace_printk( + "Error: Failure loading window scale option for flow on local port " + "%u: -ENOMSG\n", + skops->local_port); + break; + case -EINVAL: + bpf_trace_printk( + "Error: Failure loading window scale option for flow on local port " + "%u: -EINVAL\n", + skops->local_port); + break; + case -ENOENT: + bpf_trace_printk( + "Error: Failure loading window scale option for flow on local port " + "%u: -ENOENT\n", + skops->local_port); + break; + case -ENOSPC: + bpf_trace_printk( + "Error: Failure loading window scale option for flow on local port " + "%u: -ENOSPC\n", + skops->local_port); + break; + case -EFAULT: + bpf_trace_printk( + "Error: Failure loading window scale option for flow on local port " + "%u: -EFAULT\n", + skops->local_port); + break; + case -EPERM: + bpf_trace_printk( + "Error: Failure loading window scale option for flow on local port " + "%u: -EPERM\n", + skops->local_port); + break; + default: + bpf_trace_printk( + "Error: Failure loading window scale option for flow on local port " + "%u: failure code = %d\n", + skops->local_port, ret); } return SOCKOPS_ERR; } @@ -273,12 +273,12 @@ static inline int handle_write_hdr_opt(struct bpf_sock_ops *skops) { int read_win_scale(struct bpf_sock_ops *skops) { switch (skops->op) { - case BPF_SOCK_OPS_TCP_LISTEN_CB: - return set_hdr_cb_flags(skops); - case BPF_SOCK_OPS_HDR_OPT_LEN_CB: - return handle_hdr_opt_len(skops); - case BPF_SOCK_OPS_WRITE_HDR_OPT_CB: - return handle_write_hdr_opt(skops); + case BPF_SOCK_OPS_TCP_LISTEN_CB: + return set_hdr_cb_flags(skops); + case BPF_SOCK_OPS_HDR_OPT_LEN_CB: + return handle_hdr_opt_len(skops); + case BPF_SOCK_OPS_WRITE_HDR_OPT_CB: + return handle_write_hdr_opt(skops); } return SOCKOPS_OK; } diff --git a/ratemon/runtime/python/ratemon_runtime.py b/ratemon/runtime/python/ratemon_runtime.py index 2e0f0319..fd53dffd 100644 --- a/ratemon/runtime/python/ratemon_runtime.py +++ b/ratemon/runtime/python/ratemon_runtime.py @@ -1,18 +1,18 @@ """Monitors incoming TCP flow to detect if they are above their target rate.""" -from argparse import ArgumentParser import atexit import logging import multiprocessing import multiprocessing.managers -from os import path import queue import signal -from struct import unpack import sys import threading import time import typing +from argparse import ArgumentParser +from os import path +from struct import unpack import netifaces as ni import pcapy @@ -25,11 +25,10 @@ policy_engine, reaction_strategy, ) -from ratemon.runtime.python.policies import Policy from ratemon.runtime.python.mitigation_strategy import MitigationStrategy +from ratemon.runtime.python.policies import Policy from ratemon.runtime.python.reaction_strategy import ReactionStrategy - LOCALHOST = utils.ip_str_to_int("127.0.0.1") # Flows that have not received a new packet in this many seconds will be # garbage collected. diff --git a/ratemon/runtime/python/reaction_strategy.py b/ratemon/runtime/python/reaction_strategy.py index 7f9a3ffe..93711936 100644 --- a/ratemon/runtime/python/reaction_strategy.py +++ b/ratemon/runtime/python/reaction_strategy.py @@ -1,7 +1,7 @@ """Defines feedback mechanisms for reacting to flow fairness decisions.""" -from enum import IntEnum import time +from enum import IntEnum class ReactionStrategy(IntEnum): diff --git a/ratemon/scripts/eval.py b/ratemon/scripts/eval.py index 609fa234..45f6432c 100755 --- a/ratemon/scripts/eval.py +++ b/ratemon/scripts/eval.py @@ -7,11 +7,11 @@ import math import multiprocessing import os -from os import path import pickle import random import sys import time +from os import path import matplotlib.pyplot as plt import numpy as np diff --git a/ratemon/scripts/graph_all_ccas.py b/ratemon/scripts/graph_all_ccas.py index fc129363..562df4ca 100644 --- a/ratemon/scripts/graph_all_ccas.py +++ b/ratemon/scripts/graph_all_ccas.py @@ -3,14 +3,14 @@ import argparse import json import os -from os import path import pickle import sys +from os import path import numpy as np -from ratemon.scripts import eval as evl from ratemon.model import utils +from ratemon.scripts import eval as evl def load_results(args): diff --git a/ratemon/scripts/max_leaf_nodes.py b/ratemon/scripts/max_leaf_nodes.py index 0b7f8db7..9cf3d730 100755 --- a/ratemon/scripts/max_leaf_nodes.py +++ b/ratemon/scripts/max_leaf_nodes.py @@ -2,8 +2,8 @@ import argparse import os -from os import path import sys +from os import path import matplotlib.pyplot as plt diff --git a/ratemon/scripts/prepare_data_all_generalized.sh b/ratemon/scripts/prepare_data_all_generalized.sh index a554be77..f8190a59 100755 --- a/ratemon/scripts/prepare_data_all_generalized.sh +++ b/ratemon/scripts/prepare_data_all_generalized.sh @@ -2,26 +2,26 @@ set -eou pipefail -base_dir="$HOME/fawnstore2/out/cloudlab/2021-5-12" +base_dir="${HOME}/fawnstore2/out/cloudlab/2021-5-12" -source "$HOME/src/ratemon/.venv/bin/activate" +source "${HOME}/src/ratemon/.venv/bin/activate" -for dir in "$base_dir"/*; do - pair="$(echo "$dir" | cut -d'/' -f 8)" - if [ "$pair" == "composite" ] || [ "$pair" == "cubic-bbr-fewer-features-more-data" ]; then - continue - fi - out_dir="$dir/new_splits" - echo "Preparing data for: $dir -> $out_dir" - PYTHONPATH="$HOME/src/ratemon" python "$HOME/src/ratemon/ratemon/model/prepare_data.py" \ - --data-dir="$dir" \ - --train-split=70 \ - --val-split=0 \ - --test-split=30 \ - --warmup-percent=5 \ - --out-dir="$out_dir" \ - --sample-percent=0.1 \ - --disjoint-splits +for dir in "${base_dir}"/*; do + pair="$(echo "${dir}" | cut -d'/' -f 8)" + if [[ ${pair} == "composite" ]] || [[ ${pair} == "cubic-bbr-fewer-features-more-data" ]]; then + continue + fi + out_dir="${dir}/new_splits" + echo "Preparing data for: ${dir} -> ${out_dir}" + PYTHONPATH="${HOME}/src/ratemon" python "${HOME}/src/ratemon/ratemon/model/prepare_data.py" \ + --data-dir="${dir}" \ + --train-split=70 \ + --val-split=0 \ + --test-split=30 \ + --warmup-percent=5 \ + --out-dir="${out_dir}" \ + --sample-percent=0.1 \ + --disjoint-splits done deactivate diff --git a/ratemon/scripts/skb_len.py b/ratemon/scripts/skb_len.py index 660061e8..bc396f10 100755 --- a/ratemon/scripts/skb_len.py +++ b/ratemon/scripts/skb_len.py @@ -8,7 +8,7 @@ import numpy as np -PERCENTILES = [10., 25., 50., 75., 90., 95., 99., 99.9, 99.99, 100.] +PERCENTILES = [10.0, 25.0, 50.0, 75.0, 90.0, 95.0, 99.0, 99.9, 99.99, 100.0] def parse_args(): diff --git a/ratemon/scripts/train.sh b/ratemon/scripts/train.sh index 322aa471..6263ada2 100755 --- a/ratemon/scripts/train.sh +++ b/ratemon/scripts/train.sh @@ -2,14 +2,14 @@ set -eou pipefail -if [ "$#" -ne 16 ]; then - echo "Illegal number of parameters." - echo "Usage: ./train.sh " \ - " " \ - " " \ - " " \ - " " - exit 255 +if [[ $# -ne 16 ]]; then + echo "Illegal number of parameters." + echo "Usage: ./train.sh " \ + " " \ + " " \ + " " \ + " " + exit 255 fi model_tag="$1" @@ -30,26 +30,26 @@ num_features_to_pick="${15}" venv_dir="${16}" echo "train.sh:" -printf "\tmodel_tag: %s\n" "$model_tag" -printf "\ttrain_data_dir: %s\n" "$train_data_dir" -printf "\tfull_models_dir: %s\n" "$full_models_dir" -printf "\tsmall_models_dir: %s\n" "$small_models_dir" -printf "\tsample_percent: %s\n" "$sample_percent" -printf "\tmax_iter: %s\n" "$max_iter" -printf "\tmax_leaf_nodes: %s\n" "$max_leaf_nodes" -printf "\tmax_depth: %s\n" "$max_depth" -printf "\tmin_samples_leaf: %s\n" "$min_samples_leaf" -printf "\tlr: %s\n" "$lr" -printf "\tval_frac: %s\n" "$val_frac" -printf "\tval_tol: %s\n" "$val_tol" -printf "\tn_iter_no_change: %s\n" "$n_iter_no_change" -printf "\tfeature_selection_percent: %s\n" "$feature_selection_percent" -printf "\tnum_features_to_pick: %s\n" "$num_features_to_pick" -printf "\tvenv_dir: %s\n" "$venv_dir" +printf "\tmodel_tag: %s\n" "${model_tag}" +printf "\ttrain_data_dir: %s\n" "${train_data_dir}" +printf "\tfull_models_dir: %s\n" "${full_models_dir}" +printf "\tsmall_models_dir: %s\n" "${small_models_dir}" +printf "\tsample_percent: %s\n" "${sample_percent}" +printf "\tmax_iter: %s\n" "${max_iter}" +printf "\tmax_leaf_nodes: %s\n" "${max_leaf_nodes}" +printf "\tmax_depth: %s\n" "${max_depth}" +printf "\tmin_samples_leaf: %s\n" "${min_samples_leaf}" +printf "\tlr: %s\n" "${lr}" +printf "\tval_frac: %s\n" "${val_frac}" +printf "\tval_tol: %s\n" "${val_tol}" +printf "\tn_iter_no_change: %s\n" "${n_iter_no_change}" +printf "\tfeature_selection_percent: %s\n" "${feature_selection_percent}" +printf "\tnum_features_to_pick: %s\n" "${num_features_to_pick}" +printf "\tvenv_dir: %s\n" "${venv_dir}" set +u # shellcheck disable=SC1091 -source "$venv_dir/bin/activate" +source "${venv_dir}/bin/activate" set -u ratemon_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)/../.." @@ -57,62 +57,62 @@ pushd /tmp # Step 4: Select features from initial model echo "Training model with all features. Progress: tail -f /tmp/train.log" -bash -x -c "PYTHONPATH='$ratemon_dir' python '$ratemon_dir/ratemon/model/train.py' \ +bash -x -c "PYTHONPATH='${ratemon_dir}' python '${ratemon_dir}/ratemon/model/train.py' \ --no-rand \ - --tag='$model_tag' \ - --data-dir='$train_data_dir' \ - --out-dir='$full_models_dir' \ + --tag='${model_tag}' \ + --data-dir='${train_data_dir}' \ + --out-dir='${full_models_dir}' \ --model=HistGbdtSklearn \ --balance \ - --sample-percent='$sample_percent' \ - --max-iter='$max_iter' \ - --max-leaf-nodes='$max_leaf_nodes' \ - --max-depth='$max_depth' \ - --min-samples-leaf='$min_samples_leaf' \ - --hgbdt-lr='$lr' \ - --validation-fraction='$val_frac' \ - --validation-tolerance='$val_tol' \ - --n-iter-no-change='$n_iter_no_change' \ + --sample-percent='${sample_percent}' \ + --max-iter='${max_iter}' \ + --max-leaf-nodes='${max_leaf_nodes}' \ + --max-depth='${max_depth}' \ + --min-samples-leaf='${min_samples_leaf}' \ + --hgbdt-lr='${lr}' \ + --validation-fraction='${val_frac}' \ + --validation-tolerance='${val_tol}' \ + --n-iter-no-change='${n_iter_no_change}' \ --early-stop \ --analyze-features \ --feature-selection-type='perm' \ - --feature-selection-percent='$feature_selection_percent' \ - --clusters='$num_features_to_pick' \ + --feature-selection-percent='${feature_selection_percent}' \ + --clusters='${num_features_to_pick}' \ --permutation-importance-repeats=1" || - { - echo "Error encountered during full model training and feature" \ - "selection, quitting!" - exit 4 - } -mv -fv "/tmp/train.log" "$full_models_dir/${model_tag}_train.log" + { + echo "Error encountered during full model training and feature" \ + "selection, quitting!" + exit 4 + } +mv -fv "/tmp/train.log" "${full_models_dir}/${model_tag}_train.log" # Step 5: Train model with selected features echo "Training model with selected features. Progress: tail -f /tmp/train.log" -bash -x -c "PYTHONPATH='$ratemon_dir' python '$ratemon_dir/ratemon/model/train.py' \ +bash -x -c "PYTHONPATH='${ratemon_dir}' python '${ratemon_dir}/ratemon/model/train.py' \ --no-rand \ --tag='${model_tag}_selected-features' \ - --data-dir='$train_data_dir' \ - --out-dir='$small_models_dir' \ + --data-dir='${train_data_dir}' \ + --out-dir='${small_models_dir}' \ --model=HistGbdtSklearn \ --balance \ - --sample-percent='$sample_percent' \ - --max-iter='$max_iter' \ - --max-leaf-nodes='$max_leaf_nodes' \ - --max-depth='$max_depth' \ - --min-samples-leaf='$min_samples_leaf' \ - --hgbdt-lr='$lr' \ - --validation-fraction='$val_frac' \ - --validation-tolerance='$val_tol' \ - --n-iter-no-change='$n_iter_no_change' \ + --sample-percent='${sample_percent}' \ + --max-iter='${max_iter}' \ + --max-leaf-nodes='${max_leaf_nodes}' \ + --max-depth='${max_depth}' \ + --min-samples-leaf='${min_samples_leaf}' \ + --hgbdt-lr='${lr}' \ + --validation-fraction='${val_frac}' \ + --validation-tolerance='${val_tol}' \ + --n-iter-no-change='${n_iter_no_change}' \ --early-stop \ - --selected-features='$(ls -t "$full_models_dir"/model_*-"$model_tag"-selected_features.json | head -n 1)'" || - { - echo "Error encountered while training with selected features," \ - "quitting!" - exit 5 - } + --selected-features='$(ls -t "${full_models_dir}"/model_*-"${model_tag}"-selected_features.json | head -n 1)'" || + { + echo "Error encountered while training with selected features," \ + "quitting!" + exit 5 + } mv -fv "/tmp/train.log" \ - "$small_models_dir/${model_tag}_selected-features_train.log" + "${small_models_dir}/${model_tag}_selected-features_train.log" deactivate popd diff --git a/ratemon/scripts/train_composite.sh b/ratemon/scripts/train_composite.sh index 30676d3f..b8b2312f 100755 --- a/ratemon/scripts/train_composite.sh +++ b/ratemon/scripts/train_composite.sh @@ -16,8 +16,8 @@ exp_dir="$1" out_dir="$2" tag="$3" ratemon_dir="$(cd "$(dirname "$0")"/.. && pwd)" -workspace_dir="$(dirname "$ratemon_dir")" -export PYTHONPATH="$workspace_dir:$PYTHONPATH" +workspace_dir="$(dirname "${ratemon_dir}")" +export PYTHONPATH="${workspace_dir}:${PYTHONPATH}" # python "$ratemon_dir/model/gen_features.py" \ # --exp-dir="$exp_dir" \ @@ -26,26 +26,26 @@ export PYTHONPATH="$workspace_dir:$PYTHONPATH" # --parallel=20 prepare() { - # Usage: prepare - cur_exp_dir="$exp_dir/cubic-$1" - tmp_dir="/tmp/prepare_data/cubic-$1" - mkdir -p "$tmp_dir" - python "$ratemon_dir/model/prepare_data.py" \ - --data-dir="$cur_exp_dir" \ - --out-dir="$tmp_dir" \ - --model=HistGbdtSklearn \ - --train-split=70 \ - --val-split=0 \ - --test-split=30 \ - --warmup-percent=5 \ - --sample-percent=10 - pushd "$tmp_dir" - mv -vf ./* "$cur_exp_dir" - popd + # Usage: prepare + cur_exp_dir="${exp_dir}/cubic-$1" + tmp_dir="/tmp/prepare_data/cubic-$1" + mkdir -p "${tmp_dir}" + python "${ratemon_dir}/model/prepare_data.py" \ + --data-dir="${cur_exp_dir}" \ + --out-dir="${tmp_dir}" \ + --model=HistGbdtSklearn \ + --train-split=70 \ + --val-split=0 \ + --test-split=30 \ + --warmup-percent=5 \ + --sample-percent=10 + pushd "${tmp_dir}" + mv -vf ./* "${cur_exp_dir}" + popd } for cca in "highspeed" "illinois" "vivace"; do - prepare "$cca" + prepare "${cca}" done # python "$ratemon_dir/model/train.py" \ @@ -62,5 +62,5 @@ done # --clusters=10 \ # --features-to-pick=20 \ # --permutation-importance-repeats=1 - # --balance \ - # --drop-popular +# --balance \ +# --drop-popular diff --git a/ratemon/scripts/train_max_leaf_nodes.sh b/ratemon/scripts/train_max_leaf_nodes.sh index 1942e3f6..98d4ea5e 100755 --- a/ratemon/scripts/train_max_leaf_nodes.sh +++ b/ratemon/scripts/train_max_leaf_nodes.sh @@ -16,8 +16,8 @@ exp_dir="$1" out_dir="$2" tag="$3" ratemon_dir="$(cd "$(dirname "$0")"/.. && pwd)" -workspace_dir="$(dirname "$ratemon_dir")" -export PYTHONPATH="$workspace_dir:$PYTHONPATH" +workspace_dir="$(dirname "${ratemon_dir}")" +export PYTHONPATH="${workspace_dir}:${PYTHONPATH}" # python "$ratemon_dir/model/gen_features.py" \ # --exp-dir="$exp_dir" \ @@ -36,21 +36,21 @@ export PYTHONPATH="$workspace_dir:$PYTHONPATH" # 100 250 500 1000 250 5000 10000 31 -1 # 25000 50000 100000 200000 for max_leaf_nodes in 250; do - OMP_NUM_THREADS=10 python "$ratemon_dir/model/train.py" \ - --out-dir="${out_dir}/vary_max_leaf_nodes/${max_leaf_nodes}" \ - --data-dir="${out_dir}" \ - --model=HistGbdtSklearn \ - --sample-percent=40 \ - --no-rand \ - --conf-trials=1 \ - --max-iter=10000 \ - --tag="${tag}_${max_leaf_nodes}" \ - --max-leaf-nodes="${max_leaf_nodes}" \ - --early-stop - # --analyze-features \ - # --clusters=10 \ - # --features-to-pick=20 \ - # --permutation-importance-repeats=1 - # --balance \ - # --drop-popular + OMP_NUM_THREADS=10 python "${ratemon_dir}/model/train.py" \ + --out-dir="${out_dir}/vary_max_leaf_nodes/${max_leaf_nodes}" \ + --data-dir="${out_dir}" \ + --model=HistGbdtSklearn \ + --sample-percent=40 \ + --no-rand \ + --conf-trials=1 \ + --max-iter=10000 \ + --tag="${tag}_${max_leaf_nodes}" \ + --max-leaf-nodes="${max_leaf_nodes}" \ + --early-stop + # --analyze-features \ + # --clusters=10 \ + # --features-to-pick=20 \ + # --permutation-importance-repeats=1 + # --balance \ + # --drop-popular done diff --git a/ratemon/scripts/train_old.sh b/ratemon/scripts/train_old.sh index a2f47687..67ee6db5 100755 --- a/ratemon/scripts/train_old.sh +++ b/ratemon/scripts/train_old.sh @@ -16,8 +16,8 @@ exp_dir="$1" out_dir="$2" tag="$3" ratemon_dir="$(cd "$(dirname "$0")"/.. && pwd)" -workspace_dir="$(dirname "$ratemon_dir")" -export PYTHONPATH="$workspace_dir:$PYTHONPATH" +workspace_dir="$(dirname "${ratemon_dir}")" +export PYTHONPATH="${workspace_dir}:${PYTHONPATH}" # python "$ratemon_dir/model/gen_features.py" \ # --exp-dir="$exp_dir" \ @@ -34,21 +34,21 @@ export PYTHONPATH="$workspace_dir:$PYTHONPATH" # --warmup-percent=5 \ # --sample-percent=20 for max_leaf_nodes in 100 250 500 1000 250 5000 10000 31 -1; do - python "$ratemon_dir/model/train.py" \ - --out-dir="${out_dir}/vary_max_leaf_nodes/${max_leaf_nodes}" \ - --data-dir="${out_dir}" \ - --model=HistGbdtSklearn \ - --sample-percent=100 \ - --no-rand \ - --conf-trials=1 \ - --max-iter=10000 \ - --tag="${tag}_${max_leaf_nodes}" \ - --max-leaf-nodes="${max_leaf_nodes}" \ - --early-stop - # --analyze-features \ - # --clusters=10 \ - # --features-to-pick=20 \ - # --permutation-importance-repeats=1 - # --balance \ - # --drop-popular + python "${ratemon_dir}/model/train.py" \ + --out-dir="${out_dir}/vary_max_leaf_nodes/${max_leaf_nodes}" \ + --data-dir="${out_dir}" \ + --model=HistGbdtSklearn \ + --sample-percent=100 \ + --no-rand \ + --conf-trials=1 \ + --max-iter=10000 \ + --tag="${tag}_${max_leaf_nodes}" \ + --max-leaf-nodes="${max_leaf_nodes}" \ + --early-stop + # --analyze-features \ + # --clusters=10 \ + # --features-to-pick=20 \ + # --permutation-importance-repeats=1 + # --balance \ + # --drop-popular done