├── .github
├── ISSUE_TEMPLATE
│ ├── bug.md
│ ├── build.md
│ └── others.md
└── workflows
│ ├── macos-x86-cpu.yml
│ ├── pylint-doc-check.yml
│ └── ubuntu-x86-cpu.yml
├── .gitignore
├── .gitmodules
├── ACKNOWLEDGEMENTS
├── Cargo.lock
├── Cargo.toml
├── Dockerfile.github-dev
├── Dockerfile.github-release
├── LICENSE
├── README.md
├── README_zh.md
├── ci
├── build_doc.sh
├── cargo-config.github
├── doc_link_checker.py
├── run_check.sh
└── run_github_docker_build.sh
├── docs
├── 01-how-to-build
│ ├── appendix-A-build-options.md
│ ├── build-from-source.zh.md
│ ├── build-on-aarch64.zh.md
│ ├── build-on-win10.zh.md
│ └── build-with-docker.zh.md
├── 02-how-to-run
│ ├── generate-rtsp.zh.md
│ ├── run-in-15-minutes.en.md
│ ├── run-in-15-minutes.zh.md
│ └── workflow.png
├── 03-how-to-add-my-service
│ ├── 01-quickstart.zh.md
│ ├── 02-det-attr.zh.md
│ ├── 03-batching-and-pipeline-test.zh.md
│ ├── 04-web-visualization.zh.md
│ ├── appendix-A-graph-definition.zh.md
│ ├── appendix-B-python-plugin.zh.md
│ └── appendix-C-dump-model.zh.md
├── FAQ.zh.md
├── Makefile
├── conf.py
├── download-models.zh.md
├── how-to-contribute.zh.md
├── how-to-debug.zh.md
├── how-to-pack-python-whl.zh.md
├── images
│ ├── catfinder_image.png
│ ├── catfinder_video.png
│ ├── structure.png
│ ├── visualize_deployment.jpg
│ └── visualize_result.jpg
├── index.rst
├── make.bat
└── requirements.txt
├── flow-debugger
├── Cargo.lock
├── Cargo.toml
├── debugger-ui
│ ├── .gitignore
│ ├── .prettierrc
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ │ ├── index.html
│ │ └── robots.txt
│ ├── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── AppHeader.js
│ │ ├── AppHeader.module.css
│ │ ├── app
│ │ │ ├── actor.js
│ │ │ ├── index.js
│ │ │ └── store.js
│ │ ├── component
│ │ │ ├── button
│ │ │ │ ├── Button.js
│ │ │ │ └── Button.module.css
│ │ │ ├── input
│ │ │ │ ├── Input.js
│ │ │ │ └── Input.module.css
│ │ │ ├── line_with_descp
│ │ │ │ ├── LineWithDescp.js
│ │ │ │ └── LineWithDescp.module.css
│ │ │ ├── resizable_area
│ │ │ │ ├── ResizableArea.js
│ │ │ │ └── ResizableArea.module.css
│ │ │ └── tab
│ │ │ │ ├── Tab.js
│ │ │ │ └── Tab.module.css
│ │ ├── event_listener.js
│ │ ├── index.css
│ │ ├── index.js
│ │ ├── page
│ │ │ ├── chart
│ │ │ │ ├── Chart.js
│ │ │ │ ├── Chart.module.css
│ │ │ │ └── ChartSlice.js
│ │ │ ├── editor
│ │ │ │ ├── Editor.js
│ │ │ │ └── EditorSlice.js
│ │ │ ├── empty
│ │ │ │ ├── Empty.js
│ │ │ │ └── Empty.module.css
│ │ │ ├── index.js
│ │ │ ├── text
│ │ │ │ ├── Text.js
│ │ │ │ ├── Text.module.css
│ │ │ │ └── TextSlice.js
│ │ │ └── topology
│ │ │ │ ├── Topology.js
│ │ │ │ ├── TopologySlice.js
│ │ │ │ └── VisGraph.js
│ │ ├── parser.js
│ │ ├── serviceWorker.js
│ │ ├── types.js
│ │ └── websocket.js
│ └── yarn.lock
└── src
│ └── main.rs
├── flow-derive
├── Cargo.toml
├── README.md
├── examples
│ └── node_derive.rs
└── src
│ ├── actor.rs
│ ├── internal.rs
│ ├── lib.rs
│ ├── lit.rs
│ ├── node.rs
│ ├── ports.rs
│ ├── resource.rs
│ ├── type_name.rs
│ └── utils.rs
├── flow-message
├── Cargo.lock
├── Cargo.toml
└── src
│ ├── c.rs
│ ├── cross
│ ├── cow_list.rs
│ ├── cow_map.rs
│ ├── data
│ │ ├── list.rs
│ │ ├── mod.rs
│ │ └── value.rs
│ ├── list.rs
│ ├── map.rs
│ ├── mod.rs
│ └── python
│ │ ├── cow_list.rs
│ │ ├── cow_map.rs
│ │ ├── iterator.rs
│ │ ├── list.rs
│ │ ├── map.rs
│ │ └── mod.rs
│ └── lib.rs
├── flow-plugins
├── Cargo.toml
├── examples
│ ├── bytes_server.toml
│ ├── image_input.toml
│ ├── image_server.toml
│ ├── video_input.toml
│ └── video_server.toml
└── src
│ ├── bytes_server.rs
│ ├── image_input.rs
│ ├── image_server.rs
│ ├── lib.rs
│ ├── utils
│ ├── args_parser.rs
│ ├── bare_json.rs
│ ├── bytes.rs
│ ├── codec.rs
│ ├── either.rs
│ ├── error.rs
│ ├── find_lib.rs
│ ├── frame.rs
│ ├── image.rs
│ ├── mod.rs
│ └── multipart.rs
│ ├── video_input.rs
│ └── video_server.rs
├── flow-python
├── Cargo.toml
├── examples
│ ├── application
│ │ ├── cat_finder
│ │ │ ├── README.md
│ │ │ ├── __init__.py
│ │ │ ├── det.py
│ │ │ ├── image_cpu.toml
│ │ │ ├── image_gpu.toml
│ │ │ ├── images
│ │ │ │ ├── cat_finder_image_result.jpg
│ │ │ │ ├── cat_finder_image_select.jpg
│ │ │ │ └── cat_finder_video_select.jpg
│ │ │ ├── redis_proxy.py
│ │ │ ├── reid_image.py
│ │ │ ├── reid_video.py
│ │ │ ├── shaper.py
│ │ │ ├── track.py
│ │ │ ├── video_cpu.toml
│ │ │ ├── video_gpu.toml
│ │ │ ├── video_visualize.toml
│ │ │ └── visualize
│ │ │ │ ├── __init__.py
│ │ │ │ ├── shaper_visualize.py
│ │ │ │ └── visualize.py
│ │ ├── electric_bicycle
│ │ │ ├── README.md
│ │ │ ├── __init__.py
│ │ │ ├── det.py
│ │ │ ├── electric_bicycle.toml
│ │ │ ├── redis_proxy.py
│ │ │ ├── shaper.py
│ │ │ └── track.py
│ │ ├── misc
│ │ │ ├── bytes_client.py
│ │ │ ├── dump_resnet.py
│ │ │ ├── image_client.py
│ │ │ ├── video_client.py
│ │ │ └── visualize_client
│ │ │ │ ├── demo.css
│ │ │ │ ├── index.html
│ │ │ │ └── push_video.py
│ │ ├── requires.txt
│ │ ├── simple_classification
│ │ │ ├── __init__.py
│ │ │ ├── classify.py
│ │ │ ├── image_cpu.toml
│ │ │ ├── image_test.toml
│ │ │ ├── lite.py
│ │ │ └── synset_words.txt
│ │ ├── simple_det_classify
│ │ │ ├── __init__.py
│ │ │ ├── classify.py
│ │ │ ├── det.py
│ │ │ ├── lite.py
│ │ │ ├── video_cpu.toml
│ │ │ └── video_test.toml
│ │ ├── utils.py
│ │ ├── video_super_resolution
│ │ │ ├── README.md
│ │ │ ├── __init__.py
│ │ │ ├── config.toml
│ │ │ ├── lite.py
│ │ │ ├── model.py
│ │ │ ├── requires.sh
│ │ │ └── requires.txt
│ │ └── warehouse
│ │ │ ├── detection_memd
│ │ │ ├── README.md
│ │ │ ├── __init__.py
│ │ │ ├── main.py
│ │ │ ├── onnx_model.py
│ │ │ └── requirements.txt
│ │ │ ├── detection_yolox
│ │ │ ├── README.md
│ │ │ ├── __init__.py
│ │ │ ├── coco_classes.py
│ │ │ ├── lite.py
│ │ │ ├── process.py
│ │ │ └── visualize.py
│ │ │ ├── quality_naive
│ │ │ ├── __init__.py
│ │ │ └── quality.py
│ │ │ ├── reid_alignedreid
│ │ │ ├── README.md
│ │ │ ├── __init__.py
│ │ │ ├── dump.py
│ │ │ ├── image
│ │ │ │ ├── badcase_tiger.jpg
│ │ │ │ ├── negative.jpg
│ │ │ │ ├── pinggai_1.jpg
│ │ │ │ ├── positive1.jpg
│ │ │ │ ├── positive2.jpg
│ │ │ │ └── positive_pinggai.jpg
│ │ │ ├── lite.py
│ │ │ ├── main.py
│ │ │ ├── model.py
│ │ │ ├── process.py
│ │ │ └── resnet.py
│ │ │ └── track_iou
│ │ │ ├── __init__.py
│ │ │ └── track_iou.py
│ ├── basis_function
│ │ ├── batch
│ │ │ ├── __init__.py
│ │ │ ├── batch.toml
│ │ │ └── op.py
│ │ ├── demux
│ │ │ ├── demux.toml
│ │ │ └── op.py
│ │ ├── future
│ │ │ ├── future.toml
│ │ │ └── op.py
│ │ ├── interactive
│ │ │ └── main.py
│ │ ├── map_reduce
│ │ │ ├── map_reduce.toml
│ │ │ └── op.py
│ │ ├── nest
│ │ │ ├── nest.toml
│ │ │ └── op.py
│ │ ├── profile
│ │ │ ├── __init__.py
│ │ │ ├── profile.png
│ │ │ ├── profile.toml
│ │ │ ├── sink.py
│ │ │ ├── source.py
│ │ │ └── transport.py
│ │ └── unused
│ │ │ ├── op.py
│ │ │ └── unused.toml
│ └── logical_test
│ │ ├── __init__.py
│ │ ├── buffer.py
│ │ ├── logical_test.png
│ │ ├── logical_test.toml
│ │ ├── printer.py
│ │ ├── process.py
│ │ └── source.py
├── megflow
│ ├── __init__.py
│ ├── command_line.py
│ ├── func_op.py
│ └── registry.py
├── setup.py
└── src
│ └── lib.rs
├── flow-quickstart
├── Cargo.toml
└── src
│ ├── git.rs
│ ├── lib.rs
│ ├── log.rs
│ └── main.rs
├── flow-rs
├── Cargo.toml
├── examples
│ └── graph.rs
├── src
│ ├── broker.rs
│ ├── channel
│ │ ├── error.rs
│ │ ├── inner.rs
│ │ ├── mod.rs
│ │ ├── receiver.rs
│ │ ├── sender.rs
│ │ └── storage.rs
│ ├── config
│ │ ├── graphviz.rs
│ │ ├── insert.rs
│ │ ├── interlayer.rs
│ │ ├── mod.rs
│ │ ├── parser.rs
│ │ ├── presentation.rs
│ │ └── table.rs
│ ├── debug
│ │ ├── feature.rs
│ │ ├── mod.rs
│ │ ├── protocol.rs
│ │ └── server.rs
│ ├── envelope
│ │ ├── any_envelope.rs
│ │ ├── envelope.rs
│ │ └── mod.rs
│ ├── future.rs
│ ├── graph
│ │ ├── channel.rs
│ │ ├── context.rs
│ │ ├── debug.rs
│ │ ├── mod.rs
│ │ ├── node.rs
│ │ └── subgraph.rs
│ ├── helper
│ │ ├── mod.rs
│ │ └── python.rs
│ ├── lib.rs
│ ├── loader
│ │ ├── mod.rs
│ │ └── python
│ │ │ ├── channel.rs
│ │ │ ├── context.rs
│ │ │ ├── envelope.rs
│ │ │ ├── mod.rs
│ │ │ ├── node.rs
│ │ │ ├── port.rs
│ │ │ ├── unlimited.rs
│ │ │ └── utils.rs
│ ├── node
│ │ ├── bcast.rs
│ │ ├── demux.rs
│ │ ├── mod.rs
│ │ ├── noop.rs
│ │ ├── port.rs
│ │ ├── reorder.rs
│ │ ├── shared.rs
│ │ └── transform.rs
│ ├── registry.rs
│ ├── resource
│ │ ├── any_resource.rs
│ │ ├── collection.rs
│ │ ├── lazy.rs
│ │ ├── mod.rs
│ │ └── storage.rs
│ └── sandbox.rs
└── tests
│ ├── 01-subgraph.rs
│ ├── 02-dyn-subgraph.rs
│ ├── 03-share-subgraph.rs
│ ├── 04-isolated.rs
│ └── nodes_ext.rs
├── logo.png
└── pylintrc
/.github/ISSUE_TEMPLATE/bug.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "bug issue (╯°□°)╯︵ ┻━┻ "
3 | about: submit a bug report
4 | ---
5 |
6 | ## error log | 日志或报错信息
7 |
8 | ## context | 编译/运行环境
9 |
10 | ## how to reproduce | 复现步骤
11 | 1.
12 | 2.
13 | 3.
14 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/build.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "compatibility issue ┬─┬ノ( ゜-゜ノ)"
3 | about: build error
4 | ---
5 |
6 | ## platform | 软硬件环境
7 |
8 | ## error log | 日志或报错信息
9 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/others.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "others (Ծ‸ Ծ)"
3 | about: discussion, suggestion and question
4 | ---
5 |
6 | ## detail | 详细描述
7 |
--------------------------------------------------------------------------------
/.github/workflows/macos-x86-cpu.yml:
--------------------------------------------------------------------------------
1 | name: macos-x86-cpu
2 | on:
3 | push:
4 | branches: [master]
5 | pull_request:
6 | branches: [master]
7 | jobs:
8 | build:
9 | name: macos-x86-cpu
10 | runs-on: macos-latest
11 | steps:
12 | - name: cancel-previous-runs
13 | uses: styfle/cancel-workflow-action@0.9.1
14 | with:
15 | access_token: ${{ secrets.GITHUB_TOKEN }}
16 | - uses: actions/checkout@v2
17 | - uses: actions-rs/toolchain@v1
18 | with:
19 | toolchain: stable
20 | - run: brew install yasm
21 | - run: brew install openssl@1.1
22 | - run: brew install pkg-config
23 | - uses: actions/setup-python@v2
24 | with:
25 | python-version: '3.8'
26 | architecture: 'x64'
27 | - run: cd $HOME && git clone https://github.com/tpoisonooo/rust-ffmpeg && cd rust-ffmpeg && cargo build --release
28 | - run: cat /tmp/megflow_ffmpeg_dynamic_link.sh
29 | - run: ls -alh `cat /tmp/megflow_ffmpeg_dynamic_link.sh | head -n 1`/lib/
30 | - run: echo 'export FFMPEG_DIR=`cat ${HOME}/megflow_ffmpeg_dynamic_link.sh | head -n 1`' >> $HOME/myenv
31 | - run: echo 'export CARGO_FEATURE_PREBUILD="PREBUILD"' >> $HOME/myenv
32 | - run: echo 'export CARGO_FEATURE_DYNAMIC="DYNAMIC"' >> $HOME/myenv
33 | - run: echo 'export LD_LIBRARY_PATH=${FFMPEG_DIR}/lib:${LD_LIBRARY_PATH}' >> $HOME/myenv
34 | - run: echo 'export PKG_CONFIG_PATH=${FFMPEG_DIR}/lib/pkgconfig:${PKG_CONFIG_PATH}' >> $HOME/myenv
35 | - run: chmod +x $HOME/myenv
36 | - run: cat $HOME/myenv
37 | - run: . $HOME/myenv && cargo test --release
38 | - run: . $HOME/myenv && cd flow-python && python3.8 setup.py install --user && cd examples && megflow_run -p logical_test
39 |
--------------------------------------------------------------------------------
/.github/workflows/pylint-doc-check.yml:
--------------------------------------------------------------------------------
1 | name: pylint-doc-check
2 | on:
3 | push:
4 | branches: [master]
5 | pull_request:
6 | branches: [master]
7 | jobs:
8 | build:
9 | name: ubuntu-x86-cpu
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: cancel-previous-runs
13 | uses: styfle/cancel-workflow-action@0.9.1
14 | with:
15 | access_token: ${{ secrets.GITHUB_TOKEN }}
16 | - uses: actions/checkout@v2
17 | - uses: actions/setup-python@v2
18 | with:
19 | python-version: '3.8'
20 | - run: ./ci/run_check.sh
21 |
--------------------------------------------------------------------------------
/.github/workflows/ubuntu-x86-cpu.yml:
--------------------------------------------------------------------------------
1 | name: ubuntu-x86-cpu
2 | on:
3 | push:
4 | branches: [master]
5 | pull_request:
6 | branches: [master]
7 | jobs:
8 | build:
9 | name: ubuntu-x86-cpu
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: cancel-previous-runs
13 | uses: styfle/cancel-workflow-action@0.9.1
14 | with:
15 | access_token: ${{ secrets.GITHUB_TOKEN }}
16 | - uses: actions/checkout@v2
17 | - uses: actions-rs/toolchain@v1
18 | with:
19 | toolchain: stable
20 | - run: sudo apt update && sudo apt install yasm
21 | - run: sudo apt install -y libssl-dev
22 | - run: sudo apt update && sudo apt-get install -y pkg-config --fix-missing
23 | - run: sudo apt install -y libv4l-dev liblzma-dev
24 | - run: cd $HOME && git clone https://github.com/tpoisonooo/rust-ffmpeg && cd rust-ffmpeg && cargo build --release
25 | - run: echo 'export FFMPEG_DIR=`cat /tmp/megflow_ffmpeg_dynamic_link.sh | head -n 1`' >> $HOME/myenv
26 | - run: echo 'export CARGO_FEATURE_PREBUILD="PREBUILD"' >> $HOME/myenv
27 | - run: echo 'export CARGO_FEATURE_DYNAMIC="DYNAMIC"' >> $HOME/myenv
28 | - run: echo 'export LD_LIBRARY_PATH=${FFMPEG_DIR}/lib:${LD_LIBRARY_PATH}' >> $HOME/myenv
29 | - run: echo 'export PKG_CONFIG_PATH=${FFMPEG_DIR}/lib/pkgconfig:${PKG_CONFIG_PATH}' >> $HOME/myenv
30 | - run: chmod +x $HOME/myenv
31 | - run: sudo apt install python3.8-dev
32 | - run: . $HOME/myenv && cargo test --release
33 | - run: . $HOME/myenv && cd flow-python && python3 setup.py install --user && cd examples && megflow_run -p logical_test
34 |
35 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /gh-pages
2 | __pycache__
3 | *.out
4 | *.pyc
5 | *.pid
6 | *.sock
7 | *~
8 | target/
9 | *.pyo
10 | *.so
11 | .eggs
12 | .tox
13 | dist
14 | build
15 | .pytest_cache
16 | *.egg-info
17 | setuptools_rust/version.py
18 | pyo3
19 | docs/_build
20 | *.dot
21 | .clippy.toml
22 | flow-python/examples/application/models
23 | flow-python/megflow/megflow_quickstart_inner
24 | flow-python/megflow/megflow_run_inner
25 | .vim
26 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MegEngine/MegFlow/41cb9f85828aa080f6004674904fe430d8268052/.gitmodules
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [workspace]
2 | members = [
3 | "flow-rs",
4 | "flow-derive",
5 | "flow-plugins",
6 | "flow-debugger",
7 | "flow-message",
8 | "flow-quickstart",
9 | "flow-python",
10 | ]
11 |
12 | [profile.dev]
13 | incremental = false
14 | panic = 'abort'
15 |
16 | [profile.release]
17 | panic = 'abort'
18 |
--------------------------------------------------------------------------------
/Dockerfile.github-dev:
--------------------------------------------------------------------------------
1 | FROM ubuntu:18.04
2 |
3 | WORKDIR /megflow
4 |
5 | # install requirements
6 | RUN apt-get update
7 | RUN apt-get install -y wget yasm clang git build-essential
8 | RUN apt install -y libssl-dev
9 | RUN apt update && apt-get install -y pkg-config --fix-missing
10 | RUN apt-get install -y curl
11 | RUN apt install -y libv4l-dev liblzma-dev
12 |
13 | # prepare cargo env
14 | ENV CARGO_HOME /cargo
15 | ENV RUSTUP_HOME /rustup
16 | RUN curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf -o run.sh \
17 | && chmod a+x run.sh \
18 | && ./run.sh -y && rm run.sh
19 | ENV PATH $PATH:/cargo/bin
20 | RUN chmod -R 777 /cargo /rustup
21 | COPY ci/cargo-config.github /cargo/config
22 |
23 | # copy workspace
24 | RUN mkdir -p $HOME/megflow-runspace
25 | WORKDIR $HOME/megflow-runspace
26 |
27 | # build conda env and activate
28 | RUN wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
29 | RUN bash Miniconda3-latest-Linux-x86_64.sh -b -p /conda && rm Miniconda3-latest-Linux-x86_64.sh
30 | ENV PATH $PATH:/conda/bin
31 | RUN echo "PATH=${PATH}" >> ~/.bashrc
32 | RUN conda init
33 |
34 | COPY . $HOME/megflow-runspace/
35 |
36 | # python install
37 | RUN cd flow-python && python3 setup.py install --user
38 |
39 | RUN export PATH=/root/.local/bin:${PATH} && cd flow-python/examples \
40 | && megflow_run -p logical_test
41 |
--------------------------------------------------------------------------------
/Dockerfile.github-release:
--------------------------------------------------------------------------------
1 | FROM megflow:latest as stage
2 |
3 | # build .whl
4 | RUN cd flow-python \
5 | && python3 setup.py bdist_wheel -p linux-x86_64 -d ../dist
6 |
7 | # copy back to host
8 | FROM scratch AS export-stage
9 | COPY --from=stage /megflow-runspace/dist/ .
10 |
--------------------------------------------------------------------------------
/ci/build_doc.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -ex
2 |
3 | rm -rf $1
4 |
5 | : ${TARGET_DIR:=/target/${CI_COMMIT_SHA}}
6 |
7 | cargo doc --no-deps
8 |
9 | echo '' > ${TARGET_DIR}/doc/index.html
10 |
11 | mv ${TARGET_DIR}/doc $1
12 |
--------------------------------------------------------------------------------
/ci/cargo-config.github:
--------------------------------------------------------------------------------
1 | [source.crates-io]
2 | replace-with = 'tuna'
3 |
4 | [source.tuna]
5 | registry = "https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git"
6 |
--------------------------------------------------------------------------------
/ci/run_check.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | python -m pip install pylint==2.5.2 requests
4 |
5 | CHECK_DIR="flow-python/examples/application/simple_classification"
6 | CHECK_DIR+=" flow-python/examples/application/simple_det_classify"
7 | CHECK_DIR+=" flow-python/examples/application/cat_finder"
8 | CHECK_DIR+=" flow-python/examples/application/electric_bicycle"
9 | CHECK_DIR+=" flow-python/examples/application/misc"
10 |
11 | pylint $CHECK_DIR
12 |
13 | python ci/doc_link_checker.py
14 |
--------------------------------------------------------------------------------
/ci/run_github_docker_build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -ex
2 |
3 | python3 ci/convert_project_to_github.py
4 |
5 | docker build --rm -t megflow -f Dockerfile.github-dev .
--------------------------------------------------------------------------------
/docs/01-how-to-build/appendix-A-build-options.md:
--------------------------------------------------------------------------------
1 | # Build options
2 |
3 | | cargo features | function |
4 | | --------- | ----------- |
5 | | open-camera | open camera via v4l2 on VideoServer |
6 | | no-default-features | build without rweb/ffmpeg/decoder |
7 |
8 | | environment | function |
9 | | --------- | ----------- |
10 | | CARGO_FEATURE_PREBUILD | use prebuild ffmpeg |
11 | | CARGO_FEATURE_STATIC | build static ffmpeg lib |
12 | | FFMPEG_DIR | specify prebuild ffmpeg dir |
13 |
--------------------------------------------------------------------------------
/docs/01-how-to-build/build-from-source.zh.md:
--------------------------------------------------------------------------------
1 | # Building from Source
2 |
3 | ## 一、安装依赖
4 |
5 | ### 安装 Rust
6 | ```bash
7 | $ sudo apt install curl
8 | $ curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh
9 | ```
10 |
11 | 成功后,`cargo` 应该可以正常执行
12 | ```bash
13 | $ cargo --version
14 | cargo 1.56.0 (4ed5d137b 2021-10-04)
15 | ```
16 |
17 | 如果不成功,提示`Command 'cargo' not found`,可以按照提示加载一下环境变量(重新连接或打开终端也可以):
18 | ```
19 | source $HOME/.cargo/env
20 | ```
21 |
22 | > `cargo` 是 Rust 的包管理器兼编译辅助工具。类似 Java maven/go pkg/C++ CMake 的角色,更易使用。
23 |
24 | ### 安装 python3.x (推荐 conda)
25 |
26 | 打开 [miniconda 官网](https://docs.conda.io/en/latest/miniconda.html) 下载 miniconda 安装包,修改权限并安装。
27 |
28 | ```bash
29 | $ wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
30 | $ chmod a+x Miniconda3-latest-Linux-x86_64.sh
31 | $ ./Miniconda3-latest-Linux-x86_64.sh
32 | ```
33 |
34 | 安装时接受 conda 修改默认 .bashrc 环境变量(zsh 用户还需自行修改 .zshrc 中的 conda initialize 配置)。成功后 `conda` 可正常运行
35 | ```bash
36 | $ conda --version
37 | conda 4.10.3
38 | ```
39 |
40 | 创建一个 Python3.x(这里以 3.8 为例) 的环境,激活。
41 | ```bash
42 | $ conda create --name py38 python=3.8
43 | $ conda activate py38
44 | ```
45 |
46 | ### 安装基础依赖库
47 |
48 | megflow的构建需要一些基础依赖库, 下面以ubuntu系统为例:
49 | ```bash
50 | $ sudo apt update
51 | $ sudo apt install -y wget yasm clang git build-essential
52 | $ sudo apt install -y libssl-dev
53 | $ sudo apt install -y pkg-config --fix-missing
54 | ```
55 |
56 |
57 | ## 二、编译
58 |
59 | 编译并安装Python包到当前用户下
60 |
61 | ```bash
62 | $ git clone --recursive https://github.com/MegEngine/MegFlow --depth=1
63 | $ cd MegFlow/flow-python
64 | $ python3 setup.py install --user
65 | ```
66 | 编译成功后,在 Python `import megflow` 正常。
67 |
68 | ## 三、Python“开机自检”
69 | ```bash
70 | $ cd examples
71 | $ megflow_run -p logical_test
72 | ```
73 | `logical_test` 是 examples 下最基础的计算图测试用例,运行能正常结束表示 MegFlow 编译成功、基本语义无问题。
74 |
75 | `megflow_run` 是计算图的实现。编译完成之后不再需要 `cargo` 和 `Rust`,使用者只需要
76 |
77 | * `import megflow` 成功
78 | * `megflow_run -h` 正常
79 |
80 | ## 四、[编译选项](appendix-A-build-options.md)
81 |
--------------------------------------------------------------------------------
/docs/01-how-to-build/build-on-aarch64.zh.md:
--------------------------------------------------------------------------------
1 | # aarch64 源码编译
2 |
3 | aarch64 源码编译方式和 [源码编译](build-from-source.zh.md) 相同,此处只说明差异。
4 |
5 | ## 环境差异
6 |
7 | 如果是华为鲲鹏 ARM 服务器 CentOS 系统, gcc 需要 >= 7.5 版本,系统默认的 `aarch64-redhat-linux-gcc 4.8.5` 缺 `__ARM_NEON` 会导致大量异常。
8 | ```bash
9 | $ yum install -y centos-release-scl
10 | $ yum install -y devtoolset-8-gcc devtoolset-8-gcc-c++
11 | $ source /opt/rh/devtoolset-8/enable
12 | $ gcc --version
13 | gcc (GCC) 8.3.1 20190311 (Red Hat 8.3.1-3)
14 | ...
15 | ```
16 | ## 软件差异
17 |
18 | conda 建议使用 `archiconda`,目前(2021.12.06) miniconda aarch64 官网版本在 KhadasVIM3/JetsonNao 上均会崩溃。`archiconda` 安装:
19 | ```bash
20 | $ wget https://github.com/Archiconda/build-tools/releases/download/0.2.3/Archiconda3-0.2.3-Linux-aarch64.sh
21 | $ chmod +x Archiconda3-0.2.3-Linux-aarch64.sh && ./Archiconda3-0.2.3-Linux-aarch64.sh
22 | ```
23 |
--------------------------------------------------------------------------------
/docs/01-how-to-build/build-on-win10.zh.md:
--------------------------------------------------------------------------------
1 | # Build on win10
2 |
3 | ## 下载模型包
4 | docker 运行方式,建议把模型包下好,解压备用。[下载地址](../download-models.zh.md)
5 |
6 | ## 安装 wsl2
7 |
8 | [安装文档](https://docs.microsoft.com/zh-cn/windows/wsl/install-win10) 已经非常详细,核心是安装 Linux 内核更新包。完成后第 6 步中的 Linux 分发应该可以正常运行。
9 |
10 | ## 安装 docker
11 | 下载 [windows docker 客户端](https://www.docker.com/products/docker-desktop) 并安装。docker 依赖 wsl2,Docker Desktop 启动正常没有报 fail 即可。
12 |
13 | ## 安装 git
14 |
15 | 下载安装 [git 客户端](https://git-scm.com/downloads) 并运行 Git Bash。
16 |
17 | ```bash
18 | $ pwd
19 | /c/Users/username
20 | $ cd /d # 切换到合适的盘符
21 | $ git clone https://github.com/MegEngine/MegFlow
22 | ...
23 | $ cd MegFlow
24 | $ docker build -t megflow .
25 | ... # 等待镜像完成,取决于网络和 CPU
26 | ```
27 | > 注意:**不要移动 Dockerfile 文件的位置**。受 [EAR](https://www.federalregister.gov/documents/2019/10/09/2019-22210/addition-of-certain-entities-to-the-entity-list) 约束,MegFlow 无法提供现成的 docker 镜像,需要自己 build 出来,这个过程用了相对路径。
28 |
29 | ## 运行
30 |
31 | ```bash
32 | $ docker images
33 | REPOSITORY TAG IMAGE ID CREATED SIZE
34 | megflow latest c65e37e1df6c 18 hours ago 5.05GB
35 | ```
36 | 直接用 ${IMAGE ID} 进入开始跑应用,挂载上之前下载好的模型包
37 | ```bash
38 | $ docker run -p 18081:8081 -p 18082:8082 -v ${DOWNLOAD_MODEL_PATH}:/megflow-runspace/flow-python/examples/models -i -t c65e37e1df6c /bin/bash
39 | ```
40 |
--------------------------------------------------------------------------------
/docs/01-how-to-build/build-with-docker.zh.md:
--------------------------------------------------------------------------------
1 | # Building with docker
2 |
3 | docker build 方式能够“可复现地”生成运行环境、减少依赖缺失的痛苦
4 |
5 | ## 下载模型包
6 | docker 运行方式,建议把模型包下好,解压备用。[下载地址](../download-models.zh.md)
7 |
8 | ## 编译 Docker 镜像
9 |
10 | ```bash
11 | $ cd MegFlow
12 | $ docker build -t megflow -f Dockerfile.github-dev .
13 | ```
14 | 稍等一段时间(取决于网络和 CPU)镜像构建完成并做了基础自测
15 | > 注意:**不要移动 Dockerfile 文件的位置**。受 [EAR](https://www.federalregister.gov/documents/2019/10/09/2019-22210/addition-of-certain-entities-to-the-entity-list) 约束,MegFlow 无法提供现成的 docker 镜像,需要自己 build 出来,这个过程用了相对路径。
16 | ```bash
17 | $ docker images
18 | REPOSITORY TAG IMAGE ID CREATED SIZE
19 | megflow latest c65e37e1df6c 18 hours ago 5.05GB
20 | ```
21 | 直接用 ${IMAGE ID} 进入开始跑应用,挂载上之前下载好的模型包
22 | ```bash
23 | $ docker run -p 18081:8081 -p 18082:8082 -v ${DOWNLOAD_MODEL_PATH}:/megflow-runspace/flow-python/examples/models -i -t c65e37e1df6c /bin/bash
24 | ```
25 |
26 | ## Python Built-in Applications
27 |
28 | 接下来开始运行好玩的 Python 应用
29 |
30 | * [猫猫围栏运行手册](https://github.com/MegEngine/MegFlow/tree/master/flow-python/examples/application/cat_finder)
31 | * 图片注册猫猫
32 | * 部署视频围栏,注册的猫离开围栏时会发通知
33 | * 未注册的不会提示
34 | * [电梯电瓶车告警](https://github.com/MegEngine/MegFlow/tree/master/flow-python/examples/application/electric_bicycle)
35 | * 电梯里看到电瓶车立即报警
36 | * [quickstart](../03-how-to-add-my-service/01-quickstart.zh.md)
37 | * 问答式创建自己的应用
38 | * [视频实时超分](https://github.com/MegEngine/MegFlow/tree/master/flow-python/examples/application/video_super_resolution)
39 |
--------------------------------------------------------------------------------
/docs/02-how-to-run/workflow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MegEngine/MegFlow/41cb9f85828aa080f6004674904fe430d8268052/docs/02-how-to-run/workflow.png
--------------------------------------------------------------------------------
/docs/03-how-to-add-my-service/02-det-attr.zh.md:
--------------------------------------------------------------------------------
1 | # 串联检测和分类
2 |
3 | 本文将在 [tutorial01](01-quickstart.zh.md) modelserving 的基础上扩展计算图:先检测、再扣图分类。对外提供视频解析服务。完整的代码在 flow-python/examples/simple_det_classify 目录。
4 |
5 | ## 移除分类预处理
6 |
7 | 见 [生成带预处理的模型](appendix-C-dump-model.zh.md)
8 |
9 | ## 准备检测模型
10 | 这里直接用现成的 YOLOX mge 模型。复用 [cat_finder 的检测](https://github.com/MegEngine/MegFlow/blob/master/flow-python/examples/application/cat_finder/det.py) 或者从 [YOLOX 官网](https://github.com/Megvii-BaseDetection/YOLOX/tree/main/demo/MegEngine/python) 下载最新版。
11 |
12 | ## 配置计算图
13 | `flow-python/examples` 增加 `simple_det_classify/video_cpu.toml`
14 |
15 | ```bash
16 | $ cat flow-python/examples/simple_det_classify/video_cpu.toml
17 |
18 | main = "tutorial_02"
19 |
20 | # 重资源结点要先声明
21 | [[nodes]]
22 | name = "det"
23 | ty = "Detect"
24 | model = "yolox-s"
25 | conf = 0.25
26 | nms = 0.45
27 | tsize = 640
28 | path = "models/simple_det_classify_models/yolox_s.mge"
29 | interval = 5
30 | visualize = 1
31 | device = "cpu"
32 | device_id = 0
33 |
34 | [[nodes]]
35 | name = "classify"
36 | ty = "Classify"
37 | path = "models/simple_det_classify_models/resnet18_preproc_inside.mge"
38 | device = "cpu"
39 | device_id = 0
40 |
41 | [[graphs]]
42 | name = "subgraph"
43 | inputs = [{ name = "inp", cap = 16, ports = ["det:inp"] }]
44 | outputs = [{ name = "out", cap = 16, ports = ["classify:out"] }]
45 | # 描述连接关系
46 | connections = [
47 | { cap = 16, ports = ["det:out", "classify:inp"] },
48 | ]
49 |
50 | ...
51 | # ty 改成 VdieoServer
52 | [[graphs.nodes]]
53 | name = "source"
54 | ty = "VideoServer"
55 | port = 8085
56 |
57 | ...
58 | ```
59 | 想对上一期的配置,需要关注 3 点:
60 | * 视频流中的重资源结点,需要声明在 `[[graphs]]` 之外,因为多路视频需要复用这个结点。如果每一路都要启一个 det 结点,资源会爆掉
61 | * `connections` 不再是空白,因为两个结点要描述连接关系
62 | * Server 类型改成 `VideoServer`,告诉 UI 是要处理视频的
63 |
64 | ## 运行测试
65 |
66 | 运行服务
67 | ```bash
68 | $ cd flow-python/examples
69 | $ megflow_run -c simple_det_classify/video_cpu.toml -p simple_det_classify
70 | ```
71 | ## 资源
72 |
73 | [此文档描述 graph toml 定义](appendix-A-graph-definition.zh.md)
74 |
75 |
76 | [此文档描述 Python node 接口定义](appendix-B-python-plugin.zh.md)
--------------------------------------------------------------------------------
/docs/03-how-to-add-my-service/appendix-B-python-plugin.zh.md:
--------------------------------------------------------------------------------
1 | # Python Plugins
2 |
3 | 从一个最简单的例子开始
4 | ```
5 | import megflow
6 | @megflow.register(name="alias", inputs=["inp"], outputs=["out"])
7 | class Node:
8 | def __init__(self, name, args):
9 | pass
10 | def exec(self):
11 | envelope = self.inp.recv()
12 | msg = dowith(envelope.msg)
13 | self.out.send(envelope.repack(msg))
14 | ```
15 |
16 | 这其中有三部分内容: register装饰器,Node的构造函数,Node的执行函数
17 |
18 | 1. register装饰器
19 | - name: 若指定,则register所修饰插件重命名为name,默认为register所修饰类的类名
20 | - inputs: Node的输入列表,每个输入`input`都可以在`exec`方法中,通过`self.input`访问,
21 | - outputs: Node的输出列表,每个输出`output`都可以在`exec`方法中,通过`self.output`访问
22 | - exclusive: 默认为False, 调度模型是一个thread local的协程调度器, 若为True, 则将该任务安排到线程池中
23 |
24 | 2. Node的构造函数
25 | - name: 即参数文件中Node的name字段
26 | - args: 即参数文件中Node的剩余参数字段
27 |
28 | 3. Node的执行函数
29 | - 一个python插件的执行方法必须是命名为`exec`的零参成员方法
30 | - 对于在参数文件中该插件引用的资源`resource`, 可以在`exec`方法中,通过`self.resource`访问
31 | - 通过输入的`recv`方法取得输入消息,输入消息是`Envelope`对象,其`msg`成员即开发者真正需要读写的消息实例
32 | - `Envelope`语义为在图中流转的消息的相关信息,由于这些信息需要在图中被传递,所以开发者应该保持消息与`Envelope`的对应关系
33 | - 若一个`Envelope`携带的消息被拆分为多个消息,或者转换为另一个消息,应该通过`Envelope`的`repack`方法,将`Envelope`与消息关联起来
34 | - 通过输出的`send`方法发送输出消息,输出消息是`Envelope`对象
35 |
36 | MegFlow也提供了一系列异步工具
37 | 1. `yield_now()`, 让出当前任务的执行权
38 | 2. `sleep(dur)`, 使当前任务沉睡`dur`毫秒
39 | 3. `join(tasks)`, `tasks`参数是一个函数列表,`join`堵塞直到`tasks`中的函数都执行完毕
40 | 4. `create_future(callback)`, `callback`参数是一个函数, 默认值为None,`create_future`返回一个`(Future, Waker)`对象
41 | - `Future::wait`, 堵塞直到`Waker::wake`被调用,返回`Waker::wake(result)`传入的`result`参数
42 |
--------------------------------------------------------------------------------
/docs/FAQ.zh.md:
--------------------------------------------------------------------------------
1 | # FAQ
2 |
3 | Q:`megflow_run -p logical_test ` 无法运行怎么办?
4 |
5 | A1:如果报错 `message: "No such file or directory" }'`,确认是否`cd flow-python/examples`
6 |
7 | A2:确认安装了 python 组件,即 `cd flow-python` 再 `python3 setup.py install --user`
8 |
9 | 还不行就提 issue。
10 |
11 | ___
12 | Q:视频流跑一路没事。跑多个,内存爆了/显存爆了/模型加载多次是因为啥?
13 |
14 | A:参照 `cat_finder/video.toml`,把涉模型的 nodes 移到 `[[graphs]]`上面,让多个子图来共享。
15 |
16 | 每启动一个视频流就会启一个子图,如果`nodes`放到`[[graphs]]`里,20 路视频就会创建 20 套 nodes。
17 | ___
18 | Q:如何修改服务端口号,8080 已被占用?
19 |
20 | A:以`cat_finder` 为例,端口配置在 `image.toml` 的 `port` 中。
21 | ___
22 | Q:如何让 ImageServer 返回 json,而不是渲染后的图?
23 |
24 | A:ImageServer 默认返回 `envelope.msg["data"]`图像。如果要返回 json 需要改两处:
25 | * `image.toml` 的配置里增加 `response = "json"`
26 | * 最终结果用`self.out.send(envelope.repack(json.dumps(results)))`发送出去
27 |
28 | 框架既不知道哪些字段可序列化,也不知道要序列化那几个字段,因此需要调用方序列化成 `str`。代码可参照 `examaples/cat_finder/redis_proxy.py`。
29 | ___
30 | Q:视频流为什么无法停止,调用了 stop 接口还是在处理?
31 |
32 | A:调用 stop 之后队列的 `push/put` 接口已经被关闭了,不能追加新的,但之前解好的帧还在队列里。需要把遗留的处理完、依次停止子图节点才完全结束。流不会调用 stop 即刻停止,实际上有延迟。
33 | ___
34 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line, and also
5 | # from the environment for the first two.
6 | SPHINXOPTS ?=
7 | SPHINXBUILD ?= sphinx-build
8 | SOURCEDIR = .
9 | BUILDDIR = _build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
22 |
--------------------------------------------------------------------------------
/docs/download-models.zh.md:
--------------------------------------------------------------------------------
1 | # 模型和测试数据下载
2 |
3 | | 应用名称 | 云盘 | google drive |
4 | | - | - | - |
5 | | 猫猫围栏、电动车检测 | 链接: https://pan.baidu.com/s/1ZLVBR0igJ1hL6PoYQDtByA 提取码: 8ajf | [google](https://drive.google.com/file/d/1EwMJFjNp2kuNglutoleZOVsqccSOW2Z4/view?usp=sharing) |
6 | | 视频超分 | 链接: https://pan.baidu.com/s/131Ul2A9DNxTXbatO1SGKFg?pwd=viy5 提取码: viy5 | [google](https://drive.google.com/file/d/1oyrVL20MODJOSf7BJ9T5OioE-ZaARDBC/view?usp=sharing) |
7 |
8 | 取最新的 models_xxx.zip,解压、软链为 examples/models
9 |
10 | ```bash
11 | $ wget ${URL}/modes.zip
12 | $ cd flow-python/examples/application
13 | $ ln -s ${DOWNLOAD_DIR}/models models
14 | ```
15 |
16 | 如果有 MegFlow-models repo,可以直接
17 |
18 | ```bash
19 | $ cd MegFlow-models
20 | $ git-lfs update
21 | $ git lfs pull
22 | ```
23 |
--------------------------------------------------------------------------------
/docs/how-to-contribute.zh.md:
--------------------------------------------------------------------------------
1 | # 如何提交代码
2 |
3 | ## 一、fork 分支
4 | 在浏览器中打开 [MegFlow](https://github.com/MegEngine/MegFlow), `fork` 到自己的 repositories,例如
5 | ```
6 | https://github.com/user/MegFlow
7 | ```
8 |
9 | clone 项目到本地,添加官方 remote 并 fetch:
10 | ```
11 | $ git clone https://github.com/user/MegFlow && cd MegFlow
12 | $ git remote add megvii https://github.com/MegEngine/MegFlow
13 | $ git fetch megvii
14 | ```
15 | 对于 `git clone` 下来的项目,它现在有两个 remote,分别是 origin 和 megvii
16 |
17 | ```
18 | $ git remote -v
19 | origin https://github.com/user/MegFlow (fetch)
20 | origin https://github.com/user/MegFlow (push)
21 | megvii https://github.com/MegEngine/MegFlow (fetch)
22 | megvii https://github.com/MegEngine/MegFlow (push)
23 | ```
24 | origin 指向你 fork 的仓库地址;remote 即官方 repo。可以基于不同的 remote 创建和提交分支。
25 |
26 | 例如切换到官方 master 分支,并基于此创建自己的分支(命名尽量言简意赅。一个分支只做一件事,方便 review 和 revert)
27 | ```
28 | $ git checkout MegEngine/master
29 | $ git checkout -b my-awesome-branch
30 | ```
31 |
32 | 或创建分支时指定基于官方 master 分支:
33 | ```
34 | $ git checkout -b fix-typo-in-document MegFlow/master
35 | ```
36 |
37 | > `git fetch` 是从远程获取最新代码到本地。如果是第二次 pr MegFlow `git fetch megvii` 开始即可,不需要 `git remote add megvii`,也不需要修改 `github.com/user/MegFlow`。
38 |
39 | ## 二、代码习惯
40 | 为了增加沟通效率,reviewer 一般要求 contributor 遵从以下规则
41 |
42 | * 不能随意增删空行
43 | * tab 替换为 4 个空格
44 | * 若是新增功能或平台,需有对应测试用例
45 | * 文档放到`docs`目录下,中文用`.zh.md`做后缀;英文直接用`.md`后缀
46 |
47 | 开发完成后提交到自己的 repository
48 | ```
49 | $ git commit -a
50 | $ git push origin my-awesome-branch
51 | ```
52 | 推荐使用 [`commitizen`](https://pypi.org/project/commitizen/) 或 [`gitlint`](https://jorisroovers.com/gitlint/) 等工具格式化 commit message,方便事后检索海量提交记录
53 |
54 | ## 三、代码提交
55 | 浏览器中打开 [MegFlow pulls](https://github.com/MegEngine/MegFlow/pulls) ,此时应有此分支 pr 提示,点击 `Compare & pull request`
56 |
57 | * 标题**必须**是英文。未完成的分支应以 `WIP:` 开头,例如 `WIP: fix-typo`
58 | * 正文宜包含以下内容,中英不限
59 | * 内容概述和实现方式
60 | * 功能或性能测试
61 | * 测试结果
62 |
63 | 回到浏览器签署 CLA,所有 CI 测试通过后通知 reviewer merge 此分支。
--------------------------------------------------------------------------------
/docs/how-to-debug.zh.md:
--------------------------------------------------------------------------------
1 | # 如何 Debug 常见问题
2 |
3 | 一、`megflow_run` 无法启动服务,直接 core dump 报错退出
4 |
5 | 如果“Python 开机自检”的 `megflow_run -p logical_test` 能够正常结束,排查方向应该是 Python import error。调试方法举例
6 | ```bash
7 | $ gdb --args ./megflow_run -c electric_bicycle/electric_bicycle_cpu.toml -p electric_bicycle
8 | ...
9 | illegal instruction
10 | ...
11 | ```
12 | 可以看到 crash 发生在哪个 import
--------------------------------------------------------------------------------
/docs/how-to-pack-python-whl.zh.md:
--------------------------------------------------------------------------------
1 | # 打包成 Python .whl
2 |
3 | ## 作用
4 | 打成 whl 包,使用方直接安装即可,不再需要编译。
5 |
6 | ## 执行
7 |
8 | 现在使用 Dockerfile 生成各 python 版本 .whl
9 |
10 | ```bash
11 | $ cd ${MegFlow_dir}
12 | $ # 构造开发环境,安装依赖。已执行过 docker 编译可以跳过此步骤
13 | $ docker build -t megflow -f Dockerfile.github-dev .
14 | $ # 创建结果目录
15 | $ mkdir dist
16 | $ # docker 打包 whl
17 | $ # https://stackoverflow.com/questions/33377022/how-to-copy-files-from-dockerfile-to-host
18 | $ DOCKER_BUILDKIT=1 docker build -f Dockerfile.github-release --output dist .
19 | ```
20 |
21 | **注意** COPY to host 需要:
22 | * Docker 19.03 以上版本
23 | * 需要 DOCKER_BUILDKIT 环境变量
24 | * 需要 --output 参数
--------------------------------------------------------------------------------
/docs/images/catfinder_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MegEngine/MegFlow/41cb9f85828aa080f6004674904fe430d8268052/docs/images/catfinder_image.png
--------------------------------------------------------------------------------
/docs/images/catfinder_video.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MegEngine/MegFlow/41cb9f85828aa080f6004674904fe430d8268052/docs/images/catfinder_video.png
--------------------------------------------------------------------------------
/docs/images/structure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MegEngine/MegFlow/41cb9f85828aa080f6004674904fe430d8268052/docs/images/structure.png
--------------------------------------------------------------------------------
/docs/images/visualize_deployment.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MegEngine/MegFlow/41cb9f85828aa080f6004674904fe430d8268052/docs/images/visualize_deployment.jpg
--------------------------------------------------------------------------------
/docs/images/visualize_result.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MegEngine/MegFlow/41cb9f85828aa080f6004674904fe430d8268052/docs/images/visualize_result.jpg
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | .. MegFlow documentation master file, created by
2 | sphinx-quickstart on Wed Mar 24 22:40:10 2021.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 | Welcome to MegFlow's documentation!
6 | ===================================
7 |
8 |
9 | *Please select a specific version of the document in the lower left corner of the page.*
10 |
11 | .. toctree::
12 | :maxdepth: 1
13 | :caption: how to build and run
14 | :name: sec-introduction
15 |
16 | 01-how-to-build/build-with-docker.zh
17 | 01-how-to-build/build-from-source.zh
18 | 01-how-to-build/build-on-aarch64.zh
19 | 01-how-to-build/build-on-win10.zh
20 | 01-how-to-build/appendix-A-build-options.zh
21 | 02-how-to-run/generate-rtsp.zh
22 | 02-how-to-run/run-in-15-minutes.zh
23 | download-models.zh
24 |
25 | .. toctree::
26 | :maxdepth: 1
27 | :caption: built-in applications
28 | :name: sec-introduction
29 |
30 | .. toctree::
31 | :maxdepth: 1
32 | :caption: how to use
33 | :name: sec-how-to-use
34 |
35 | 03-how-to-add-my-service/01-quickstart.zh
36 | 03-how-to-add-my-service/02-det-attr.zh
37 | 03-how-to-add-my-service/03-batching-and-pipeline-test.zh
38 | 03-how-to-add-my-service/04-web-visualization.zh
39 | 03-how-to-add-my-service/appendix-A-graph-definition.zh
40 | 03-how-to-add-my-service/appendix-B-python-plugin.zh
41 | 03-how-to-add-my-service/appendix-C-dump-model.zh
42 |
43 | .. toctree::
44 | :maxdepth: 1
45 | :caption: home
46 |
47 | FAQ.zh
48 | how-to-debug.zh
49 | how-to-contribute.zh
50 | how-to-pack-python-whl.zh
51 |
52 |
--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=.
11 | set BUILDDIR=_build
12 |
13 | if "%1" == "" goto help
14 |
15 | %SPHINXBUILD% >NUL 2>NUL
16 | if errorlevel 9009 (
17 | echo.
18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
19 | echo.installed, then set the SPHINXBUILD environment variable to point
20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
21 | echo.may add the Sphinx directory to PATH.
22 | echo.
23 | echo.If you don't have Sphinx installed, grab it from
24 | echo.http://sphinx-doc.org/
25 | exit /b 1
26 | )
27 |
28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29 | goto end
30 |
31 | :help
32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33 |
34 | :end
35 | popd
36 |
--------------------------------------------------------------------------------
/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | sphinx
2 | recommonmark
3 | sphinx_markdown_tables
4 | sphinx_rtd_theme
5 |
--------------------------------------------------------------------------------
/flow-debugger/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "flow-debugger"
3 | version = "0.3.5"
4 | edition = "2018"
5 | authors = ["megvii"]
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [dependencies]
10 | tokio = { version="1.10.0", features=["macros", "rt-multi-thread"] }
11 | warp = "0.3.1"
12 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "tabWidth": 4
3 | }
4 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "debugger-ui",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@codemirror/basic-setup": "^0.19.0",
7 | "@codemirror/legacy-modes": "^0.19.0",
8 | "@codemirror/state": "^0.19.1",
9 | "@codemirror/stream-parser": "^0.19.1",
10 | "@codemirror/theme-one-dark": "^0.19.0",
11 | "@codemirror/view": "^0.19.1",
12 | "@popperjs/core": "^2.9.3",
13 | "@reduxjs/toolkit": "^1.5.1",
14 | "@testing-library/jest-dom": "^4.2.4",
15 | "@testing-library/react": "^9.3.2",
16 | "@testing-library/user-event": "^7.1.2",
17 | "lodash": "^4.17.21",
18 | "react": "^17.0.2",
19 | "react-charts": "^3.0.0-beta.32",
20 | "react-dom": "^17.0.2",
21 | "react-popper": "^2.2.5",
22 | "react-redux": "^7.2.3",
23 | "react-scripts": "^2.0.0",
24 | "react-wait": "^0.3.0",
25 | "reactjs-popup": "^2.0.5",
26 | "rodemirror": "^1.6.3",
27 | "split-grid": "^1.0.11",
28 | "toml": "^3.0.0",
29 | "vis-data": "^7.1.2",
30 | "vis-network": "^9.0.5"
31 | },
32 | "scripts": {
33 | "start": "react-scripts start",
34 | "build": "react-scripts build",
35 | "test": "react-scripts test",
36 | "eject": "react-scripts eject",
37 | "fix": "npx prettier --write ./src"
38 | },
39 | "eslintConfig": {
40 | "extends": "react-app"
41 | },
42 | "browserslist": {
43 | "production": [
44 | ">0.2%",
45 | "not dead",
46 | "not op_mini all"
47 | ],
48 | "development": [
49 | "last 1 chrome version",
50 | "last 1 firefox version",
51 | "last 1 safari version"
52 | ]
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 | Debugger UI
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | display: flex;
3 | height: 100vh;
4 | flex-direction: column;
5 | padding-bottom: 1em;
6 | align-items: center;
7 | justify-content: center;
8 | }
9 |
10 | .Area {
11 | width: 100%;
12 | min-width: 0;
13 | height: 100%;
14 | min-height: 0;
15 | }
16 |
17 | .BorderArea {
18 | display: flex;
19 | flex-direction: column;
20 | width: 100%;
21 | min-width: 0;
22 | height: 100%;
23 | min-height: 0;
24 | border: 4px solid #dedede;
25 | border-radius: 4px;
26 | }
27 |
28 | .tabClose {
29 | border: 1px solid #dedede;
30 | border-right: none;
31 | background-color: #d4dfe6;
32 | cursor: pointer;
33 | line-height: 1.5em;
34 | }
35 |
36 | .body {
37 | flex-grow: 1;
38 | overflow-y: auto;
39 | }
40 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/AppHeader.module.css:
--------------------------------------------------------------------------------
1 | .AppHeader {
2 | display: flex;
3 | justify-content: flex-start;
4 | padding: 1.25em 0;
5 | font-size: 12px;
6 | width: 100%;
7 | }
8 |
9 | .AppHeader button:enabled {
10 | cursor: pointer;
11 | }
12 |
13 | .ButtonSet {
14 | margin-right: 0.5em;
15 | }
16 |
17 | AppHeaderSet:last-child {
18 | margin-right: 0;
19 | }
20 |
21 | .PopupContent {
22 | display: flex;
23 | flex-flow: column;
24 | justify-content: center;
25 | align-items: center;
26 | padding: 1.25em 0;
27 | font-size: 8px;
28 | width: auto;
29 | }
30 |
31 | .spinner {
32 | display: block;
33 | height: 1em;
34 | width: 1em;
35 | }
36 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/app/actor.js:
--------------------------------------------------------------------------------
1 | import { createAction } from "@reduxjs/toolkit";
2 |
3 | export const BrowserWidthChanged = "BROWSER_WIDTH_CHANGED";
4 | export const browserWidthChanged = createAction(
5 | BrowserWidthChanged,
6 | (isSmall) => {
7 | return {
8 | payload: {
9 | isSmall,
10 | },
11 | };
12 | }
13 | );
14 |
15 | export const StoreDebuggerPage = "STORE_DEBUGGER_PAGE";
16 | export const storeDebuggerPage = createAction(StoreDebuggerPage, () => {
17 | return {
18 | payload: {},
19 | };
20 | });
21 |
22 | export const RestoreDebuggerPage = "RESTORE_DEBUGGER_PAGE";
23 | export const restoreDebuggerPage = createAction(
24 | RestoreDebuggerPage,
25 | (focus) => {
26 | return {
27 | payload: {
28 | focus,
29 | },
30 | };
31 | }
32 | );
33 |
34 | export const ChangeMainPage = "CHANGE_MAIN_PAGE";
35 | export const changeMainPage = createAction(ChangeMainPage, (focus) => {
36 | return {
37 | payload: {
38 | focus,
39 | },
40 | };
41 | });
42 |
43 | export const ChangeStage = "CHANGE_STAGE";
44 | export const changeStage = createAction(ChangeStage, (stage) => {
45 | return {
46 | payload: {
47 | stage,
48 | },
49 | };
50 | });
51 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/app/index.js:
--------------------------------------------------------------------------------
1 | import { store } from "./store";
2 | import { browserWidthChanged } from "./actor";
3 |
4 | const z = (evt) => store.dispatch(browserWidthChanged(evt.matches));
5 | const maxWidthMediaQuery = window.matchMedia("(max-width: 1600px)");
6 | z(maxWidthMediaQuery);
7 | maxWidthMediaQuery.addListener(z);
8 |
9 | export * from "./actor";
10 | export * from "./store";
11 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/app/store.js:
--------------------------------------------------------------------------------
1 | import { configureStore } from "@reduxjs/toolkit";
2 | import * as actor from "./actor";
3 | import editor from "../page/editor/EditorSlice";
4 | import topology from "../page/topology/TopologySlice";
5 | import text from "../page/text/TextSlice";
6 | import chart from "../page/chart/ChartSlice";
7 | import { MainTabs, DebuggerTabs } from "../types";
8 |
9 | export const store = configureStore({
10 | reducer: {
11 | editor,
12 | topology,
13 | text,
14 | chart,
15 | isSmall: (state = false, action) => {
16 | switch (action.type) {
17 | case actor.BrowserWidthChanged:
18 | return action.payload.isSmall;
19 | default:
20 | return state;
21 | }
22 | },
23 | main: (state = { focus: 0, page: "" }, action) => {
24 | switch (action.type) {
25 | case actor.ChangeMainPage:
26 | return {
27 | focus: action.payload.focus,
28 | page: MainTabs[action.payload.focus],
29 | };
30 | default:
31 | return state;
32 | }
33 | },
34 | dbg: (state = { focus: -1, page: "" }, action) => {
35 | switch (action.type) {
36 | case actor.StoreDebuggerPage:
37 | return { focus: -1, page: state.page };
38 | case actor.RestoreDebuggerPage:
39 | return {
40 | focus: 0,
41 | page:
42 | action.payload.focus >= 0
43 | ? DebuggerTabs[action.payload.focus]
44 | : state.page,
45 | };
46 | default:
47 | return state;
48 | }
49 | },
50 | stage: (state = "", action) => {
51 | switch (action.type) {
52 | case actor.ChangeStage:
53 | return action.payload.stage;
54 | default:
55 | return state;
56 | }
57 | },
58 | },
59 | });
60 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/component/button/Button.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styles from "./Button.module.css";
3 |
4 | export const Button = ({ red, bold, icon, rightIcon, children, ...props }) => {
5 | const c = [styles.container];
6 |
7 | if (bold) {
8 | c.push(styles.bold);
9 | }
10 | if (icon) {
11 | c.push(styles.hasLeftIcon);
12 | }
13 | if (rightIcon) {
14 | c.push(styles.hasRightIcon);
15 | }
16 | if (red) {
17 | c.push(styles.red);
18 | }
19 |
20 | return (
21 |
30 | );
31 | };
32 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/component/input/Input.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styles from "./Input.module.css";
3 |
4 | export const Input = ({ label, ...props }) => {
5 | return (
6 |
7 |
8 |
14 |
15 | );
16 | };
17 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/component/input/Input.module.css:
--------------------------------------------------------------------------------
1 | .inner {
2 | display: table-cell;
3 | margin: 10px;
4 | font-weight: bold;
5 | }
6 |
7 | .container {
8 | margin: 5px;
9 | display: table-row;
10 | }
11 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/component/line_with_descp/LineWithDescp.js:
--------------------------------------------------------------------------------
1 | import React, { useMemo } from "react";
2 | import styles from "./LineWithDescp.module.css";
3 | import { Chart } from "react-charts";
4 |
5 | export const LineWithDescp = ({ data, children, ...props }) => {
6 | const primaryAxis = useMemo(
7 | () => ({
8 | getValue: (datum) => datum.primary,
9 | }),
10 | []
11 | );
12 |
13 | const secondaryAxes = useMemo(
14 | () => [
15 | {
16 | getValue: (datum) => datum.secondary,
17 | },
18 | ],
19 | []
20 | );
21 | let convert_data = [];
22 | for (const k in data) {
23 | convert_data.push({
24 | label: k,
25 | data: data[k].map((v, i)=>{
26 | return {
27 | primary: i,
28 | secondary: v,
29 | }
30 | }),
31 | })
32 | }
33 |
34 | return (
35 |
36 |
{children}
37 |
38 |
39 |
40 |
41 | );
42 | };
43 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/component/line_with_descp/LineWithDescp.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | width: 100%;
3 | height: 300px;
4 | display: flex;
5 | justify-content: center;
6 | align-items: center;
7 | flex-direction: column;
8 | }
9 |
10 | .descp {
11 | white-space: nowrap;
12 | text-decoration: none;
13 | padding: 0 1.25em;
14 | height: 3em;
15 | font-weight: 700;
16 | color: #444;
17 | display: flex;
18 | width: 50%;
19 | }
20 |
21 | .line {
22 | flex-grow: 1;
23 | width: 50%;
24 | }
25 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/component/resizable_area/ResizableArea.module.css:
--------------------------------------------------------------------------------
1 | .resizeable {
2 | width: 100%;
3 | min-width: 0;
4 | height: 100%;
5 | min-height: 0;
6 | }
7 |
8 | .container {
9 | display: flex;
10 | height: 100vh;
11 | flex-direction: column;
12 | padding-bottom: 1em;
13 | }
14 |
15 | .resizeableAreaRow {
16 | composes: resizeable;
17 | display: grid;
18 | grid-template-rows: 1fr 12px 1fr;
19 | }
20 |
21 | .resizeableAreaColumn {
22 | composes: resizeable;
23 | display: grid;
24 | grid-template-columns: 1fr 12px 1fr;
25 | }
26 |
27 | .resizeableHiddenAreaRow {
28 | composes: resizeable;
29 | display: grid;
30 | grid-template-rows: 1fr auto;
31 | }
32 |
33 | .resizeableHiddenAreaColumn {
34 | composes: resizeable;
35 | display: grid;
36 | grid-template-columns: 1fr auto;
37 | }
38 |
39 | .splitRowsGutter {
40 | display: flex;
41 | align-items: center;
42 | justify-content: center;
43 | cursor: row-resize;
44 | color: #fff;
45 | }
46 |
47 | .splitRowsGutterHandle {
48 | pointer-events: none;
49 | transform: rotate(90deg);
50 | }
51 |
52 | .splitColumnsGutter {
53 | display: flex;
54 | align-items: center;
55 | justify-content: center;
56 | cursor: col-resize;
57 | color: #fff;
58 | }
59 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/component/tab/Tab.js:
--------------------------------------------------------------------------------
1 | import styles from "./Tab.module.css";
2 | import React from "react";
3 |
4 | const Tab = ({ focus, label, onClick, ...props }) => {
5 | return (
6 |
13 | );
14 | };
15 |
16 | export const TabList = ({ focus, tabs, children = null }) => {
17 | let tabsLabel = tabs.map((tab, i) => (
18 |
19 | ));
20 | return (
21 |
22 | {tabsLabel}
23 | {children}
24 |
25 | );
26 | };
27 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/component/tab/Tab.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | display: flex;
3 | width: 100%;
4 | height: 100%;
5 | flex-direction: column;
6 | }
7 |
8 | .tabs {
9 | display: flex;
10 | }
11 |
12 | .tab {
13 | flex: 1 1 auto;
14 | border: 1px solid #dedede;
15 | border-right: none;
16 | background-color: #dedede;
17 | cursor: pointer;
18 | line-height: 1.5em;
19 | }
20 |
21 | .tab:last-of-type {
22 | border-right: 1px solid #dedede;
23 | }
24 |
25 | .tabSelected {
26 | composes: tab;
27 | border-bottom: none;
28 | background-color: #f9ffff;
29 | cursor: default;
30 | }
31 |
32 | .tabSelected:focus {
33 | outline: none;
34 | background-color: #fff;
35 | }
36 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/event_listener.js:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import { pin, unpin } from "./page/editor/EditorSlice";
3 | import { update } from "./page/topology/TopologySlice";
4 | import { update as update_err } from "./page/text/TextSlice";
5 | import { changeMainPage, restoreDebuggerPage, changeStage } from "./app/actor";
6 | import { ERROR, TOPOLOGY, EDITOR } from "./types";
7 | import { parse } from "./parser";
8 | import toml from "toml";
9 |
10 | export default (dispatch, notify) => {
11 | const [parsed, setParsed] = useState({});
12 | return [parsed, {
13 | _onerror: (e) => {
14 | dispatch(update_err(`WEBSOCKET ERROR: ${e}`));
15 | dispatch(restoreDebuggerPage(ERROR));
16 | notify('connect')
17 | notify('disconnect')
18 | },
19 | _onclose: (e) => {
20 | dispatch(changeStage(""));
21 | dispatch(unpin());
22 | dispatch(changeMainPage(EDITOR));
23 | notify('connect')
24 | notify('disconnect')
25 | },
26 | initialized: (msg) => {
27 | try {
28 | dispatch(pin(msg.graph));
29 | const [for_viz, tmp] = parse(toml.parse(msg.graph));
30 | setParsed(tmp);
31 | dispatch(update(for_viz));
32 | dispatch(changeMainPage(TOPOLOGY));
33 | } catch (e) {
34 | if (e.line) {
35 | dispatch(
36 | update_err(
37 | `ERROR: ${e.message} at lint ${e.line}, column ${e.column}`
38 | )
39 | );
40 | } else {
41 | dispatch(update_err(`ERROR: ${e.message}`));
42 | }
43 | dispatch(restoreDebuggerPage(ERROR));
44 | }
45 | notify('connect')
46 | },
47 | terminated: (msg) => {
48 | notify('disconnect')
49 | },
50 | }];
51 | };
52 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/index.css:
--------------------------------------------------------------------------------
1 | textarea {
2 | font-family: "Open Sans", sans-serif;
3 | }
4 |
5 | html {
6 | box-sizing: border-box;
7 | }
8 |
9 | *,
10 | *:before,
11 | *:after {
12 | box-sizing: inherit;
13 | }
14 |
15 | body {
16 | overflow-y: hidden;
17 | background-color: #282c37;
18 | padding: 0 1em;
19 | font-family: "Open Sans", sans-serif;
20 | -webkit-font-smoothing: antialiased;
21 | -moz-osx-font-smoothing: grayscale;
22 | }
23 |
24 | code {
25 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
26 | monospace;
27 | font-size: 0.9em;
28 | }
29 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 | import "./index.css";
4 | import { store } from "./app";
5 | import App from "./App";
6 | import { Provider } from "react-redux";
7 | import * as serviceWorker from "./serviceWorker";
8 | import { Waiter } from "react-wait";
9 |
10 | ReactDOM.render(
11 |
12 |
13 |
14 |
15 |
16 |
17 | ,
18 | document.getElementById("root")
19 | );
20 |
21 | serviceWorker.register();
22 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/page/chart/Chart.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styles from "./Chart.module.css";
3 | import { useSelector } from "react-redux";
4 | import { LineWithDescp } from "../../component/line_with_descp/LineWithDescp";
5 | import { selectChartLines, selectChartFocus } from "./ChartSlice";
6 |
7 | export const Chart = () => {
8 | const ids = useSelector(selectChartFocus);
9 | const lines = useSelector(selectChartLines(ids));
10 | const labels = Object.values(lines).map((line, i)=> {
11 | return ( {line.descp} )
12 | });
13 | return (
14 |
15 |
16 | { labels }
17 |
18 |
19 | );
20 | };
21 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/page/chart/Chart.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | height: 100%;
3 | width: 100%;
4 | background-color: #f9ffff;
5 | }
6 |
7 | .list {
8 | border: 1px solid #dedede;
9 | border-top: none;
10 | border-bottom: none;
11 | padding: 0.5em;
12 | background-color: #f9ffff;
13 | display: flex;
14 | height: auto;
15 | width: 100%;
16 | justify-content: flex-start;
17 | flex-direction: column;
18 | }
19 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/page/chart/ChartSlice.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from "@reduxjs/toolkit";
2 |
3 | export const chartSlice = createSlice({
4 | name: "chart",
5 | initialState: {
6 | lines: {},
7 | focus: [],
8 | },
9 | reducers: {
10 | append: (state, elem) => {
11 | if (!(elem.payload.id in state.lines)) {
12 | state.lines[elem.payload.id] = { descp: elem.payload.descp, start: Date.now(), data: {} };
13 | }
14 | let dst = state.lines[elem.payload.id].data;
15 | let start = state.lines[elem.payload.id].start;
16 | let src = elem.payload.data;
17 |
18 | let now = Date.now();
19 | let dur = now - start;
20 |
21 | for (const k in src) {
22 | if (!(k in dst)) {
23 | dst[k] = [];
24 | }
25 | const len = dst[k].length;
26 | if (dur > 1000 || len === 0) {
27 | dst[k].push(src[k]);
28 | } else {
29 | dst[k][len-1] = Math.max(dst[k][len-1], src[k]);
30 | }
31 | if (len >= 60) { // TODO: remove the hardcode
32 | dst[k].shift();
33 | }
34 | }
35 | if (dur > 1000) { // TODO: remove the hardcode
36 | state.lines[elem.payload.id].start = Date.now();
37 | }
38 | },
39 | reset: (state) => {
40 | state.lines = {};
41 | state.focus = [];
42 | },
43 | focus: (state, ids) => {
44 | state.focus = ids.payload;
45 | }
46 | },
47 | });
48 |
49 | export const { append, reset, focus } = chartSlice.actions;
50 |
51 | export const selectChartLines = (ids) => (state) => {
52 | let lines = {};
53 | for (const id of ids) {
54 | if (id in state.chart.lines) {
55 | lines[id] = state.chart.lines[id];
56 | }
57 | }
58 | return lines;
59 | };
60 |
61 | export const selectChartFocus = (state) => state.chart.focus;
62 |
63 | export default chartSlice.reducer;
64 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/page/editor/Editor.js:
--------------------------------------------------------------------------------
1 | import React, { useMemo } from "react";
2 | import { useDispatch, useSelector } from "react-redux";
3 | import CodeMirror from "rodemirror";
4 | import { basicSetup } from "@codemirror/basic-setup";
5 | import { oneDark } from "@codemirror/theme-one-dark";
6 | import { StreamLanguage } from "@codemirror/stream-parser";
7 | import { toml } from "@codemirror/legacy-modes/mode/toml";
8 | import { update, selectEditorInit, selectEdit } from "./EditorSlice";
9 |
10 | export const Editor = () => {
11 | const dispatch = useDispatch();
12 | const init = useSelector(selectEditorInit);
13 | const edit = useSelector(selectEdit);
14 | const extensions = useMemo(
15 | () => [basicSetup, oneDark, StreamLanguage.define(toml)],
16 | []
17 | );
18 | return (
19 | {
23 | if (v.docChanged && edit) {
24 | dispatch(update(v.state.doc.toString()));
25 | }
26 | }}
27 | />
28 | );
29 | };
30 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/page/editor/EditorSlice.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from "@reduxjs/toolkit";
2 |
3 | export const editorSlice = createSlice({
4 | name: "editor",
5 | initialState: {
6 | init: "",
7 | changed: "",
8 | edit: true,
9 | },
10 | reducers: {
11 | save: (state) => {
12 | state.init = state.changed;
13 | },
14 | update: (state, changed) => {
15 | state.changed = changed.payload;
16 | },
17 | pin: (state, overwrite) => {
18 | state.init = overwrite.payload;
19 | state.changed = overwrite.payload;
20 | state.edit = false;
21 | },
22 | unpin: (state) => {
23 | state.edit = true;
24 | },
25 | },
26 | });
27 |
28 | export const { save, update, pin, unpin } = editorSlice.actions;
29 |
30 | export const selectEditorInit = (state) => state.editor.init;
31 | export const selectEditorChanged = (state) => state.editor.changed;
32 | export const selectEdit = (state) => state.editor.edit;
33 |
34 | export default editorSlice.reducer;
35 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/page/empty/Empty.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styles from "./Empty.module.css";
3 |
4 | export const Empty = (props) => {
5 | return {props.children}
;
6 | };
7 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/page/empty/Empty.module.css:
--------------------------------------------------------------------------------
1 | .empty {
2 | height: 100%;
3 | width: 100%;
4 | padding: 0.5em;
5 | border: 1px solid #dedede;
6 | border-top: none;
7 | background-color: #f9ffff;
8 | }
9 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/page/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useSelector } from "react-redux";
3 | import { Empty } from "./empty/Empty";
4 | import { Text } from "./text/Text";
5 | import { Topology } from "./topology/Topology";
6 | import { Editor } from "./editor/Editor";
7 | import { Chart } from "./chart/Chart";
8 |
9 | export const MainSwitcher = () => {
10 | const page = useSelector((state) => state.main.page);
11 | switch (page) {
12 | case "topology":
13 | return ;
14 | case "editor":
15 | return ;
16 | default:
17 | return ;
18 | }
19 | };
20 |
21 | export const DebuggerSwitcher = () => {
22 | const page = useSelector((state) => state.dbg.page);
23 |
24 | switch (page) {
25 | case "error":
26 | return ;
27 | case "chart":
28 | return ;
29 | default:
30 | return ;
31 | }
32 | };
33 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/page/text/Text.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styles from "./Text.module.css";
3 | import { useSelector } from "react-redux";
4 | import { selectTextMessage } from "./TextSlice";
5 |
6 | export const Text = () => {
7 | const message = useSelector(selectTextMessage);
8 | return (
9 |
10 |
{message}
11 |
12 | );
13 | };
14 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/page/text/Text.module.css:
--------------------------------------------------------------------------------
1 | .text {
2 | height: 100%;
3 | width: 100%;
4 | padding: 0.5em;
5 | border: 1px solid #dedede;
6 | border-top: none;
7 | background-color: #f9ffff;
8 | }
9 |
10 | .text h1 {
11 | margin: 1em;
12 | color: rgb(214, 122, 127);
13 | }
14 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/page/text/TextSlice.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from "@reduxjs/toolkit";
2 |
3 | export const textSlice = createSlice({
4 | name: "text",
5 | initialState: {
6 | message: "",
7 | },
8 | reducers: {
9 | update: (state, changed) => {
10 | state.message = changed.payload;
11 | },
12 | },
13 | });
14 |
15 | export const { update } = textSlice.actions;
16 |
17 | export const selectTextMessage = (state) => state.text.message;
18 |
19 | export default textSlice.reducer;
20 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/page/topology/Topology.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useSelector, useDispatch } from "react-redux";
3 | import { selectDescp, selectListen } from "./TopologySlice";
4 | import Graph from "./VisGraph";
5 | import { restoreDebuggerPage, storeDebuggerPage } from "../../app/actor";
6 | import { CHART } from "../../types";
7 | import { focus } from "../chart/ChartSlice";
8 |
9 | const options = {
10 | autoResize: true,
11 | width: "100%",
12 | height: "100%",
13 | layout: {
14 | randomSeed: 0,
15 | hierarchical: false,
16 | },
17 | edges: {
18 | color: "#ffffff",
19 | },
20 | physics: {
21 | enabled: false,
22 | },
23 | };
24 |
25 | export const Topology = () => {
26 | let dispatch = useDispatch();
27 | let descp = useSelector(selectDescp);
28 | let listen = useSelector(selectListen);
29 | let edges = descp.edges.map((edge) => {
30 | return { ...edge };
31 | }); // workaround for graph-viz
32 | let events = listen ? {
33 | click: (e) => {
34 | if (e.nodes.length === 1) {
35 | let id = e.nodes[0];
36 | let ports = descp.nodes.find(node=>node.id === id).ports;
37 | let ids = ports.map(port=>`${id}#${port}`);
38 | dispatch(focus(ids));
39 | dispatch(restoreDebuggerPage(CHART));
40 | }
41 | },
42 | deselectNode: (e) => {
43 | if (e.nodes.length === 0) {
44 | dispatch(storeDebuggerPage())
45 | }
46 | },
47 | } : {};
48 | return (
49 |
55 | );
56 | };
57 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/page/topology/TopologySlice.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from "@reduxjs/toolkit";
2 |
3 | export const topologySlice = createSlice({
4 | name: "topology",
5 | initialState: {
6 | descp: {
7 | nodes: [],
8 | edges: [],
9 | },
10 | listen: false,
11 | },
12 | reducers: {
13 | update: (state, descp) => {
14 | state.descp = {
15 | nodes: descp.payload.nodes || [],
16 | edges: descp.payload.edges || [],
17 | };
18 | },
19 | setBlock: (state, ids) => {
20 | for (let node of state.descp.nodes) {
21 | if (ids.payload.includes(node.id)) {
22 | node.color = '#ff0000';
23 | node.font = { color: "#fff" };
24 | } else if (node.title) {
25 | node.color = '#fff';
26 | node.font = { color: "#000" };
27 | }
28 | }
29 | },
30 | listen: (state, listen) => {
31 | state.listen = listen.payload;
32 | }
33 | },
34 | });
35 |
36 | export const { update, setBlock, listen } = topologySlice.actions;
37 |
38 | export const selectDescp = (state) => state.topology.descp;
39 | export const selectListen = (state) => state.topology.listen;
40 |
41 | export default topologySlice.reducer;
42 |
--------------------------------------------------------------------------------
/flow-debugger/debugger-ui/src/types.js:
--------------------------------------------------------------------------------
1 | export const Orientation = {
2 | Horizontal: "horizontal",
3 | Vertical: "vertical",
4 | };
5 |
6 | export const MainTabs = ["editor", "topology"];
7 | export const EDITOR = 0;
8 | export const TOPOLOGY = 1;
9 |
10 | export const DebuggerTabs = ["empty", "error", "chart"];
11 | export const EMPTY = 0;
12 | export const ERROR = 1;
13 | export const CHART = 2;
14 |
--------------------------------------------------------------------------------
/flow-debugger/src/main.rs:
--------------------------------------------------------------------------------
1 | #[tokio::main]
2 | async fn main() {
3 | warp::serve(warp::fs::dir("debugger-ui/build"))
4 | .run(([0, 0, 0, 0], 3000))
5 | .await;
6 | }
7 |
--------------------------------------------------------------------------------
/flow-derive/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "flow-derive"
3 | version = "0.3.5"
4 | authors = ["megvii"]
5 | edition = "2018"
6 |
7 | [lib]
8 | proc-macro = true
9 |
10 | [dependencies]
11 | quote = "1"
12 | syn = "1"
13 | proc-macro2 = {version ="1", features= ["span-locations"]}
14 | anyhow = "1.0.38"
15 |
16 | [dev-dependencies]
17 | flow-rs = { path = "../flow-rs" }
18 | toml = "0.5.8"
19 |
--------------------------------------------------------------------------------
/flow-derive/README.md:
--------------------------------------------------------------------------------
1 | # flow-derive
2 |
3 | ### Q & A
4 | 1. Proc macro attributes are not yet supported in rust analyzer, and here is a workaround way.
5 | ```json
6 | "rust-analyzer.diagnostics.disabled": [
7 | "no-such-field"
8 | ]
9 | ```
10 |
--------------------------------------------------------------------------------
/flow-derive/examples/node_derive.rs:
--------------------------------------------------------------------------------
1 | /**
2 | * \file flow-derive/examples/node_derive.rs
3 | * MegFlow is Licensed under the Apache License, Version 2.0 (the "License")
4 | *
5 | * Copyright (c) 2019-2021 Megvii Inc. All rights reserved.
6 | *
7 | * Unless required by applicable law or agreed to in writing,
8 | * software distributed under the License is distributed on an
9 | * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | */
11 | use anyhow::Result;
12 | use flow_rs::prelude::*;
13 |
14 | #[allow(dead_code)]
15 | #[inputs(first, second:dyn, third:[], fourth:{})]
16 | #[outputs(front, last:dyn)]
17 | #[derive(Node, Actor, Default)]
18 | struct SubNode {}
19 |
20 | impl SubNode {
21 | fn new(_: String, _args: &toml::value::Table) -> Self {
22 | SubNode {
23 | ..Default::default()
24 | }
25 | }
26 |
27 | async fn initialize(&mut self, _: ResourceCollection) {}
28 | async fn finalize(&mut self) {}
29 |
30 | async fn exec(&mut self, _: &Context) -> Result<()> {
31 | let _: Envelope = self.first.recv::().await.unwrap();
32 | Ok(())
33 | }
34 | }
35 |
36 | node_register!("sub", SubNode);
37 |
38 | fn main() {}
39 |
--------------------------------------------------------------------------------
/flow-derive/src/lit.rs:
--------------------------------------------------------------------------------
1 | /**
2 | * \file flow-derive/src/lit.rs
3 | * MegFlow is Licensed under the Apache License, Version 2.0 (the "License")
4 | *
5 | * Copyright (c) 2019-2021 Megvii Inc. All rights reserved.
6 | *
7 | * Unless required by applicable law or agreed to in writing,
8 | * software distributed under the License is distributed on an
9 | * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | */
11 | use proc_macro2::Span;
12 | use std::fmt::Display;
13 |
14 | use syn::{Ident, LitStr};
15 |
16 | pub fn string(lit: T) -> LitStr {
17 | LitStr::new(lit.to_string().as_str(), Span::call_site())
18 | }
19 |
20 | pub fn ident(lit: impl AsRef) -> Ident {
21 | Ident::new(lit.as_ref(), Span::call_site())
22 | }
23 |
--------------------------------------------------------------------------------
/flow-derive/src/resource.rs:
--------------------------------------------------------------------------------
1 | use proc_macro2::TokenStream;
2 | use quote::quote;
3 | use syn::parse::{Parse, ParseStream, Result};
4 | use syn::Token;
5 |
6 | pub struct ResourceDefine {
7 | name: syn::Expr,
8 | ty: syn::Type,
9 | }
10 | impl Parse for ResourceDefine {
11 | fn parse(input: ParseStream) -> Result {
12 | let name: syn::Expr = input.parse()?;
13 | input.parse::()?;
14 | let ty: syn::Type = input.parse()?;
15 | Ok(ResourceDefine { name, ty })
16 | }
17 | }
18 |
19 | pub fn registry_expand(input: ResourceDefine) -> TokenStream {
20 | let name = &input.name;
21 | let ty = &input.ty;
22 | quote! {
23 | flow_rs::submit!(#name.to_owned(),
24 | flow_rs::node::ResourceSlice{
25 | cons: Box::new(|name: String, args: &toml::value::Table| Box::new(<#ty>::new(name, args))),
26 | }
27 | );
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/flow-derive/src/type_name.rs:
--------------------------------------------------------------------------------
1 | /**
2 | * \file flow-derive/src/type_name.rs
3 | * MegFlow is Licensed under the Apache License, Version 2.0 (the "License")
4 | *
5 | * Copyright (c) 2019-2021 Megvii Inc. All rights reserved.
6 | *
7 | * Unless required by applicable law or agreed to in writing,
8 | * software distributed under the License is distributed on an
9 | * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | */
11 |
12 | pub const IN_T: &str = "Receiver";
13 | pub const OUT_T: &str = "Sender";
14 |
--------------------------------------------------------------------------------
/flow-message/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "flow-message"
3 | version = "0.3.5"
4 | edition = "2018"
5 |
6 | [features]
7 | cross = ["byteorder", "dashmap", "enum-as-inner", "im", "paste", "pyo3"]
8 | c = ["libc"]
9 |
10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
11 |
12 | [dependencies]
13 | byteorder = {version="1.4", optional=true}
14 | dashmap = {version="4.0", optional=true}
15 | enum-as-inner = {version="0.3", optional=true}
16 | im = {version="15.0", optional=true}
17 | paste = {version="1.0",optional=true}
18 | pyo3 = {version="0.15", features=["abi3"], optional=true}
19 | libc = {version="0.2",optional=true}
20 |
--------------------------------------------------------------------------------
/flow-message/src/c.rs:
--------------------------------------------------------------------------------
1 | /**
2 | * \file flow-message/c.rs
3 | * MegFlow is Licensed under the Apache License, Version 2.0 (the "License")
4 | *
5 | * Copyright (c) 2019-2021 Megvii Inc. All rights reserved.
6 | *
7 | * Unless required by applicable law or agreed to in writing,
8 | * software distributed under the License is distributed on an
9 | * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | */
11 |
12 | #[repr(C)]
13 | pub struct CMessage {
14 | pub ptr: *mut libc::c_void,
15 | pub clone_func: extern "C" fn(*mut libc::c_void) -> *mut libc::c_void,
16 | pub release_func: extern "C" fn(*mut libc::c_void),
17 | }
18 |
19 | pub struct Message(Option);
20 |
21 | unsafe impl Send for Message {}
22 | unsafe impl Sync for Message {}
23 |
24 | impl Message {
25 | pub fn as_ptr(&self) -> *const T {
26 | self.0.as_ref().unwrap().ptr as *const _
27 | }
28 |
29 | pub fn as_mut_ptr(&mut self) -> *mut T {
30 | self.0.as_mut().unwrap().ptr as *mut T
31 | }
32 | }
33 |
34 | impl Drop for Message {
35 | fn drop(&mut self) {
36 | if let Some(inner) = self.0.as_ref() {
37 | (inner.release_func)(inner.ptr)
38 | }
39 | }
40 | }
41 |
42 | impl Clone for Message {
43 | fn clone(&self) -> Self {
44 | let inner = self.0.as_ref().unwrap();
45 | Message(Some(CMessage {
46 | ptr: (inner.clone_func)(inner.ptr),
47 | clone_func: inner.clone_func,
48 | release_func: inner.release_func,
49 | }))
50 | }
51 | }
52 |
53 | impl From for Message {
54 | fn from(msg: CMessage) -> Self {
55 | Message(Some(msg))
56 | }
57 | }
58 |
59 | impl From for CMessage {
60 | fn from(mut msg: Message) -> Self {
61 | msg.0.take().unwrap()
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/flow-message/src/cross/cow_list.rs:
--------------------------------------------------------------------------------
1 | use super::*;
2 |
3 | impl private::IndexGetDataRefForGetRef for CowList {
4 | fn get_ref(&self, key: &usize) -> Option<&data::Data> {
5 | self.get(*key)
6 | }
7 | }
8 |
9 | impl private::IndexGetDataRefForGet for CowList {
10 | fn get_ref(&self, key: &usize) -> Option<&data::Data> {
11 | self.get(*key)
12 | }
13 | }
14 |
15 | impl private::IndexSetData for CowList {
16 | fn set(&mut self, key: usize, data: data::Data) {
17 | self.set(key, data);
18 | }
19 | }
20 |
21 | impl private::IndexGetDataMut for CowList {
22 | fn get_mut(&mut self, key: &usize) -> Option<&mut data::Data> {
23 | self.get_mut(*key)
24 | }
25 | }
26 |
27 | impl VectorOpr for CowList
28 | where
29 | T: From,
30 | data::Data: From,
31 | {
32 | fn xpop_front(&mut self) -> Option {
33 | self.pop_front().map(T::from)
34 | }
35 |
36 | fn xpop_back(&mut self) -> Option {
37 | self.pop_back().map(T::from)
38 | }
39 |
40 | fn xpush_back(&mut self, value: T) {
41 | self.push_back(data::Data::from(value))
42 | }
43 |
44 | fn xpush_front(&mut self, value: T) {
45 | self.push_front(data::Data::from(value))
46 | }
47 | }
48 |
49 | #[cfg(test)]
50 | mod test {
51 | use super::*;
52 |
53 | #[test]
54 | fn test_basis() {
55 | let mut list = CowList::new();
56 | list.xpush_back(1f64);
57 | list.xpush_back(1i64);
58 | list.xpush_back(false);
59 | assert_eq!(list.len(), 3);
60 | assert_eq!(list.xget(&1), Some(1i64));
61 | assert_eq!(list.xpop_back(), Some(false));
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/flow-message/src/cross/cow_map.rs:
--------------------------------------------------------------------------------
1 | /**
2 | * \file flow-message/cross/cow_map.rs
3 | * MegFlow is Licensed under the Apache License, Version 2.0 (the "License")
4 | *
5 | * Copyright (c) 2019-2021 Megvii Inc. All rights reserved.
6 | *
7 | * Unless required by applicable law or agreed to in writing,
8 | * software distributed under the License is distributed on an
9 | * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | */
11 | use super::*;
12 |
13 | impl private::IndexSetData for CowMap {
14 | fn set(&mut self, key: String, data: data::Data) {
15 | self.insert(key, data);
16 | }
17 | }
18 |
19 | impl private::IndexGetDataRefForGet for CowMap {
20 | fn get_ref(&self, key: &str) -> Option<&data::Data> {
21 | self.get(key)
22 | }
23 | }
24 |
25 | impl private::IndexGetDataRefForGetRef for CowMap {
26 | fn get_ref(&self, key: &str) -> Option<&data::Data> {
27 | self.get(key)
28 | }
29 | }
30 |
31 | impl private::IndexGetDataMut for CowMap {
32 | fn get_mut(&mut self, key: &str) -> Option<&mut data::Data> {
33 | self.get_mut(key)
34 | }
35 | }
36 |
37 | #[cfg(test)]
38 | mod test {
39 | use super::*;
40 |
41 | #[test]
42 | fn test_basis() {
43 | let mut map = CowMap::new();
44 | map.xset("a".to_owned(), 1i64);
45 | map.xset("b".to_owned(), 1f64);
46 | let mut sub = CowMap::new();
47 | sub.xset("d".to_owned(), false);
48 | map.xset("c".to_owned(), sub);
49 |
50 | assert_eq!(map.xget("b"), Some(1f64));
51 | let has_c: Option<&mut CowMap> = map.xget_mut("c");
52 | assert!(has_c.is_some());
53 | let sub = has_c.unwrap();
54 | assert_eq!(sub.xget("d"), Some(false));
55 | sub.xset("e".to_owned(), true);
56 |
57 | let has_c: Option<&CowMap> = map.xget_ref("c");
58 | assert!(has_c.is_some());
59 | let sub = has_c.unwrap();
60 | assert_eq!(sub.xget("e"), Some(true));
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/flow-message/src/cross/list.rs:
--------------------------------------------------------------------------------
1 | /**
2 | * \file flow-message/cross/list.rs
3 | * MegFlow is Licensed under the Apache License, Version 2.0 (the "License")
4 | *
5 | * Copyright (c) 2019-2021 Megvii Inc. All rights reserved.
6 | *
7 | * Unless required by applicable law or agreed to in writing,
8 | * software distributed under the License is distributed on an
9 | * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | */
11 | use super::*;
12 |
13 | impl